xref: /petsc/src/ksp/pc/impls/gasm/gasm.c (revision fdc4864643572ece7a592487c1b8b7350d449f62)
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 */
11b45d2f2cSJed Brown #include <petsc-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     }
676bf464f9SBarry Smith     ierr = PetscViewerDestroy(&sviewer);CHKERRQ(ierr);
68af538404SDmitry Karpeev     ierr = ISRestoreIndices(osm->is[i],&idx);CHKERRQ(ierr);
69eec7e3faSDmitry Karpeev 
707b23a99aSBarry Smith     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
71af538404SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer, "Subdomain with overlap\n");CHKERRQ(ierr);
72af538404SDmitry Karpeev     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%s", cidx);CHKERRQ(ierr);
73af538404SDmitry Karpeev     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
747b23a99aSBarry Smith     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
75af538404SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
76af538404SDmitry Karpeev     ierr = PetscFree(cidx);CHKERRQ(ierr);
776bf464f9SBarry Smith     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
78af538404SDmitry Karpeev     if (osm->is_local) {
79af538404SDmitry Karpeev       ierr = PetscViewerASCIIOpen(((PetscObject)((osm->is)[i]))->comm,fname,&viewer);CHKERRQ(ierr);
80af538404SDmitry Karpeev       ierr = ISGetLocalSize(osm->is_local[i], &nidx);CHKERRQ(ierr);
81eec7e3faSDmitry Karpeev       /*
82eec7e3faSDmitry Karpeev        No more than 15 characters per index plus a space.
83eec7e3faSDmitry Karpeev        PetscViewerStringSPrintf requires a string of size at least 2, so use (nidx+1) instead of nidx,
84eec7e3faSDmitry Karpeev        in case nidx == 0. That will take care of the space for the trailing '\0' as well.
85eec7e3faSDmitry Karpeev        For nidx == 0, the whole string 16 '\0'.
86eec7e3faSDmitry Karpeev        */
87eec7e3faSDmitry Karpeev       ierr = PetscMalloc(sizeof(char)*(16*(nidx+1)+1), &cidx);CHKERRQ(ierr);
88af538404SDmitry Karpeev       ierr = ISGetIndices(osm->is_local[i], &idx);CHKERRQ(ierr);
89eec7e3faSDmitry Karpeev       ierr = PetscViewerStringOpen(((PetscObject)(osm->is_local[i]))->comm, cidx, 16*(nidx+1), &sviewer);CHKERRQ(ierr);
90af538404SDmitry Karpeev       for(j = 0; j < nidx; ++j) {
91af538404SDmitry Karpeev         ierr = PetscViewerStringSPrintf(sviewer, "%D ", idx[j]);CHKERRQ(ierr);
92af538404SDmitry Karpeev       }
936bf464f9SBarry Smith       ierr = PetscViewerDestroy(&sviewer);CHKERRQ(ierr);
94af538404SDmitry Karpeev       ierr = ISRestoreIndices(osm->is_local[i],&idx);CHKERRQ(ierr);
95eec7e3faSDmitry Karpeev 
967b23a99aSBarry Smith       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
97af538404SDmitry Karpeev       ierr = PetscViewerASCIIPrintf(viewer, "Subdomain without overlap\n");CHKERRQ(ierr);
98af538404SDmitry Karpeev       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%s", cidx);CHKERRQ(ierr);
99af538404SDmitry Karpeev       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1007b23a99aSBarry Smith       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
101af538404SDmitry Karpeev       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
102af538404SDmitry Karpeev       ierr = PetscFree(cidx);CHKERRQ(ierr);
1036bf464f9SBarry Smith       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
104af538404SDmitry Karpeev     }
105af538404SDmitry Karpeev   }
106af538404SDmitry Karpeev   PetscFunctionReturn(0);
107af538404SDmitry Karpeev }
108af538404SDmitry Karpeev 
109af538404SDmitry Karpeev 
110af538404SDmitry Karpeev #undef __FUNCT__
111f746d493SDmitry Karpeev #define __FUNCT__ "PCView_GASM"
112f746d493SDmitry Karpeev static PetscErrorCode PCView_GASM(PC pc,PetscViewer viewer)
113b1a0a8a3SJed Brown {
114f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
115af538404SDmitry Karpeev   const char     *prefix;
116b1a0a8a3SJed Brown   PetscErrorCode ierr;
117af538404SDmitry Karpeev   PetscMPIInt    rank, size;
118b1a0a8a3SJed Brown   PetscInt       i,bsz;
119e4b3f054SSatish Balay   PetscBool      iascii,isstring, print_subdomains=PETSC_FALSE;
120b1a0a8a3SJed Brown   PetscViewer    sviewer;
121b1a0a8a3SJed Brown 
122b1a0a8a3SJed Brown 
123b1a0a8a3SJed Brown   PetscFunctionBegin;
124af538404SDmitry Karpeev   ierr = MPI_Comm_size(((PetscObject)pc)->comm, &size);CHKERRQ(ierr);
125af538404SDmitry Karpeev   ierr = MPI_Comm_rank(((PetscObject)pc)->comm, &rank);CHKERRQ(ierr);
126b1a0a8a3SJed Brown   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
127b1a0a8a3SJed Brown   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr);
128af538404SDmitry Karpeev   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
129af538404SDmitry Karpeev   ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&print_subdomains,PETSC_NULL);CHKERRQ(ierr);
130b1a0a8a3SJed Brown   if (iascii) {
131af538404SDmitry Karpeev     char overlaps[256] = "user-defined overlap",subdomains[256] = "total subdomains set";
132b1a0a8a3SJed Brown     if (osm->overlap >= 0) {ierr = PetscSNPrintf(overlaps,sizeof overlaps,"amount of overlap = %D",osm->overlap);CHKERRQ(ierr);}
133af538404SDmitry Karpeev     if (osm->nmax > 0)     {ierr = PetscSNPrintf(subdomains,sizeof subdomains,"max number of local subdomains = %D",osm->nmax);CHKERRQ(ierr);}
1347b23a99aSBarry Smith     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
135eec7e3faSDmitry Karpeev     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"  [%d:%d] number of locally-supported subdomains = %D\n",(int)rank,(int)size,osm->n);CHKERRQ(ierr);
136af538404SDmitry Karpeev     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1377b23a99aSBarry Smith     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
138af538404SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer,"  Generalized additive Schwarz: %s, %s\n",subdomains,overlaps);CHKERRQ(ierr);
139f746d493SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer,"  Generalized additive Schwarz: restriction/interpolation type - %s\n",PCGASMTypes[osm->type]);CHKERRQ(ierr);
140b1a0a8a3SJed Brown     ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
141b1a0a8a3SJed Brown     if (osm->same_local_solves) {
142b1a0a8a3SJed Brown       if (osm->ksp) {
143af538404SDmitry Karpeev         ierr = PetscViewerASCIIPrintf(viewer,"  Local solve is same for all subdomains, in the following KSP and PC objects:\n");CHKERRQ(ierr);
144b1a0a8a3SJed Brown         ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
145b1a0a8a3SJed Brown         if (!rank) {
146b1a0a8a3SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
147b1a0a8a3SJed Brown           ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);
148b1a0a8a3SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
149b1a0a8a3SJed Brown         }
150b1a0a8a3SJed Brown         ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
151b1a0a8a3SJed Brown       }
152b1a0a8a3SJed Brown     } else {
153b1a0a8a3SJed Brown       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154af538404SDmitry Karpeev       ierr = PetscViewerASCIIPrintf(viewer,"  Local solve info for each subdomain is in the following KSP and PC objects:\n");CHKERRQ(ierr);
155b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
156b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr);
157f746d493SDmitry Karpeev       for (i=0; i<osm->nmax; i++) {
158b1a0a8a3SJed Brown         ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
159f746d493SDmitry Karpeev         if (i < osm->n) {
160b1a0a8a3SJed Brown           ierr = ISGetLocalSize(osm->is[i],&bsz);CHKERRQ(ierr);
1617b23a99aSBarry Smith           ierr = PetscViewerASCIISynchronizedAllow(sviewer,PETSC_TRUE);CHKERRQ(ierr);
162af538404SDmitry Karpeev           ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"[%d:%d] local subdomain number %D, size = %D\n",(int)rank,(int)size,i,bsz);CHKERRQ(ierr);
163b1a0a8a3SJed Brown           ierr = KSPView(osm->ksp[i],sviewer);CHKERRQ(ierr);
164b1a0a8a3SJed Brown           ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr);
1657b23a99aSBarry Smith           ierr = PetscViewerFlush(sviewer);CHKERRQ(ierr);
1667b23a99aSBarry Smith           ierr = PetscViewerASCIISynchronizedAllow(sviewer,PETSC_FALSE);CHKERRQ(ierr);
167b1a0a8a3SJed Brown         }
168b1a0a8a3SJed Brown         ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
169b1a0a8a3SJed Brown       }
170b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
171b1a0a8a3SJed Brown       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
172b1a0a8a3SJed Brown     }
173b1a0a8a3SJed Brown   } else if (isstring) {
174af538404SDmitry Karpeev     ierr = PetscViewerStringSPrintf(viewer," subdomains=%D, overlap=%D, type=%s",osm->n,osm->overlap,PCGASMTypes[osm->type]);CHKERRQ(ierr);
175b1a0a8a3SJed Brown     ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
176b1a0a8a3SJed Brown     if (osm->ksp) {ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);}
177b1a0a8a3SJed Brown     ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
178b1a0a8a3SJed Brown   } else {
179f746d493SDmitry Karpeev     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCGASM",((PetscObject)viewer)->type_name);
180b1a0a8a3SJed Brown   }
181b1a0a8a3SJed Brown   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
182af538404SDmitry Karpeev   if(print_subdomains) {
183af538404SDmitry Karpeev     ierr = PCGASMPrintSubdomains(pc);CHKERRQ(ierr);
184af538404SDmitry Karpeev   }
185b1a0a8a3SJed Brown   PetscFunctionReturn(0);
186b1a0a8a3SJed Brown }
187b1a0a8a3SJed Brown 
188af538404SDmitry Karpeev 
189af538404SDmitry Karpeev 
190af538404SDmitry Karpeev 
191af538404SDmitry Karpeev 
192b1a0a8a3SJed Brown #undef __FUNCT__
193f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUp_GASM"
194f746d493SDmitry Karpeev static PetscErrorCode PCSetUp_GASM(PC pc)
195b1a0a8a3SJed Brown {
196f746d493SDmitry Karpeev   PC_GASM         *osm  = (PC_GASM*)pc->data;
197b1a0a8a3SJed Brown   PetscErrorCode ierr;
198b1a0a8a3SJed Brown   PetscBool      symset,flg;
19988389755SJed Brown   PetscInt       i;
200c10bc1a1SDmitry Karpeev   PetscMPIInt    rank, size;
201b1a0a8a3SJed Brown   MatReuse       scall = MAT_REUSE_MATRIX;
202b1a0a8a3SJed Brown   KSP            ksp;
203b1a0a8a3SJed Brown   PC             subpc;
204b1a0a8a3SJed Brown   const char     *prefix,*pprefix;
205f746d493SDmitry Karpeev   PetscInt       dn;       /* Number of indices in a single subdomain assigned to this processor. */
206f746d493SDmitry Karpeev   const PetscInt *didx;    /* Indices from a single subdomain assigned to this processor. */
207f746d493SDmitry Karpeev   PetscInt       ddn;      /* Number of indices in all subdomains assigned to this processor. */
208f746d493SDmitry Karpeev   PetscInt       *ddidx;   /* Indices of all subdomains assigned to this processor. */
209f746d493SDmitry Karpeev   IS             gid;      /* Identity IS of the size of all subdomains assigned to this processor. */
210f746d493SDmitry Karpeev   Vec            x,y;
211f746d493SDmitry Karpeev   PetscScalar    *gxarray, *gyarray;
2126d98aee9SDmitry Karpeev   PetscInt       gfirst, glast;
213*fdc48646SDmitry Karpeev   DM             *domain_dm = PETSC_NULL;
214b1a0a8a3SJed Brown 
215b1a0a8a3SJed Brown   PetscFunctionBegin;
216c10bc1a1SDmitry Karpeev   ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
217c10bc1a1SDmitry Karpeev   ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
218b1a0a8a3SJed Brown   if (!pc->setupcalled) {
219b1a0a8a3SJed Brown 
220b1a0a8a3SJed Brown     if (!osm->type_set) {
221b1a0a8a3SJed Brown       ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr);
222f746d493SDmitry Karpeev       if (symset && flg) { osm->type = PC_GASM_BASIC; }
223b1a0a8a3SJed Brown     }
224b1a0a8a3SJed Brown 
22544fe18e5SDmitry Karpeev     if (osm->N == PETSC_DECIDE && osm->n < 1) {
226*fdc48646SDmitry Karpeev       /* no subdomains given, try pc->dm */
227*fdc48646SDmitry Karpeev       if(pc->dm) {
228*fdc48646SDmitry Karpeev         char      ddm_name[1024];
229*fdc48646SDmitry Karpeev         DM        ddm;
230*fdc48646SDmitry Karpeev         PetscBool flg;
231*fdc48646SDmitry Karpeev         PetscInt     num_domains, d;
232*fdc48646SDmitry Karpeev         char         **domain_names;
233*fdc48646SDmitry Karpeev         IS           *domain_is;
234*fdc48646SDmitry Karpeev         /* Allow the user to request a decomposition DM by name */
235*fdc48646SDmitry Karpeev         ierr = PetscStrncpy(ddm_name, "", 1024); CHKERRQ(ierr);
236*fdc48646SDmitry Karpeev         ierr = PetscOptionsString("-pc_asm_decomposition_dm", "Name of the DM defining the composition", "PCSetDM", ddm_name, ddm_name,1024,&flg); CHKERRQ(ierr);
237*fdc48646SDmitry Karpeev         if(flg) {
238*fdc48646SDmitry Karpeev           ierr = DMCreateDecompositionDM(pc->dm, ddm_name, &ddm); CHKERRQ(ierr);
239*fdc48646SDmitry Karpeev           if(!ddm) {
240*fdc48646SDmitry Karpeev             SETERRQ1(((PetscObject)pc)->comm, PETSC_ERR_ARG_WRONGSTATE, "Uknown DM decomposition name %s", ddm_name);
241*fdc48646SDmitry Karpeev           }
242*fdc48646SDmitry Karpeev           ierr = PetscInfo(pc,"Using decomposition DM defined using options database\n");CHKERRQ(ierr);
243*fdc48646SDmitry Karpeev           ierr = PCSetDM(pc,ddm); CHKERRQ(ierr);
244*fdc48646SDmitry Karpeev         }
245*fdc48646SDmitry Karpeev         ierr = DMCreateDecomposition(pc->dm, &num_domains, &domain_names, &domain_is, &domain_dm);    CHKERRQ(ierr);
246*fdc48646SDmitry Karpeev         ierr = PCGASMSetLocalSubdomains(pc, num_domains, domain_is, PETSC_NULL);CHKERRQ(ierr);
247*fdc48646SDmitry Karpeev         for(d = 0; d < num_domains; ++d) {
248*fdc48646SDmitry Karpeev           ierr = PetscFree(domain_names[d]); CHKERRQ(ierr);
249*fdc48646SDmitry Karpeev           ierr = ISDestroy(&domain_is[d]);   CHKERRQ(ierr);
250*fdc48646SDmitry Karpeev         }
251*fdc48646SDmitry Karpeev         ierr = PetscFree(domain_names);CHKERRQ(ierr);
252*fdc48646SDmitry Karpeev         ierr = PetscFree(domain_is);CHKERRQ(ierr);
253*fdc48646SDmitry Karpeev       }
254*fdc48646SDmitry Karpeev       else { /* no dm, use one per processor */
25544fe18e5SDmitry Karpeev         osm->nmax = osm->n = 1;
256b1a0a8a3SJed Brown         ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
257f746d493SDmitry Karpeev         osm->N = size;
258*fdc48646SDmitry Karpeev       }
259f746d493SDmitry Karpeev     } else if (osm->N == PETSC_DECIDE) {
260b1a0a8a3SJed Brown       PetscInt inwork[2], outwork[2];
261f746d493SDmitry Karpeev       /* determine global number of subdomains and the max number of local subdomains */
262f746d493SDmitry Karpeev       inwork[0] = inwork[1] = osm->n;
263b1a0a8a3SJed Brown       ierr = MPI_Allreduce(inwork,outwork,1,MPIU_2INT,PetscMaxSum_Op,((PetscObject)pc)->comm);CHKERRQ(ierr);
264f746d493SDmitry Karpeev       osm->nmax = outwork[0];
265f746d493SDmitry Karpeev       osm->N    = outwork[1];
266b1a0a8a3SJed Brown     }
267b1a0a8a3SJed Brown     if (!osm->is){ /* create the index sets */
268f746d493SDmitry Karpeev       ierr = PCGASMCreateSubdomains(pc->pmat,osm->n,&osm->is);CHKERRQ(ierr);
269b1a0a8a3SJed Brown     }
27093c1ec32SDmitry Karpeev     if (!osm->is_local) {
27193c1ec32SDmitry Karpeev       /*
27293c1ec32SDmitry Karpeev 	 This indicates that osm->is should define a nonoverlapping decomposition
27393c1ec32SDmitry Karpeev 	 (there is no way to really guarantee that if subdomains are set by the user through PCGASMSetLocalSubdomains,
27493c1ec32SDmitry Karpeev 	  but the assumption is that either the user does the right thing, or subdomains in ossm->is have been created
27593c1ec32SDmitry Karpeev 	  via PCGASMCreateSubdomains, which guarantees a nonoverlapping decomposition).
27693c1ec32SDmitry Karpeev 	 Therefore, osm->is will be used to define osm->is_local.
27793c1ec32SDmitry Karpeev 	 If a nonzero overlap has been requested by the user, then osm->is will be expanded and will overlap,
27893c1ec32SDmitry Karpeev 	 so osm->is_local should obtain a copy of osm->is while they are still (presumably) nonoverlapping.
27993c1ec32SDmitry Karpeev 	 Otherwise (no overlap has been requested), osm->is_local are simply aliases for osm->is.
28093c1ec32SDmitry Karpeev       */
281f746d493SDmitry Karpeev       ierr = PetscMalloc(osm->n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
282f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
283b1a0a8a3SJed Brown         if (osm->overlap > 0) { /* With positive overlap, osm->is[i] will be modified */
284b1a0a8a3SJed Brown           ierr = ISDuplicate(osm->is[i],&osm->is_local[i]);CHKERRQ(ierr);
285b1a0a8a3SJed Brown           ierr = ISCopy(osm->is[i],osm->is_local[i]);CHKERRQ(ierr);
286b1a0a8a3SJed Brown         } else {
287b1a0a8a3SJed Brown           ierr = PetscObjectReference((PetscObject)osm->is[i]);CHKERRQ(ierr);
288b1a0a8a3SJed Brown           osm->is_local[i] = osm->is[i];
289b1a0a8a3SJed Brown         }
290b1a0a8a3SJed Brown       }
291b1a0a8a3SJed Brown     }
29293c1ec32SDmitry Karpeev     /* Beyond this point osm->is_local is not null. */
29393c1ec32SDmitry Karpeev     if (osm->overlap > 0) {
29493c1ec32SDmitry Karpeev       /* Extend the "overlapping" regions by a number of steps */
29593c1ec32SDmitry Karpeev       ierr = MatIncreaseOverlap(pc->pmat,osm->n,osm->is,osm->overlap);CHKERRQ(ierr);
29693c1ec32SDmitry Karpeev     }
297b1a0a8a3SJed Brown     ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
298b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
299f746d493SDmitry Karpeev     ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&flg,PETSC_NULL);CHKERRQ(ierr);
300f746d493SDmitry Karpeev     if (flg) { ierr = PCGASMPrintSubdomains(pc);CHKERRQ(ierr); }
301b1a0a8a3SJed Brown 
302b1a0a8a3SJed Brown     if (osm->sort_indices) {
303f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
304b1a0a8a3SJed Brown         ierr = ISSort(osm->is[i]);CHKERRQ(ierr);
305b1a0a8a3SJed Brown 	ierr = ISSort(osm->is_local[i]);CHKERRQ(ierr);
306b1a0a8a3SJed Brown       }
307b1a0a8a3SJed Brown     }
308f746d493SDmitry Karpeev     /* Merge the ISs, create merged vectors and scatter contexts. */
30993c1ec32SDmitry Karpeev     /* Restriction ISs. */
310f746d493SDmitry Karpeev     ddn = 0;
311f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
312f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
313f746d493SDmitry Karpeev       ddn += dn;
314f746d493SDmitry Karpeev     }
315f746d493SDmitry Karpeev     ierr = PetscMalloc(ddn*sizeof(PetscInt), &ddidx);CHKERRQ(ierr);
316f746d493SDmitry Karpeev     ddn = 0;
317f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
318f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
319f746d493SDmitry Karpeev       ierr = ISGetIndices(osm->is[i],&didx);CHKERRQ(ierr);
320f746d493SDmitry Karpeev       ierr = PetscMemcpy(ddidx+ddn, didx, sizeof(PetscInt)*dn);CHKERRQ(ierr);
321f746d493SDmitry Karpeev       ierr = ISRestoreIndices(osm->is[i], &didx);CHKERRQ(ierr);
32293c1ec32SDmitry Karpeev       ddn += dn;
323f746d493SDmitry Karpeev     }
324f746d493SDmitry Karpeev     ierr = ISCreateGeneral(((PetscObject)(pc))->comm, ddn, ddidx, PETSC_OWN_POINTER, &osm->gis);CHKERRQ(ierr);
325f746d493SDmitry Karpeev     ierr = MatGetVecs(pc->pmat,&x,&y);CHKERRQ(ierr);
326f746d493SDmitry Karpeev     ierr = VecCreateMPI(((PetscObject)pc)->comm, ddn, PETSC_DECIDE, &osm->gx);CHKERRQ(ierr);
327f746d493SDmitry Karpeev     ierr = VecDuplicate(osm->gx,&osm->gy);CHKERRQ(ierr);
3286d98aee9SDmitry Karpeev     ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast);CHKERRQ(ierr);
3296d98aee9SDmitry Karpeev     ierr = ISCreateStride(((PetscObject)pc)->comm,ddn,gfirst,1, &gid);CHKERRQ(ierr);
330f746d493SDmitry Karpeev     ierr = VecScatterCreate(x,osm->gis,osm->gx,gid, &(osm->grestriction));CHKERRQ(ierr);
331fcfd50ebSBarry Smith     ierr = ISDestroy(&gid);CHKERRQ(ierr);
33293c1ec32SDmitry Karpeev     /* Prolongation ISs */
33381a5c4aaSDmitry Karpeev     { PetscInt       dn_local;       /* Number of indices in the local part of a single domain assigned to this processor. */
334f746d493SDmitry Karpeev       const PetscInt *didx_local;    /* Global indices from the local part of a single domain assigned to this processor. */
335f746d493SDmitry Karpeev       PetscInt       ddn_local;      /* Number of indices in the local part of the disjoint union all domains assigned to this processor. */
336f746d493SDmitry Karpeev       PetscInt       *ddidx_local;   /* Global indices of the local part of the disjoint union of all domains assigned to this processor. */
337f746d493SDmitry Karpeev       /**/
33893c1ec32SDmitry Karpeev       ISLocalToGlobalMapping ltog;          /* Map from global to local indices on the disjoint union of subdomains: "local" ind's run from 0 to ddn-1. */
33993c1ec32SDmitry Karpeev       PetscInt              *ddidx_llocal;  /* Mapped local indices of the disjoint union of local parts of subdomains. */
340f746d493SDmitry 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. */
341f746d493SDmitry Karpeev       IS                     gis_llocal;    /* IS with ddidx_llocal indices. */
342f746d493SDmitry Karpeev       PetscInt               j;
343f746d493SDmitry Karpeev       ddn_local = 0;
344f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
345f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local);CHKERRQ(ierr);
346f746d493SDmitry Karpeev 	ddn_local += dn_local;
347f746d493SDmitry Karpeev       }
348f746d493SDmitry Karpeev       ierr = PetscMalloc(ddn_local*sizeof(PetscInt), &ddidx_local);CHKERRQ(ierr);
349f746d493SDmitry Karpeev       ddn_local = 0;
350f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
351f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local);CHKERRQ(ierr);
352f746d493SDmitry Karpeev 	ierr = ISGetIndices(osm->is_local[i],&didx_local);CHKERRQ(ierr);
353f746d493SDmitry Karpeev 	ierr = PetscMemcpy(ddidx_local+ddn_local, didx_local, sizeof(PetscInt)*dn_local);CHKERRQ(ierr);
354f746d493SDmitry Karpeev 	ierr = ISRestoreIndices(osm->is_local[i], &didx_local);CHKERRQ(ierr);
355f746d493SDmitry Karpeev 	ddn_local += dn_local;
356f746d493SDmitry Karpeev       }
357ab3e923fSDmitry Karpeev       ierr = PetscMalloc(sizeof(PetscInt)*ddn_local, &ddidx_llocal);CHKERRQ(ierr);
358f746d493SDmitry Karpeev       ierr = ISCreateGeneral(((PetscObject)pc)->comm, ddn_local, ddidx_local, PETSC_OWN_POINTER, &(osm->gis_local));CHKERRQ(ierr);
359f746d493SDmitry Karpeev       ierr = ISLocalToGlobalMappingCreateIS(osm->gis,&ltog);CHKERRQ(ierr);
36081a5c4aaSDmitry Karpeev       ierr = ISGlobalToLocalMappingApply(ltog,IS_GTOLM_DROP,ddn_local,ddidx_local,&ddn_llocal,ddidx_llocal);CHKERRQ(ierr);
3616bf464f9SBarry Smith       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
36293c1ec32SDmitry 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);
363f746d493SDmitry Karpeev       /* Now convert these localized indices into the global indices into the merged output vector. */
3646d98aee9SDmitry Karpeev       ierr = VecGetOwnershipRange(osm->gy, &gfirst, &glast);CHKERRQ(ierr);
365f746d493SDmitry Karpeev       for(j=0; j < ddn_llocal; ++j) {
3666d98aee9SDmitry Karpeev 	ddidx_llocal[j] += gfirst;
367f746d493SDmitry Karpeev       }
368f746d493SDmitry Karpeev       ierr = ISCreateGeneral(PETSC_COMM_SELF,ddn_llocal,ddidx_llocal,PETSC_OWN_POINTER,&gis_llocal);CHKERRQ(ierr);
369f746d493SDmitry Karpeev       ierr = VecScatterCreate(y,osm->gis_local,osm->gy,gis_llocal,&osm->gprolongation);CHKERRQ(ierr);
370fcfd50ebSBarry Smith       ierr = ISDestroy(&gis_llocal);CHKERRQ(ierr);
371b1a0a8a3SJed Brown     }
372f746d493SDmitry Karpeev     /* Create the subdomain work vectors. */
373f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->x);CHKERRQ(ierr);
374f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->y);CHKERRQ(ierr);
3756d98aee9SDmitry Karpeev     ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast);CHKERRQ(ierr);
376f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gx, &gxarray);CHKERRQ(ierr);
377f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gy, &gyarray);CHKERRQ(ierr);
378f746d493SDmitry Karpeev     for (i=0, ddn=0; i<osm->n; ++i, ddn += dn) {
37986b96d36SDmitry Karpeev       PetscInt dN;
380f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
38186b96d36SDmitry Karpeev       ierr = ISGetSize(osm->is[i],&dN);CHKERRQ(ierr);
38286b96d36SDmitry Karpeev       ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gxarray+ddn,&osm->x[i]);CHKERRQ(ierr);
38386b96d36SDmitry Karpeev       ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gyarray+ddn,&osm->y[i]);CHKERRQ(ierr);
384b1a0a8a3SJed Brown     }
385f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gx, &gxarray);CHKERRQ(ierr);
386f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gy, &gyarray);CHKERRQ(ierr);
3876bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
3886bf464f9SBarry Smith     ierr = VecDestroy(&y);CHKERRQ(ierr);
389b1a0a8a3SJed Brown     /* Create the local solvers */
390f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(KSP *),&osm->ksp);CHKERRQ(ierr);
39144fe18e5SDmitry Karpeev     for (i=0; i<osm->n; i++) { /* KSPs are local */
39286b96d36SDmitry Karpeev       ierr = KSPCreate(((PetscObject)(osm->is[i]))->comm,&ksp);CHKERRQ(ierr);
393b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,ksp);CHKERRQ(ierr);
394b1a0a8a3SJed Brown       ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1);CHKERRQ(ierr);
395b1a0a8a3SJed Brown       ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr);
396b1a0a8a3SJed Brown       ierr = KSPGetPC(ksp,&subpc);CHKERRQ(ierr);
397b1a0a8a3SJed Brown       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
398b1a0a8a3SJed Brown       ierr = KSPSetOptionsPrefix(ksp,prefix);CHKERRQ(ierr);
399b1a0a8a3SJed Brown       ierr = KSPAppendOptionsPrefix(ksp,"sub_");CHKERRQ(ierr);
400b1a0a8a3SJed Brown       osm->ksp[i] = ksp;
401b1a0a8a3SJed Brown     }
402b1a0a8a3SJed Brown     scall = MAT_INITIAL_MATRIX;
403b1a0a8a3SJed Brown 
404b1a0a8a3SJed Brown   } else {
405b1a0a8a3SJed Brown     /*
406b1a0a8a3SJed Brown        Destroy the blocks from the previous iteration
407b1a0a8a3SJed Brown     */
408b1a0a8a3SJed Brown     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
409f746d493SDmitry Karpeev       ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr);
410b1a0a8a3SJed Brown       scall = MAT_INITIAL_MATRIX;
411b1a0a8a3SJed Brown     }
412b1a0a8a3SJed Brown   }
413b1a0a8a3SJed Brown 
414b1a0a8a3SJed Brown   /*
415f746d493SDmitry Karpeev      Extract out the submatrices.
416b1a0a8a3SJed Brown   */
41781a5c4aaSDmitry Karpeev   if(size > 1) {
4186d42056aSDmitry Karpeev     ierr = MatGetSubMatricesParallel(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr);
41981a5c4aaSDmitry Karpeev   }
42081a5c4aaSDmitry Karpeev   else {
42181a5c4aaSDmitry Karpeev     ierr = MatGetSubMatrices(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr);
42281a5c4aaSDmitry Karpeev   }
423b1a0a8a3SJed Brown   if (scall == MAT_INITIAL_MATRIX) {
424b1a0a8a3SJed Brown     ierr = PetscObjectGetOptionsPrefix((PetscObject)pc->pmat,&pprefix);CHKERRQ(ierr);
425f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
426b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,osm->pmat[i]);CHKERRQ(ierr);
427b1a0a8a3SJed Brown       ierr = PetscObjectSetOptionsPrefix((PetscObject)osm->pmat[i],pprefix);CHKERRQ(ierr);
428b1a0a8a3SJed Brown     }
429b1a0a8a3SJed Brown   }
430b1a0a8a3SJed Brown 
431b1a0a8a3SJed Brown   /* Return control to the user so that the submatrices can be modified (e.g., to apply
432b1a0a8a3SJed Brown      different boundary conditions for the submatrices than for the global problem) */
433c10bc1a1SDmitry Karpeev   ierr = PCModifySubMatrices(pc,osm->n,osm->is,osm->is,osm->pmat,pc->modifysubmatricesP);CHKERRQ(ierr);
434b1a0a8a3SJed Brown 
435b1a0a8a3SJed Brown   /*
436f746d493SDmitry Karpeev      Loop over submatrices putting them into local ksp
437b1a0a8a3SJed Brown   */
438f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
439b1a0a8a3SJed Brown     ierr = KSPSetOperators(osm->ksp[i],osm->pmat[i],osm->pmat[i],pc->flag);CHKERRQ(ierr);
440b1a0a8a3SJed Brown     if (!pc->setupcalled) {
441b1a0a8a3SJed Brown       ierr = KSPSetFromOptions(osm->ksp[i]);CHKERRQ(ierr);
442b1a0a8a3SJed Brown     }
443b1a0a8a3SJed Brown   }
444b1a0a8a3SJed Brown 
445b1a0a8a3SJed Brown   PetscFunctionReturn(0);
446b1a0a8a3SJed Brown }
447b1a0a8a3SJed Brown 
448b1a0a8a3SJed Brown #undef __FUNCT__
449f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUpOnBlocks_GASM"
450f746d493SDmitry Karpeev static PetscErrorCode PCSetUpOnBlocks_GASM(PC pc)
451b1a0a8a3SJed Brown {
452f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
453b1a0a8a3SJed Brown   PetscErrorCode ierr;
454b1a0a8a3SJed Brown   PetscInt       i;
455b1a0a8a3SJed Brown 
456b1a0a8a3SJed Brown   PetscFunctionBegin;
457f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
458b1a0a8a3SJed Brown     ierr = KSPSetUp(osm->ksp[i]);CHKERRQ(ierr);
459b1a0a8a3SJed Brown   }
460b1a0a8a3SJed Brown   PetscFunctionReturn(0);
461b1a0a8a3SJed Brown }
462b1a0a8a3SJed Brown 
463b1a0a8a3SJed Brown #undef __FUNCT__
464f746d493SDmitry Karpeev #define __FUNCT__ "PCApply_GASM"
465f746d493SDmitry Karpeev static PetscErrorCode PCApply_GASM(PC pc,Vec x,Vec y)
466b1a0a8a3SJed Brown {
467f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
468b1a0a8a3SJed Brown   PetscErrorCode ierr;
469f746d493SDmitry Karpeev   PetscInt       i;
470b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
471b1a0a8a3SJed Brown 
472b1a0a8a3SJed Brown   PetscFunctionBegin;
473b1a0a8a3SJed Brown   /*
474b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
475b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
476b1a0a8a3SJed Brown   */
477f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
478b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
479b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
480f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr);
481b1a0a8a3SJed Brown   }
482f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
483b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
484b1a0a8a3SJed Brown   }
485b1a0a8a3SJed Brown 
486f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
487b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
488f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
48986b96d36SDmitry Karpeev   /* do the subdomain solves */
49086b96d36SDmitry Karpeev   for (i=0; i<osm->n; ++i) {
491b1a0a8a3SJed Brown     ierr = KSPSolve(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
492b1a0a8a3SJed Brown   }
493f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
494f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
495b1a0a8a3SJed Brown   PetscFunctionReturn(0);
496b1a0a8a3SJed Brown }
497b1a0a8a3SJed Brown 
498b1a0a8a3SJed Brown #undef __FUNCT__
499f746d493SDmitry Karpeev #define __FUNCT__ "PCApplyTranspose_GASM"
500f746d493SDmitry Karpeev static PetscErrorCode PCApplyTranspose_GASM(PC pc,Vec x,Vec y)
501b1a0a8a3SJed Brown {
502f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
503b1a0a8a3SJed Brown   PetscErrorCode ierr;
504f746d493SDmitry Karpeev   PetscInt       i;
505b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
506b1a0a8a3SJed Brown 
507b1a0a8a3SJed Brown   PetscFunctionBegin;
508b1a0a8a3SJed Brown   /*
509b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
510b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
511b1a0a8a3SJed Brown 
512f746d493SDmitry Karpeev      Note: these are reversed from the PCApply_GASM() because we are applying the
513b1a0a8a3SJed Brown      transpose of the three terms
514b1a0a8a3SJed Brown   */
515f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
516b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
517b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
518f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr);
519b1a0a8a3SJed Brown   }
520f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
521b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
522b1a0a8a3SJed Brown   }
523b1a0a8a3SJed Brown 
524ab3e923fSDmitry Karpeev   ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
525b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
526ab3e923fSDmitry Karpeev   ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
527b1a0a8a3SJed Brown   /* do the local solves */
528ab3e923fSDmitry 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. */
529b1a0a8a3SJed Brown     ierr = KSPSolveTranspose(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
530b1a0a8a3SJed Brown   }
531ab3e923fSDmitry Karpeev   ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
532ab3e923fSDmitry Karpeev   ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
533b1a0a8a3SJed Brown   PetscFunctionReturn(0);
534b1a0a8a3SJed Brown }
535b1a0a8a3SJed Brown 
536b1a0a8a3SJed Brown #undef __FUNCT__
537a06653b4SBarry Smith #define __FUNCT__ "PCReset_GASM"
538a06653b4SBarry Smith static PetscErrorCode PCReset_GASM(PC pc)
539b1a0a8a3SJed Brown {
540f746d493SDmitry Karpeev   PC_GASM        *osm = (PC_GASM*)pc->data;
541b1a0a8a3SJed Brown   PetscErrorCode ierr;
542b1a0a8a3SJed Brown   PetscInt       i;
543b1a0a8a3SJed Brown 
544b1a0a8a3SJed Brown   PetscFunctionBegin;
545b1a0a8a3SJed Brown   if (osm->ksp) {
546f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
547a06653b4SBarry Smith       ierr = KSPReset(osm->ksp[i]);CHKERRQ(ierr);
548b1a0a8a3SJed Brown     }
549b1a0a8a3SJed Brown   }
550b1a0a8a3SJed Brown   if (osm->pmat) {
551f746d493SDmitry Karpeev     if (osm->n > 0) {
552ab3e923fSDmitry Karpeev       ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr);
553b1a0a8a3SJed Brown     }
554b1a0a8a3SJed Brown   }
555d34fcf5fSBarry Smith   if (osm->x) {
556f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
557fcfd50ebSBarry Smith       ierr = VecDestroy(&osm->x[i]);CHKERRQ(ierr);
558fcfd50ebSBarry Smith       ierr = VecDestroy(&osm->y[i]);CHKERRQ(ierr);
559b1a0a8a3SJed Brown     }
560d34fcf5fSBarry Smith   }
5616bf464f9SBarry Smith   ierr = VecDestroy(&osm->gx);CHKERRQ(ierr);
5626bf464f9SBarry Smith   ierr = VecDestroy(&osm->gy);CHKERRQ(ierr);
563ab3e923fSDmitry Karpeev 
5646bf464f9SBarry Smith   ierr = VecScatterDestroy(&osm->grestriction);CHKERRQ(ierr);
5656bf464f9SBarry Smith   ierr = VecScatterDestroy(&osm->gprolongation);CHKERRQ(ierr);
566d34fcf5fSBarry Smith   if (osm->is) {ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr); osm->is = 0;}
567fcfd50ebSBarry Smith   ierr = ISDestroy(&osm->gis);CHKERRQ(ierr);
568fcfd50ebSBarry Smith   ierr = ISDestroy(&osm->gis_local);CHKERRQ(ierr);
569a06653b4SBarry Smith   PetscFunctionReturn(0);
570a06653b4SBarry Smith }
571a06653b4SBarry Smith 
572a06653b4SBarry Smith #undef __FUNCT__
573a06653b4SBarry Smith #define __FUNCT__ "PCDestroy_GASM"
574a06653b4SBarry Smith static PetscErrorCode PCDestroy_GASM(PC pc)
575a06653b4SBarry Smith {
576a06653b4SBarry Smith   PC_GASM         *osm = (PC_GASM*)pc->data;
577a06653b4SBarry Smith   PetscErrorCode ierr;
578a06653b4SBarry Smith   PetscInt       i;
579a06653b4SBarry Smith 
580a06653b4SBarry Smith   PetscFunctionBegin;
581a06653b4SBarry Smith   ierr = PCReset_GASM(pc);CHKERRQ(ierr);
582a06653b4SBarry Smith   if (osm->ksp) {
583a06653b4SBarry Smith     for (i=0; i<osm->n; i++) {
5846bf464f9SBarry Smith       ierr = KSPDestroy(&osm->ksp[i]);CHKERRQ(ierr);
585a06653b4SBarry Smith     }
586a06653b4SBarry Smith     ierr = PetscFree(osm->ksp);CHKERRQ(ierr);
587a06653b4SBarry Smith   }
588a06653b4SBarry Smith   ierr = PetscFree(osm->x);CHKERRQ(ierr);
589a06653b4SBarry Smith   ierr = PetscFree(osm->y);CHKERRQ(ierr);
590c31cb41cSBarry Smith   ierr = PetscFree(pc->data);CHKERRQ(ierr);
591b1a0a8a3SJed Brown   PetscFunctionReturn(0);
592b1a0a8a3SJed Brown }
593b1a0a8a3SJed Brown 
594b1a0a8a3SJed Brown #undef __FUNCT__
595f746d493SDmitry Karpeev #define __FUNCT__ "PCSetFromOptions_GASM"
596ab3e923fSDmitry Karpeev static PetscErrorCode PCSetFromOptions_GASM(PC pc) {
597f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
598b1a0a8a3SJed Brown   PetscErrorCode ierr;
599b1a0a8a3SJed Brown   PetscInt       blocks,ovl;
600b1a0a8a3SJed Brown   PetscBool      symset,flg;
601f746d493SDmitry Karpeev   PCGASMType      gasmtype;
602b1a0a8a3SJed Brown 
603b1a0a8a3SJed Brown   PetscFunctionBegin;
604b1a0a8a3SJed Brown   /* set the type to symmetric if matrix is symmetric */
605b1a0a8a3SJed Brown   if (!osm->type_set && pc->pmat) {
606b1a0a8a3SJed Brown     ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr);
607f746d493SDmitry Karpeev     if (symset && flg) { osm->type = PC_GASM_BASIC; }
608b1a0a8a3SJed Brown   }
60944fe18e5SDmitry Karpeev   ierr = PetscOptionsHead("Generalized additive Schwarz options");CHKERRQ(ierr);
610f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_blocks","Number of subdomains","PCGASMSetTotalSubdomains",osm->n,&blocks,&flg);CHKERRQ(ierr);
611ab3e923fSDmitry Karpeev     if (flg) {ierr = PCGASMSetTotalSubdomains(pc,blocks);CHKERRQ(ierr); }
612f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_overlap","Number of grid points overlap","PCGASMSetOverlap",osm->overlap,&ovl,&flg);CHKERRQ(ierr);
613f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetOverlap(pc,ovl);CHKERRQ(ierr); }
614b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
615f746d493SDmitry Karpeev     ierr = PetscOptionsEnum("-pc_gasm_type","Type of restriction/extension","PCGASMSetType",PCGASMTypes,(PetscEnum)osm->type,(PetscEnum*)&gasmtype,&flg);CHKERRQ(ierr);
616f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetType(pc,gasmtype);CHKERRQ(ierr); }
617b1a0a8a3SJed Brown   ierr = PetscOptionsTail();CHKERRQ(ierr);
618b1a0a8a3SJed Brown   PetscFunctionReturn(0);
619b1a0a8a3SJed Brown }
620b1a0a8a3SJed Brown 
621b1a0a8a3SJed Brown /*------------------------------------------------------------------------------------*/
622b1a0a8a3SJed Brown 
623b1a0a8a3SJed Brown EXTERN_C_BEGIN
624b1a0a8a3SJed Brown #undef __FUNCT__
625f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains_GASM"
6267087cfbeSBarry Smith PetscErrorCode  PCGASMSetLocalSubdomains_GASM(PC pc,PetscInt n,IS is[],IS is_local[])
627b1a0a8a3SJed Brown {
628f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
629b1a0a8a3SJed Brown   PetscErrorCode ierr;
630b1a0a8a3SJed Brown   PetscInt       i;
631b1a0a8a3SJed Brown 
632b1a0a8a3SJed Brown   PetscFunctionBegin;
633b1a0a8a3SJed Brown   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Each process must have 1 or more blocks, n = %D",n);
634f746d493SDmitry Karpeev   if (pc->setupcalled && (n != osm->n || is)) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetLocalSubdomains() should be called before calling PCSetUp().");
635b1a0a8a3SJed Brown 
636b1a0a8a3SJed Brown   if (!pc->setupcalled) {
63793c1ec32SDmitry Karpeev     osm->n            = n;
63893c1ec32SDmitry Karpeev     osm->is           = 0;
63993c1ec32SDmitry Karpeev     osm->is_local     = 0;
640b1a0a8a3SJed Brown     if (is) {
641b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is[i]);CHKERRQ(ierr);}
642b1a0a8a3SJed Brown     }
643b1a0a8a3SJed Brown     if (is_local) {
644b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is_local[i]);CHKERRQ(ierr);}
645b1a0a8a3SJed Brown     }
646b1a0a8a3SJed Brown     if (osm->is) {
647ab3e923fSDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr);
648b1a0a8a3SJed Brown     }
649b1a0a8a3SJed Brown     if (is) {
650b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is);CHKERRQ(ierr);
651b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is[i] = is[i]; }
652f746d493SDmitry Karpeev       /* Flag indicating that the user has set overlapping subdomains so PCGASM should not increase their size. */
653b1a0a8a3SJed Brown       osm->overlap = -1;
654b1a0a8a3SJed Brown     }
655b1a0a8a3SJed Brown     if (is_local) {
656b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
657b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is_local[i] = is_local[i]; }
658b1a0a8a3SJed Brown     }
659b1a0a8a3SJed Brown   }
660b1a0a8a3SJed Brown   PetscFunctionReturn(0);
661b1a0a8a3SJed Brown }
662b1a0a8a3SJed Brown EXTERN_C_END
663b1a0a8a3SJed Brown 
664b1a0a8a3SJed Brown EXTERN_C_BEGIN
665b1a0a8a3SJed Brown #undef __FUNCT__
666f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains_GASM"
6677087cfbeSBarry Smith PetscErrorCode  PCGASMSetTotalSubdomains_GASM(PC pc,PetscInt N) {
668f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
669b1a0a8a3SJed Brown   PetscErrorCode ierr;
670b1a0a8a3SJed Brown   PetscMPIInt    rank,size;
671b1a0a8a3SJed Brown   PetscInt       n;
672b1a0a8a3SJed Brown 
673b1a0a8a3SJed Brown   PetscFunctionBegin;
674b1a0a8a3SJed Brown   if (N < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of total blocks must be > 0, N = %D",N);
675b1a0a8a3SJed Brown 
676b1a0a8a3SJed Brown   /*
677b1a0a8a3SJed Brown      Split the subdomains equally among all processors
678b1a0a8a3SJed Brown   */
679b1a0a8a3SJed Brown   ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
680b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
681b1a0a8a3SJed Brown   n = N/size + ((N % size) > rank);
682b1a0a8a3SJed 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);
683f746d493SDmitry Karpeev   if (pc->setupcalled && n != osm->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetTotalSubdomains() should be called before PCSetUp().");
684b1a0a8a3SJed Brown   if (!pc->setupcalled) {
685b1a0a8a3SJed Brown     if (osm->is) {
686ab3e923fSDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr);
687b1a0a8a3SJed Brown     }
68893c1ec32SDmitry Karpeev     osm->N            = N;
689f746d493SDmitry Karpeev     osm->n            = n;
690b1a0a8a3SJed Brown     osm->is           = 0;
691b1a0a8a3SJed Brown     osm->is_local     = 0;
692b1a0a8a3SJed Brown   }
693b1a0a8a3SJed Brown   PetscFunctionReturn(0);
694ab3e923fSDmitry Karpeev }/* PCGASMSetTotalSubdomains_GASM() */
695b1a0a8a3SJed Brown EXTERN_C_END
696b1a0a8a3SJed Brown 
697b1a0a8a3SJed Brown EXTERN_C_BEGIN
698b1a0a8a3SJed Brown #undef __FUNCT__
699f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap_GASM"
7007087cfbeSBarry Smith PetscErrorCode  PCGASMSetOverlap_GASM(PC pc,PetscInt ovl)
701b1a0a8a3SJed Brown {
702f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
703b1a0a8a3SJed Brown 
704b1a0a8a3SJed Brown   PetscFunctionBegin;
705b1a0a8a3SJed Brown   if (ovl < 0) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Negative overlap value requested");
706f746d493SDmitry Karpeev   if (pc->setupcalled && ovl != osm->overlap) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetOverlap() should be called before PCSetUp().");
707b1a0a8a3SJed Brown   if (!pc->setupcalled) {
708b1a0a8a3SJed Brown     osm->overlap = ovl;
709b1a0a8a3SJed Brown   }
710b1a0a8a3SJed Brown   PetscFunctionReturn(0);
711b1a0a8a3SJed Brown }
712b1a0a8a3SJed Brown EXTERN_C_END
713b1a0a8a3SJed Brown 
714b1a0a8a3SJed Brown EXTERN_C_BEGIN
715b1a0a8a3SJed Brown #undef __FUNCT__
716f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType_GASM"
7177087cfbeSBarry Smith PetscErrorCode  PCGASMSetType_GASM(PC pc,PCGASMType type)
718b1a0a8a3SJed Brown {
719f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
720b1a0a8a3SJed Brown 
721b1a0a8a3SJed Brown   PetscFunctionBegin;
722b1a0a8a3SJed Brown   osm->type     = type;
723b1a0a8a3SJed Brown   osm->type_set = PETSC_TRUE;
724b1a0a8a3SJed Brown   PetscFunctionReturn(0);
725b1a0a8a3SJed Brown }
726b1a0a8a3SJed Brown EXTERN_C_END
727b1a0a8a3SJed Brown 
728b1a0a8a3SJed Brown EXTERN_C_BEGIN
729b1a0a8a3SJed Brown #undef __FUNCT__
730f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices_GASM"
7317087cfbeSBarry Smith PetscErrorCode  PCGASMSetSortIndices_GASM(PC pc,PetscBool  doSort)
732b1a0a8a3SJed Brown {
733f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
734b1a0a8a3SJed Brown 
735b1a0a8a3SJed Brown   PetscFunctionBegin;
736b1a0a8a3SJed Brown   osm->sort_indices = doSort;
737b1a0a8a3SJed Brown   PetscFunctionReturn(0);
738b1a0a8a3SJed Brown }
739b1a0a8a3SJed Brown EXTERN_C_END
740b1a0a8a3SJed Brown 
741b1a0a8a3SJed Brown EXTERN_C_BEGIN
742b1a0a8a3SJed Brown #undef __FUNCT__
743f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP_GASM"
74444fe18e5SDmitry Karpeev /*
74544fe18e5SDmitry Karpeev    FIX: This routine might need to be modified once multiple ranks per subdomain are allowed.
74644fe18e5SDmitry Karpeev         In particular, it would upset the global subdomain number calculation.
74744fe18e5SDmitry Karpeev */
7487087cfbeSBarry Smith PetscErrorCode  PCGASMGetSubKSP_GASM(PC pc,PetscInt *n,PetscInt *first,KSP **ksp)
749b1a0a8a3SJed Brown {
750f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
751b1a0a8a3SJed Brown   PetscErrorCode ierr;
752b1a0a8a3SJed Brown 
753b1a0a8a3SJed Brown   PetscFunctionBegin;
754ab3e923fSDmitry 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");
755b1a0a8a3SJed Brown 
756ab3e923fSDmitry Karpeev   if (n) {
757ab3e923fSDmitry Karpeev     *n = osm->n;
758b1a0a8a3SJed Brown   }
759ab3e923fSDmitry Karpeev   if (first) {
760ab3e923fSDmitry Karpeev     ierr = MPI_Scan(&osm->n,first,1,MPIU_INT,MPI_SUM,((PetscObject)pc)->comm);CHKERRQ(ierr);
761ab3e923fSDmitry Karpeev     *first -= osm->n;
762b1a0a8a3SJed Brown   }
763b1a0a8a3SJed Brown   if (ksp) {
764b1a0a8a3SJed Brown     /* Assume that local solves are now different; not necessarily
765f746d493SDmitry Karpeev        true though!  This flag is used only for PCView_GASM() */
766b1a0a8a3SJed Brown     *ksp                   = osm->ksp;
767b1a0a8a3SJed Brown     osm->same_local_solves = PETSC_FALSE;
768b1a0a8a3SJed Brown   }
769b1a0a8a3SJed Brown   PetscFunctionReturn(0);
770ab3e923fSDmitry Karpeev }/* PCGASMGetSubKSP_GASM() */
771b1a0a8a3SJed Brown EXTERN_C_END
772b1a0a8a3SJed Brown 
773b1a0a8a3SJed Brown 
774b1a0a8a3SJed Brown #undef __FUNCT__
775f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains"
776b1a0a8a3SJed Brown /*@C
777f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains - Sets the local subdomains (for this processor
778b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
779b1a0a8a3SJed Brown 
780b1a0a8a3SJed Brown     Collective on PC
781b1a0a8a3SJed Brown 
782b1a0a8a3SJed Brown     Input Parameters:
783b1a0a8a3SJed Brown +   pc - the preconditioner context
784b1a0a8a3SJed Brown .   n - the number of subdomains for this processor (default value = 1)
785b1a0a8a3SJed Brown .   is - the index set that defines the subdomains for this processor
786b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
787b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
788b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
789b1a0a8a3SJed Brown 
790b1a0a8a3SJed Brown     Notes:
791b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
792b1a0a8a3SJed Brown 
793f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
794b1a0a8a3SJed Brown 
795f746d493SDmitry Karpeev     Use PCGASMSetTotalSubdomains() to set the subdomains for all processors.
796b1a0a8a3SJed Brown 
797b1a0a8a3SJed Brown     Level: advanced
798b1a0a8a3SJed Brown 
799f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
800b1a0a8a3SJed Brown 
801f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
802f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
803b1a0a8a3SJed Brown @*/
8047087cfbeSBarry Smith PetscErrorCode  PCGASMSetLocalSubdomains(PC pc,PetscInt n,IS is[],IS is_local[])
805b1a0a8a3SJed Brown {
806b1a0a8a3SJed Brown   PetscErrorCode ierr;
807b1a0a8a3SJed Brown 
808b1a0a8a3SJed Brown   PetscFunctionBegin;
809b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
810f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetLocalSubdomains_C",(PC,PetscInt,IS[],IS[]),(pc,n,is,is_local));CHKERRQ(ierr);
811b1a0a8a3SJed Brown   PetscFunctionReturn(0);
812b1a0a8a3SJed Brown }
813b1a0a8a3SJed Brown 
814b1a0a8a3SJed Brown #undef __FUNCT__
815f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains"
816b1a0a8a3SJed Brown /*@C
817f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains - Sets the subdomains for all processor for the
818b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
819b1a0a8a3SJed Brown     PC communicator must call this routine, with the same index sets.
820b1a0a8a3SJed Brown 
821b1a0a8a3SJed Brown     Collective on PC
822b1a0a8a3SJed Brown 
823b1a0a8a3SJed Brown     Input Parameters:
824b1a0a8a3SJed Brown +   pc - the preconditioner context
825b1a0a8a3SJed Brown .   n - the number of subdomains for all processors
826b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for all processor
827b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
828b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
829b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
830b1a0a8a3SJed Brown 
831b1a0a8a3SJed Brown     Options Database Key:
832b1a0a8a3SJed Brown     To set the total number of subdomain blocks rather than specify the
833b1a0a8a3SJed Brown     index sets, use the option
834f746d493SDmitry Karpeev .    -pc_gasm_blocks <blks> - Sets total blocks
835b1a0a8a3SJed Brown 
836b1a0a8a3SJed Brown     Notes:
837b1a0a8a3SJed Brown     Currently you cannot use this to set the actual subdomains with the argument is.
838b1a0a8a3SJed Brown 
839f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
840b1a0a8a3SJed Brown 
841b1a0a8a3SJed Brown     These index sets cannot be destroyed until after completion of the
842f746d493SDmitry Karpeev     linear solves for which the GASM preconditioner is being used.
843b1a0a8a3SJed Brown 
844f746d493SDmitry Karpeev     Use PCGASMSetLocalSubdomains() to set local subdomains.
845b1a0a8a3SJed Brown 
846b1a0a8a3SJed Brown     Level: advanced
847b1a0a8a3SJed Brown 
848f746d493SDmitry Karpeev .keywords: PC, GASM, set, total, global, subdomains, additive Schwarz
849b1a0a8a3SJed Brown 
850f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
851f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
852b1a0a8a3SJed Brown @*/
8537087cfbeSBarry Smith PetscErrorCode  PCGASMSetTotalSubdomains(PC pc,PetscInt N)
854b1a0a8a3SJed Brown {
855b1a0a8a3SJed Brown   PetscErrorCode ierr;
856b1a0a8a3SJed Brown 
857b1a0a8a3SJed Brown   PetscFunctionBegin;
858b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
859f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetTotalSubdomains_C",(PC,PetscInt),(pc,N));CHKERRQ(ierr);
860b1a0a8a3SJed Brown   PetscFunctionReturn(0);
861b1a0a8a3SJed Brown }
862b1a0a8a3SJed Brown 
863b1a0a8a3SJed Brown #undef __FUNCT__
864f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap"
865b1a0a8a3SJed Brown /*@
866f746d493SDmitry Karpeev     PCGASMSetOverlap - Sets the overlap between a pair of subdomains for the
867b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
868b1a0a8a3SJed Brown     PC communicator must call this routine.
869b1a0a8a3SJed Brown 
870b1a0a8a3SJed Brown     Logically Collective on PC
871b1a0a8a3SJed Brown 
872b1a0a8a3SJed Brown     Input Parameters:
873b1a0a8a3SJed Brown +   pc  - the preconditioner context
874b1a0a8a3SJed Brown -   ovl - the amount of overlap between subdomains (ovl >= 0, default value = 1)
875b1a0a8a3SJed Brown 
876b1a0a8a3SJed Brown     Options Database Key:
877f746d493SDmitry Karpeev .   -pc_gasm_overlap <ovl> - Sets overlap
878b1a0a8a3SJed Brown 
879b1a0a8a3SJed Brown     Notes:
880f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.  To use
881f746d493SDmitry Karpeev     multiple blocks per perocessor, see PCGASMSetTotalSubdomains() and
882f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains() (and the option -pc_gasm_blocks <blks>).
883b1a0a8a3SJed Brown 
884b1a0a8a3SJed Brown     The overlap defaults to 1, so if one desires that no additional
885b1a0a8a3SJed Brown     overlap be computed beyond what may have been set with a call to
886f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(), then ovl
887b1a0a8a3SJed Brown     must be set to be 0.  In particular, if one does not explicitly set
888b1a0a8a3SJed Brown     the subdomains an application code, then all overlap would be computed
889f746d493SDmitry Karpeev     internally by PETSc, and using an overlap of 0 would result in an GASM
890b1a0a8a3SJed Brown     variant that is equivalent to the block Jacobi preconditioner.
891b1a0a8a3SJed Brown 
892b1a0a8a3SJed Brown     Note that one can define initial index sets with any overlap via
893f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(); the routine
894f746d493SDmitry Karpeev     PCGASMSetOverlap() merely allows PETSc to extend that overlap further
895b1a0a8a3SJed Brown     if desired.
896b1a0a8a3SJed Brown 
897b1a0a8a3SJed Brown     Level: intermediate
898b1a0a8a3SJed Brown 
899f746d493SDmitry Karpeev .keywords: PC, GASM, set, overlap
900b1a0a8a3SJed Brown 
901f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
902f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
903b1a0a8a3SJed Brown @*/
9047087cfbeSBarry Smith PetscErrorCode  PCGASMSetOverlap(PC pc,PetscInt ovl)
905b1a0a8a3SJed Brown {
906b1a0a8a3SJed Brown   PetscErrorCode ierr;
907b1a0a8a3SJed Brown 
908b1a0a8a3SJed Brown   PetscFunctionBegin;
909b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
910b1a0a8a3SJed Brown   PetscValidLogicalCollectiveInt(pc,ovl,2);
911f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetOverlap_C",(PC,PetscInt),(pc,ovl));CHKERRQ(ierr);
912b1a0a8a3SJed Brown   PetscFunctionReturn(0);
913b1a0a8a3SJed Brown }
914b1a0a8a3SJed Brown 
915b1a0a8a3SJed Brown #undef __FUNCT__
916f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType"
917b1a0a8a3SJed Brown /*@
918f746d493SDmitry Karpeev     PCGASMSetType - Sets the type of restriction and interpolation used
919b1a0a8a3SJed Brown     for local problems in the additive Schwarz method.
920b1a0a8a3SJed Brown 
921b1a0a8a3SJed Brown     Logically Collective on PC
922b1a0a8a3SJed Brown 
923b1a0a8a3SJed Brown     Input Parameters:
924b1a0a8a3SJed Brown +   pc  - the preconditioner context
925f746d493SDmitry Karpeev -   type - variant of GASM, one of
926b1a0a8a3SJed Brown .vb
927f746d493SDmitry Karpeev       PC_GASM_BASIC       - full interpolation and restriction
928f746d493SDmitry Karpeev       PC_GASM_RESTRICT    - full restriction, local processor interpolation
929f746d493SDmitry Karpeev       PC_GASM_INTERPOLATE - full interpolation, local processor restriction
930f746d493SDmitry Karpeev       PC_GASM_NONE        - local processor restriction and interpolation
931b1a0a8a3SJed Brown .ve
932b1a0a8a3SJed Brown 
933b1a0a8a3SJed Brown     Options Database Key:
934f746d493SDmitry Karpeev .   -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
935b1a0a8a3SJed Brown 
936b1a0a8a3SJed Brown     Level: intermediate
937b1a0a8a3SJed Brown 
938f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
939b1a0a8a3SJed Brown 
940f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
941f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
942b1a0a8a3SJed Brown @*/
9437087cfbeSBarry Smith PetscErrorCode  PCGASMSetType(PC pc,PCGASMType type)
944b1a0a8a3SJed Brown {
945b1a0a8a3SJed Brown   PetscErrorCode ierr;
946b1a0a8a3SJed Brown 
947b1a0a8a3SJed Brown   PetscFunctionBegin;
948b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
949b1a0a8a3SJed Brown   PetscValidLogicalCollectiveEnum(pc,type,2);
950f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetType_C",(PC,PCGASMType),(pc,type));CHKERRQ(ierr);
951b1a0a8a3SJed Brown   PetscFunctionReturn(0);
952b1a0a8a3SJed Brown }
953b1a0a8a3SJed Brown 
954b1a0a8a3SJed Brown #undef __FUNCT__
955f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices"
956b1a0a8a3SJed Brown /*@
957f746d493SDmitry Karpeev     PCGASMSetSortIndices - Determines whether subdomain indices are sorted.
958b1a0a8a3SJed Brown 
959b1a0a8a3SJed Brown     Logically Collective on PC
960b1a0a8a3SJed Brown 
961b1a0a8a3SJed Brown     Input Parameters:
962b1a0a8a3SJed Brown +   pc  - the preconditioner context
963b1a0a8a3SJed Brown -   doSort - sort the subdomain indices
964b1a0a8a3SJed Brown 
965b1a0a8a3SJed Brown     Level: intermediate
966b1a0a8a3SJed Brown 
967f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
968b1a0a8a3SJed Brown 
969f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
970f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
971b1a0a8a3SJed Brown @*/
9727087cfbeSBarry Smith PetscErrorCode  PCGASMSetSortIndices(PC pc,PetscBool  doSort)
973b1a0a8a3SJed Brown {
974b1a0a8a3SJed Brown   PetscErrorCode ierr;
975b1a0a8a3SJed Brown 
976b1a0a8a3SJed Brown   PetscFunctionBegin;
977b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
978b1a0a8a3SJed Brown   PetscValidLogicalCollectiveBool(pc,doSort,2);
979f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetSortIndices_C",(PC,PetscBool),(pc,doSort));CHKERRQ(ierr);
980b1a0a8a3SJed Brown   PetscFunctionReturn(0);
981b1a0a8a3SJed Brown }
982b1a0a8a3SJed Brown 
983b1a0a8a3SJed Brown #undef __FUNCT__
984f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP"
985b1a0a8a3SJed Brown /*@C
986f746d493SDmitry Karpeev    PCGASMGetSubKSP - Gets the local KSP contexts for all blocks on
987b1a0a8a3SJed Brown    this processor.
988b1a0a8a3SJed Brown 
989b1a0a8a3SJed Brown    Collective on PC iff first_local is requested
990b1a0a8a3SJed Brown 
991b1a0a8a3SJed Brown    Input Parameter:
992b1a0a8a3SJed Brown .  pc - the preconditioner context
993b1a0a8a3SJed Brown 
994b1a0a8a3SJed Brown    Output Parameters:
995b1a0a8a3SJed Brown +  n_local - the number of blocks on this processor or PETSC_NULL
996b1a0a8a3SJed Brown .  first_local - the global number of the first block on this processor or PETSC_NULL,
997b1a0a8a3SJed Brown                  all processors must request or all must pass PETSC_NULL
998b1a0a8a3SJed Brown -  ksp - the array of KSP contexts
999b1a0a8a3SJed Brown 
1000b1a0a8a3SJed Brown    Note:
1001f746d493SDmitry Karpeev    After PCGASMGetSubKSP() the array of KSPes is not to be freed
1002b1a0a8a3SJed Brown 
1003b1a0a8a3SJed Brown    Currently for some matrix implementations only 1 block per processor
1004b1a0a8a3SJed Brown    is supported.
1005b1a0a8a3SJed Brown 
1006f746d493SDmitry Karpeev    You must call KSPSetUp() before calling PCGASMGetSubKSP().
1007b1a0a8a3SJed Brown 
1008b1a0a8a3SJed Brown    Level: advanced
1009b1a0a8a3SJed Brown 
1010f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, get, sub, KSP, context
1011b1a0a8a3SJed Brown 
1012f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMSetOverlap(),
1013f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(),
1014b1a0a8a3SJed Brown @*/
10157087cfbeSBarry Smith PetscErrorCode  PCGASMGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[])
1016b1a0a8a3SJed Brown {
1017b1a0a8a3SJed Brown   PetscErrorCode ierr;
1018b1a0a8a3SJed Brown 
1019b1a0a8a3SJed Brown   PetscFunctionBegin;
1020b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1021f746d493SDmitry Karpeev   ierr = PetscUseMethod(pc,"PCGASMGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));CHKERRQ(ierr);
1022b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1023b1a0a8a3SJed Brown }
1024b1a0a8a3SJed Brown 
1025b1a0a8a3SJed Brown /* -------------------------------------------------------------------------------------*/
1026b1a0a8a3SJed Brown /*MC
1027f746d493SDmitry Karpeev    PCGASM - Use the (restricted) additive Schwarz method, each block is (approximately) solved with
1028b1a0a8a3SJed Brown            its own KSP object.
1029b1a0a8a3SJed Brown 
1030b1a0a8a3SJed Brown    Options Database Keys:
1031f746d493SDmitry Karpeev +  -pc_gasm_truelocal - Activates PCGGASMSetUseTrueLocal()
1032f746d493SDmitry Karpeev .  -pc_gasm_blocks <blks> - Sets total blocks
1033f746d493SDmitry Karpeev .  -pc_gasm_overlap <ovl> - Sets overlap
1034f746d493SDmitry Karpeev -  -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
1035b1a0a8a3SJed Brown 
1036b1a0a8a3SJed Brown      IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you
1037f746d493SDmitry Karpeev       will get a different convergence rate due to the default option of -pc_gasm_type restrict. Use
1038f746d493SDmitry Karpeev       -pc_gasm_type basic to use the standard GASM.
1039b1a0a8a3SJed Brown 
1040b1a0a8a3SJed Brown    Notes: Each processor can have one or more blocks, but a block cannot be shared by more
1041b1a0a8a3SJed Brown      than one processor. Defaults to one block per processor.
1042b1a0a8a3SJed Brown 
1043b1a0a8a3SJed Brown      To set options on the solvers for each block append -sub_ to all the KSP, and PC
1044b1a0a8a3SJed Brown         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
1045b1a0a8a3SJed Brown 
1046f746d493SDmitry Karpeev      To set the options on the solvers separate for each block call PCGASMGetSubKSP()
1047b1a0a8a3SJed Brown          and set the options directly on the resulting KSP object (you can access its PC
1048b1a0a8a3SJed Brown          with KSPGetPC())
1049b1a0a8a3SJed Brown 
1050b1a0a8a3SJed Brown 
1051b1a0a8a3SJed Brown    Level: beginner
1052b1a0a8a3SJed Brown 
1053b1a0a8a3SJed Brown    Concepts: additive Schwarz method
1054b1a0a8a3SJed Brown 
1055b1a0a8a3SJed Brown     References:
1056b1a0a8a3SJed Brown     An additive variant of the Schwarz alternating method for the case of many subregions
1057b1a0a8a3SJed Brown     M Dryja, OB Widlund - Courant Institute, New York University Technical report
1058b1a0a8a3SJed Brown 
1059b1a0a8a3SJed Brown     Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations,
1060b1a0a8a3SJed Brown     Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X.
1061b1a0a8a3SJed Brown 
1062b1a0a8a3SJed Brown .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
1063f746d493SDmitry Karpeev            PCBJACOBI, PCGASMSetUseTrueLocal(), PCGASMGetSubKSP(), PCGASMSetLocalSubdomains(),
1064f746d493SDmitry Karpeev            PCGASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCGASMSetOverlap(), PCGASMSetType()
1065b1a0a8a3SJed Brown 
1066b1a0a8a3SJed Brown M*/
1067b1a0a8a3SJed Brown 
1068b1a0a8a3SJed Brown EXTERN_C_BEGIN
1069b1a0a8a3SJed Brown #undef __FUNCT__
1070f746d493SDmitry Karpeev #define __FUNCT__ "PCCreate_GASM"
10717087cfbeSBarry Smith PetscErrorCode  PCCreate_GASM(PC pc)
1072b1a0a8a3SJed Brown {
1073b1a0a8a3SJed Brown   PetscErrorCode ierr;
1074f746d493SDmitry Karpeev   PC_GASM         *osm;
1075b1a0a8a3SJed Brown 
1076b1a0a8a3SJed Brown   PetscFunctionBegin;
1077f746d493SDmitry Karpeev   ierr = PetscNewLog(pc,PC_GASM,&osm);CHKERRQ(ierr);
1078ab3e923fSDmitry Karpeev   osm->N                 = PETSC_DECIDE;
1079ab3e923fSDmitry Karpeev   osm->n                 = 0;
1080ab3e923fSDmitry Karpeev   osm->nmax              = 0;
1081b1a0a8a3SJed Brown   osm->overlap           = 1;
1082b1a0a8a3SJed Brown   osm->ksp               = 0;
1083ab3e923fSDmitry Karpeev   osm->grestriction      = 0;
1084ab3e923fSDmitry Karpeev   osm->gprolongation     = 0;
1085ab3e923fSDmitry Karpeev   osm->gx                = 0;
1086ab3e923fSDmitry Karpeev   osm->gy                = 0;
1087b1a0a8a3SJed Brown   osm->x                 = 0;
1088b1a0a8a3SJed Brown   osm->y                 = 0;
1089b1a0a8a3SJed Brown   osm->is                = 0;
1090b1a0a8a3SJed Brown   osm->is_local          = 0;
1091b1a0a8a3SJed Brown   osm->pmat              = 0;
1092f746d493SDmitry Karpeev   osm->type              = PC_GASM_RESTRICT;
1093b1a0a8a3SJed Brown   osm->same_local_solves = PETSC_TRUE;
1094b1a0a8a3SJed Brown   osm->sort_indices      = PETSC_TRUE;
1095b1a0a8a3SJed Brown 
1096b1a0a8a3SJed Brown   pc->data                   = (void*)osm;
1097f746d493SDmitry Karpeev   pc->ops->apply             = PCApply_GASM;
1098f746d493SDmitry Karpeev   pc->ops->applytranspose    = PCApplyTranspose_GASM;
1099f746d493SDmitry Karpeev   pc->ops->setup             = PCSetUp_GASM;
1100a06653b4SBarry Smith   pc->ops->reset             = PCReset_GASM;
1101f746d493SDmitry Karpeev   pc->ops->destroy           = PCDestroy_GASM;
1102f746d493SDmitry Karpeev   pc->ops->setfromoptions    = PCSetFromOptions_GASM;
1103f746d493SDmitry Karpeev   pc->ops->setuponblocks     = PCSetUpOnBlocks_GASM;
1104f746d493SDmitry Karpeev   pc->ops->view              = PCView_GASM;
1105b1a0a8a3SJed Brown   pc->ops->applyrichardson   = 0;
1106b1a0a8a3SJed Brown 
1107f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetLocalSubdomains_C","PCGASMSetLocalSubdomains_GASM",
1108f746d493SDmitry Karpeev                     PCGASMSetLocalSubdomains_GASM);CHKERRQ(ierr);
1109f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetTotalSubdomains_C","PCGASMSetTotalSubdomains_GASM",
1110f746d493SDmitry Karpeev                     PCGASMSetTotalSubdomains_GASM);CHKERRQ(ierr);
1111f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetOverlap_C","PCGASMSetOverlap_GASM",
1112f746d493SDmitry Karpeev                     PCGASMSetOverlap_GASM);CHKERRQ(ierr);
1113f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetType_C","PCGASMSetType_GASM",
1114f746d493SDmitry Karpeev                     PCGASMSetType_GASM);CHKERRQ(ierr);
1115f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetSortIndices_C","PCGASMSetSortIndices_GASM",
1116f746d493SDmitry Karpeev                     PCGASMSetSortIndices_GASM);CHKERRQ(ierr);
1117f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMGetSubKSP_C","PCGASMGetSubKSP_GASM",
1118f746d493SDmitry Karpeev                     PCGASMGetSubKSP_GASM);CHKERRQ(ierr);
1119b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1120b1a0a8a3SJed Brown }
1121b1a0a8a3SJed Brown EXTERN_C_END
1122b1a0a8a3SJed Brown 
1123b1a0a8a3SJed Brown 
1124b1a0a8a3SJed Brown #undef __FUNCT__
1125f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains"
1126b1a0a8a3SJed Brown /*@C
1127f746d493SDmitry Karpeev    PCGASMCreateSubdomains - Creates the index sets for the overlapping Schwarz
1128b1a0a8a3SJed Brown    preconditioner for a any problem on a general grid.
1129b1a0a8a3SJed Brown 
1130b1a0a8a3SJed Brown    Collective
1131b1a0a8a3SJed Brown 
1132b1a0a8a3SJed Brown    Input Parameters:
1133b1a0a8a3SJed Brown +  A - The global matrix operator
1134b1a0a8a3SJed Brown -  n - the number of local blocks
1135b1a0a8a3SJed Brown 
1136b1a0a8a3SJed Brown    Output Parameters:
1137b1a0a8a3SJed Brown .  outis - the array of index sets defining the subdomains
1138b1a0a8a3SJed Brown 
1139b1a0a8a3SJed Brown    Level: advanced
1140b1a0a8a3SJed Brown 
1141f746d493SDmitry Karpeev    Note: this generates nonoverlapping subdomains; the PCGASM will generate the overlap
1142f746d493SDmitry Karpeev     from these if you use PCGASMSetLocalSubdomains()
1143b1a0a8a3SJed Brown 
1144b1a0a8a3SJed Brown     In the Fortran version you must provide the array outis[] already allocated of length n.
1145b1a0a8a3SJed Brown 
1146f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1147b1a0a8a3SJed Brown 
1148f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMDestroySubdomains()
1149b1a0a8a3SJed Brown @*/
11507087cfbeSBarry Smith PetscErrorCode  PCGASMCreateSubdomains(Mat A, PetscInt n, IS* outis[])
1151b1a0a8a3SJed Brown {
1152b1a0a8a3SJed Brown   MatPartitioning           mpart;
1153b1a0a8a3SJed Brown   const char                *prefix;
115411bd1e4dSLisandro Dalcin   PetscErrorCode            (*f)(Mat,MatReuse,Mat*);
1155b1a0a8a3SJed Brown   PetscMPIInt               size;
1156b1a0a8a3SJed Brown   PetscInt                  i,j,rstart,rend,bs;
115711bd1e4dSLisandro Dalcin   PetscBool                 isbaij = PETSC_FALSE,foundpart = PETSC_FALSE;
1158b1a0a8a3SJed Brown   Mat                       Ad = PETSC_NULL, adj;
1159b1a0a8a3SJed Brown   IS                        ispart,isnumb,*is;
1160b1a0a8a3SJed Brown   PetscErrorCode            ierr;
1161b1a0a8a3SJed Brown 
1162b1a0a8a3SJed Brown   PetscFunctionBegin;
1163b1a0a8a3SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1164b1a0a8a3SJed Brown   PetscValidPointer(outis,3);
1165b1a0a8a3SJed Brown   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n);
1166b1a0a8a3SJed Brown 
1167b1a0a8a3SJed Brown   /* Get prefix, row distribution, and block size */
1168b1a0a8a3SJed Brown   ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr);
1169b1a0a8a3SJed Brown   ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);
1170b1a0a8a3SJed Brown   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1171b1a0a8a3SJed 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);
1172b1a0a8a3SJed Brown 
1173b1a0a8a3SJed Brown   /* Get diagonal block from matrix if possible */
1174b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
1175b1a0a8a3SJed Brown   ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**)(void))&f);CHKERRQ(ierr);
1176b1a0a8a3SJed Brown   if (f) {
117711bd1e4dSLisandro Dalcin     ierr = MatGetDiagonalBlock(A,&Ad);CHKERRQ(ierr);
1178b1a0a8a3SJed Brown   } else if (size == 1) {
117911bd1e4dSLisandro Dalcin     Ad = A;
1180b1a0a8a3SJed Brown   }
1181b1a0a8a3SJed Brown   if (Ad) {
1182b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr);
1183b1a0a8a3SJed Brown     if (!isbaij) {ierr = PetscTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);}
1184b1a0a8a3SJed Brown   }
1185b1a0a8a3SJed Brown   if (Ad && n > 1) {
1186b1a0a8a3SJed Brown     PetscBool  match,done;
1187b1a0a8a3SJed Brown     /* Try to setup a good matrix partitioning if available */
1188b1a0a8a3SJed Brown     ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr);
1189b1a0a8a3SJed Brown     ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr);
1190b1a0a8a3SJed Brown     ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr);
1191b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr);
1192b1a0a8a3SJed Brown     if (!match) {
1193b1a0a8a3SJed Brown       ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr);
1194b1a0a8a3SJed Brown     }
1195b1a0a8a3SJed Brown     if (!match) { /* assume a "good" partitioner is available */
1196b1a0a8a3SJed Brown       PetscInt na,*ia,*ja;
1197b1a0a8a3SJed Brown       ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1198b1a0a8a3SJed Brown       if (done) {
1199b1a0a8a3SJed Brown         /* Build adjacency matrix by hand. Unfortunately a call to
1200b1a0a8a3SJed Brown            MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will
1201b1a0a8a3SJed Brown            remove the block-aij structure and we cannot expect
1202b1a0a8a3SJed Brown            MatPartitioning to split vertices as we need */
1203b1a0a8a3SJed Brown         PetscInt i,j,*row,len,nnz,cnt,*iia=0,*jja=0;
1204b1a0a8a3SJed Brown         nnz = 0;
1205b1a0a8a3SJed Brown         for (i=0; i<na; i++) { /* count number of nonzeros */
1206b1a0a8a3SJed Brown           len = ia[i+1] - ia[i];
1207b1a0a8a3SJed Brown           row = ja + ia[i];
1208b1a0a8a3SJed Brown           for (j=0; j<len; j++) {
1209b1a0a8a3SJed Brown             if (row[j] == i) { /* don't count diagonal */
1210b1a0a8a3SJed Brown               len--; break;
1211b1a0a8a3SJed Brown             }
1212b1a0a8a3SJed Brown           }
1213b1a0a8a3SJed Brown           nnz += len;
1214b1a0a8a3SJed Brown         }
1215b1a0a8a3SJed Brown         ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr);
1216b1a0a8a3SJed Brown         ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr);
1217b1a0a8a3SJed Brown         nnz    = 0;
1218b1a0a8a3SJed Brown         iia[0] = 0;
1219b1a0a8a3SJed Brown         for (i=0; i<na; i++) { /* fill adjacency */
1220b1a0a8a3SJed Brown           cnt = 0;
1221b1a0a8a3SJed Brown           len = ia[i+1] - ia[i];
1222b1a0a8a3SJed Brown           row = ja + ia[i];
1223b1a0a8a3SJed Brown           for (j=0; j<len; j++) {
1224b1a0a8a3SJed Brown             if (row[j] != i) { /* if not diagonal */
1225b1a0a8a3SJed Brown               jja[nnz+cnt++] = row[j];
1226b1a0a8a3SJed Brown             }
1227b1a0a8a3SJed Brown           }
1228b1a0a8a3SJed Brown           nnz += cnt;
1229b1a0a8a3SJed Brown           iia[i+1] = nnz;
1230b1a0a8a3SJed Brown         }
1231b1a0a8a3SJed Brown         /* Partitioning of the adjacency matrix */
1232b1a0a8a3SJed Brown         ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,PETSC_NULL,&adj);CHKERRQ(ierr);
1233b1a0a8a3SJed Brown         ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr);
1234b1a0a8a3SJed Brown         ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr);
1235b1a0a8a3SJed Brown         ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr);
1236b1a0a8a3SJed Brown         ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr);
12376bf464f9SBarry Smith         ierr = MatDestroy(&adj);CHKERRQ(ierr);
1238b1a0a8a3SJed Brown         foundpart = PETSC_TRUE;
1239b1a0a8a3SJed Brown       }
1240b1a0a8a3SJed Brown       ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1241b1a0a8a3SJed Brown     }
12426bf464f9SBarry Smith     ierr = MatPartitioningDestroy(&mpart);CHKERRQ(ierr);
1243b1a0a8a3SJed Brown   }
1244b1a0a8a3SJed Brown 
1245b1a0a8a3SJed Brown   ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr);
1246b1a0a8a3SJed Brown   *outis = is;
1247b1a0a8a3SJed Brown 
1248b1a0a8a3SJed Brown   if (!foundpart) {
1249b1a0a8a3SJed Brown 
1250b1a0a8a3SJed Brown     /* Partitioning by contiguous chunks of rows */
1251b1a0a8a3SJed Brown 
1252b1a0a8a3SJed Brown     PetscInt mbs   = (rend-rstart)/bs;
1253b1a0a8a3SJed Brown     PetscInt start = rstart;
1254b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1255b1a0a8a3SJed Brown       PetscInt count = (mbs/n + ((mbs % n) > i)) * bs;
1256b1a0a8a3SJed Brown       ierr   = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr);
1257b1a0a8a3SJed Brown       start += count;
1258b1a0a8a3SJed Brown     }
1259b1a0a8a3SJed Brown 
1260b1a0a8a3SJed Brown   } else {
1261b1a0a8a3SJed Brown 
1262b1a0a8a3SJed Brown     /* Partitioning by adjacency of diagonal block  */
1263b1a0a8a3SJed Brown 
1264b1a0a8a3SJed Brown     const PetscInt *numbering;
1265b1a0a8a3SJed Brown     PetscInt       *count,nidx,*indices,*newidx,start=0;
1266b1a0a8a3SJed Brown     /* Get node count in each partition */
1267b1a0a8a3SJed Brown     ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr);
1268b1a0a8a3SJed Brown     ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr);
1269b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1270b1a0a8a3SJed Brown       for (i=0; i<n; i++) count[i] *= bs;
1271b1a0a8a3SJed Brown     }
1272b1a0a8a3SJed Brown     /* Build indices from node numbering */
1273b1a0a8a3SJed Brown     ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr);
1274b1a0a8a3SJed Brown     ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1275b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */
1276b1a0a8a3SJed Brown     ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr);
1277b1a0a8a3SJed Brown     ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr);
1278b1a0a8a3SJed Brown     ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr);
1279b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1280b1a0a8a3SJed Brown       ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr);
1281b1a0a8a3SJed Brown       for (i=0; i<nidx; i++)
1282b1a0a8a3SJed Brown         for (j=0; j<bs; j++)
1283b1a0a8a3SJed Brown           newidx[i*bs+j] = indices[i]*bs + j;
1284b1a0a8a3SJed Brown       ierr = PetscFree(indices);CHKERRQ(ierr);
1285b1a0a8a3SJed Brown       nidx   *= bs;
1286b1a0a8a3SJed Brown       indices = newidx;
1287b1a0a8a3SJed Brown     }
1288b1a0a8a3SJed Brown     /* Shift to get global indices */
1289b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] += rstart;
1290b1a0a8a3SJed Brown 
1291b1a0a8a3SJed Brown     /* Build the index sets for each block */
1292b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1293b1a0a8a3SJed Brown       ierr   = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],PETSC_COPY_VALUES,&is[i]);CHKERRQ(ierr);
1294b1a0a8a3SJed Brown       ierr   = ISSort(is[i]);CHKERRQ(ierr);
1295b1a0a8a3SJed Brown       start += count[i];
1296b1a0a8a3SJed Brown     }
1297b1a0a8a3SJed Brown 
1298b1a0a8a3SJed Brown     ierr = PetscFree(count);
1299b1a0a8a3SJed Brown     ierr = PetscFree(indices);
1300fcfd50ebSBarry Smith     ierr = ISDestroy(&isnumb);CHKERRQ(ierr);
1301fcfd50ebSBarry Smith     ierr = ISDestroy(&ispart);CHKERRQ(ierr);
1302b1a0a8a3SJed Brown   }
1303b1a0a8a3SJed Brown 
1304b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1305b1a0a8a3SJed Brown }
1306b1a0a8a3SJed Brown 
1307b1a0a8a3SJed Brown #undef __FUNCT__
1308f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMDestroySubdomains"
1309b1a0a8a3SJed Brown /*@C
1310f746d493SDmitry Karpeev    PCGASMDestroySubdomains - Destroys the index sets created with
1311f746d493SDmitry Karpeev    PCGASMCreateSubdomains(). Should be called after setting subdomains
1312f746d493SDmitry Karpeev    with PCGASMSetLocalSubdomains().
1313b1a0a8a3SJed Brown 
1314b1a0a8a3SJed Brown    Collective
1315b1a0a8a3SJed Brown 
1316b1a0a8a3SJed Brown    Input Parameters:
1317b1a0a8a3SJed Brown +  n - the number of index sets
1318b1a0a8a3SJed Brown .  is - the array of index sets
1319b1a0a8a3SJed Brown -  is_local - the array of local index sets, can be PETSC_NULL
1320b1a0a8a3SJed Brown 
1321b1a0a8a3SJed Brown    Level: advanced
1322b1a0a8a3SJed Brown 
1323f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1324b1a0a8a3SJed Brown 
1325f746d493SDmitry Karpeev .seealso: PCGASMCreateSubdomains(), PCGASMSetLocalSubdomains()
1326b1a0a8a3SJed Brown @*/
13277087cfbeSBarry Smith PetscErrorCode  PCGASMDestroySubdomains(PetscInt n, IS is[], IS is_local[])
1328b1a0a8a3SJed Brown {
1329b1a0a8a3SJed Brown   PetscInt       i;
1330b1a0a8a3SJed Brown   PetscErrorCode ierr;
1331b1a0a8a3SJed Brown   PetscFunctionBegin;
1332b1a0a8a3SJed Brown   if (n <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n must be > 0: n = %D",n);
1333b1a0a8a3SJed Brown   PetscValidPointer(is,2);
1334fcfd50ebSBarry Smith   for (i=0; i<n; i++) { ierr = ISDestroy(&is[i]);CHKERRQ(ierr); }
1335b1a0a8a3SJed Brown   ierr = PetscFree(is);CHKERRQ(ierr);
1336b1a0a8a3SJed Brown   if (is_local) {
1337b1a0a8a3SJed Brown     PetscValidPointer(is_local,3);
1338fcfd50ebSBarry Smith     for (i=0; i<n; i++) { ierr = ISDestroy(&is_local[i]);CHKERRQ(ierr); }
1339b1a0a8a3SJed Brown     ierr = PetscFree(is_local);CHKERRQ(ierr);
1340b1a0a8a3SJed Brown   }
1341b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1342b1a0a8a3SJed Brown }
1343b1a0a8a3SJed Brown 
1344af538404SDmitry Karpeev 
1345af538404SDmitry Karpeev #define PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,xleft_loc,ylow_loc,xright_loc,yhigh_loc,n) \
1346af538404SDmitry Karpeev {                                                                                                       \
1347af538404SDmitry Karpeev  PetscInt first_row = first/M, last_row = last/M+1;                                                     \
1348af538404SDmitry Karpeev   /*                                                                                                    \
1349af538404SDmitry Karpeev    Compute ylow_loc and yhigh_loc so that (ylow_loc,xleft) and (yhigh_loc,xright) are the corners       \
1350af538404SDmitry Karpeev    of the bounding box of the intersection of the subdomain with the local ownership range (local       \
1351af538404SDmitry Karpeev    subdomain).                                                                                          \
1352af538404SDmitry Karpeev    Also compute xleft_loc and xright_loc as the lower and upper bounds on the first and last rows       \
1353af538404SDmitry Karpeev    of the intersection.                                                                                 \
1354af538404SDmitry Karpeev   */                                                                                                    \
1355af538404SDmitry Karpeev   /* ylow_loc is the grid row containing the first element of the local sumbdomain */                   \
1356eec7e3faSDmitry Karpeev   *ylow_loc = PetscMax(first_row,ylow);                                                                    \
1357af538404SDmitry Karpeev   /* xleft_loc is the offset of first element of the local subdomain within its grid row (might actually be outside the local subdomain) */ \
1358eec7e3faSDmitry Karpeev   *xleft_loc = *ylow_loc==first_row?PetscMax(first%M,xleft):xleft;                                                                            \
1359af538404SDmitry Karpeev   /* yhigh_loc is the grid row above the last local subdomain element */                                                                    \
1360eec7e3faSDmitry Karpeev   *yhigh_loc = PetscMin(last_row,yhigh);                                                                                                     \
1361af538404SDmitry Karpeev   /* xright is the offset of the end of the  local subdomain within its grid row (might actually be outside the local subdomain) */         \
1362eec7e3faSDmitry Karpeev   *xright_loc = *yhigh_loc==last_row?PetscMin(xright,last%M):xright;                                                                          \
1363af538404SDmitry Karpeev   /* Now compute the size of the local subdomain n. */ \
1364c3518bceSDmitry Karpeev   *n = 0;                                               \
1365eec7e3faSDmitry Karpeev   if(*ylow_loc < *yhigh_loc) {                           \
1366af538404SDmitry Karpeev     PetscInt width = xright-xleft;                     \
1367eec7e3faSDmitry Karpeev     *n += width*(*yhigh_loc-*ylow_loc-1);                 \
1368eec7e3faSDmitry Karpeev     *n += PetscMin(PetscMax(*xright_loc-xleft,0),width); \
1369eec7e3faSDmitry Karpeev     *n -= PetscMin(PetscMax(*xleft_loc-xleft,0), width); \
1370af538404SDmitry Karpeev   }\
1371af538404SDmitry Karpeev }
1372af538404SDmitry Karpeev 
1373c3518bceSDmitry Karpeev 
1374eec7e3faSDmitry Karpeev 
1375eec7e3faSDmitry Karpeev #undef __FUNCT__
1376f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains2D"
1377b1a0a8a3SJed Brown /*@
1378f746d493SDmitry Karpeev    PCGASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz
1379b1a0a8a3SJed Brown    preconditioner for a two-dimensional problem on a regular grid.
1380b1a0a8a3SJed Brown 
1381af538404SDmitry Karpeev    Collective
1382b1a0a8a3SJed Brown 
1383b1a0a8a3SJed Brown    Input Parameters:
1384af538404SDmitry Karpeev +  M, N - the global number of mesh points in the x and y directions
1385af538404SDmitry Karpeev .  Mdomains, Ndomains - the global number of subdomains in the x and y directions
1386b1a0a8a3SJed Brown .  dof - degrees of freedom per node
1387b1a0a8a3SJed Brown -  overlap - overlap in mesh lines
1388b1a0a8a3SJed Brown 
1389b1a0a8a3SJed Brown    Output Parameters:
1390af538404SDmitry Karpeev +  Nsub - the number of local subdomains created
1391b1a0a8a3SJed Brown .  is - array of index sets defining overlapping (if overlap > 0) subdomains
1392b1a0a8a3SJed Brown -  is_local - array of index sets defining non-overlapping subdomains
1393b1a0a8a3SJed Brown 
1394b1a0a8a3SJed Brown    Note:
1395b1a0a8a3SJed Brown    Presently PCAMSCreateSubdomains2d() is valid only for sequential
1396b1a0a8a3SJed Brown    preconditioners.  More general related routines are
1397f746d493SDmitry Karpeev    PCGASMSetTotalSubdomains() and PCGASMSetLocalSubdomains().
1398b1a0a8a3SJed Brown 
1399b1a0a8a3SJed Brown    Level: advanced
1400b1a0a8a3SJed Brown 
1401f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, 2D, regular grid
1402b1a0a8a3SJed Brown 
1403f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
1404f746d493SDmitry Karpeev           PCGASMSetOverlap()
1405b1a0a8a3SJed Brown @*/
14067087cfbeSBarry Smith PetscErrorCode  PCGASMCreateSubdomains2D(PC pc, PetscInt M,PetscInt N,PetscInt Mdomains,PetscInt Ndomains,PetscInt dof,PetscInt overlap, PetscInt *nsub,IS **is,IS **is_local)
1407b1a0a8a3SJed Brown {
1408b1a0a8a3SJed Brown   PetscErrorCode ierr;
14092bbb417fSDmitry Karpeev   PetscMPIInt    size, rank;
14102bbb417fSDmitry Karpeev   PetscInt       i, j;
14112bbb417fSDmitry Karpeev   PetscInt       maxheight, maxwidth;
14122bbb417fSDmitry Karpeev   PetscInt       xstart, xleft, xright, xleft_loc, xright_loc;
14132bbb417fSDmitry Karpeev   PetscInt       ystart, ylow,  yhigh,  ylow_loc,  yhigh_loc;
1414eec7e3faSDmitry Karpeev   PetscInt       x[2][2], y[2][2], n[2];
14152bbb417fSDmitry Karpeev   PetscInt       first, last;
14162bbb417fSDmitry Karpeev   PetscInt       nidx, *idx;
14172bbb417fSDmitry Karpeev   PetscInt       ii,jj,s,q,d;
1418af538404SDmitry Karpeev   PetscInt       k,kk;
14192bbb417fSDmitry Karpeev   PetscMPIInt    color;
14202bbb417fSDmitry Karpeev   MPI_Comm       comm, subcomm;
14215d38c402SBarry Smith   IS             **iis = 0;
1422d34fcf5fSBarry Smith 
1423b1a0a8a3SJed Brown   PetscFunctionBegin;
14242bbb417fSDmitry Karpeev   ierr = PetscObjectGetComm((PetscObject)pc, &comm);CHKERRQ(ierr);
14252bbb417fSDmitry Karpeev   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
14262bbb417fSDmitry Karpeev   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
14272bbb417fSDmitry Karpeev   ierr = MatGetOwnershipRange(pc->pmat, &first, &last);CHKERRQ(ierr);
1428d34fcf5fSBarry Smith   if (first%dof || last%dof) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Matrix row partitioning unsuitable for domain decomposition: local row range (%D,%D) "
14292bbb417fSDmitry Karpeev 	     "does not respect the number of degrees of freedom per grid point %D", first, last, dof);
1430d34fcf5fSBarry Smith 
1431af538404SDmitry Karpeev   /* Determine the number of domains with nonzero intersections with the local ownership range. */
14322bbb417fSDmitry Karpeev   s = 0;
1433af538404SDmitry Karpeev   ystart = 0;
1434af538404SDmitry Karpeev   for (j=0; j<Ndomains; ++j) {
1435af538404SDmitry Karpeev     maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */
1436af538404SDmitry 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);
1437eec7e3faSDmitry Karpeev     /* Vertical domain limits with an overlap. */
1438eec7e3faSDmitry Karpeev     ylow = PetscMax(ystart - overlap,0);
1439eec7e3faSDmitry Karpeev     yhigh = PetscMin(ystart + maxheight + overlap,N);
1440b1a0a8a3SJed Brown     xstart = 0;
1441af538404SDmitry Karpeev     for (i=0; i<Mdomains; ++i) {
1442af538404SDmitry Karpeev       maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */
1443af538404SDmitry 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);
1444eec7e3faSDmitry Karpeev       /* Horizontal domain limits with an overlap. */
1445eec7e3faSDmitry Karpeev       xleft   = PetscMax(xstart - overlap,0);
1446eec7e3faSDmitry Karpeev       xright  = PetscMin(xstart + maxwidth + overlap,M);
1447af538404SDmitry Karpeev       /*
1448af538404SDmitry Karpeev 	 Determine whether this subdomain intersects this processor's ownership range of pc->pmat.
1449af538404SDmitry Karpeev       */
1450c3518bceSDmitry Karpeev       PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx));
1451af538404SDmitry Karpeev       if(nidx) {
1452af538404SDmitry Karpeev         ++s;
1453af538404SDmitry Karpeev       }
1454af538404SDmitry Karpeev       xstart += maxwidth;
1455af538404SDmitry Karpeev     }/* for(i = 0; i < Mdomains; ++i) */
1456af538404SDmitry Karpeev     ystart += maxheight;
1457af538404SDmitry Karpeev   }/* for(j = 0; j < Ndomains; ++j) */
1458af538404SDmitry Karpeev   /* Now we can allocate the necessary number of ISs. */
1459af538404SDmitry Karpeev   *nsub = s;
1460af538404SDmitry Karpeev   ierr = PetscMalloc((*nsub)*sizeof(IS*),is);CHKERRQ(ierr);
1461af538404SDmitry Karpeev   ierr = PetscMalloc((*nsub)*sizeof(IS*),is_local);CHKERRQ(ierr);
1462af538404SDmitry Karpeev   s = 0;
1463af538404SDmitry Karpeev   ystart = 0;
1464af538404SDmitry Karpeev   for (j=0; j<Ndomains; ++j) {
1465af538404SDmitry Karpeev     maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */
1466af538404SDmitry 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);
1467af538404SDmitry Karpeev     /* Vertical domain limits with an overlap. */
1468eec7e3faSDmitry Karpeev     y[0][0] = PetscMax(ystart - overlap,0);
1469eec7e3faSDmitry Karpeev     y[0][1] = PetscMin(ystart + maxheight + overlap,N);
1470eec7e3faSDmitry Karpeev     /* Vertical domain limits without an overlap. */
1471eec7e3faSDmitry Karpeev     y[1][0] = ystart;
1472eec7e3faSDmitry Karpeev     y[1][1] = PetscMin(ystart + maxheight,N);
1473eec7e3faSDmitry Karpeev     xstart = 0;
1474af538404SDmitry Karpeev     for (i=0; i<Mdomains; ++i) {
1475af538404SDmitry Karpeev       maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */
1476af538404SDmitry 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);
1477af538404SDmitry Karpeev       /* Horizontal domain limits with an overlap. */
1478eec7e3faSDmitry Karpeev       x[0][0]  = PetscMax(xstart - overlap,0);
1479eec7e3faSDmitry Karpeev       x[0][1]  = PetscMin(xstart + maxwidth + overlap,M);
1480eec7e3faSDmitry Karpeev       /* Horizontal domain limits without an overlap. */
1481eec7e3faSDmitry Karpeev       x[1][0] = xstart;
1482eec7e3faSDmitry Karpeev       x[1][1] = PetscMin(xstart+maxwidth,M);
14832bbb417fSDmitry Karpeev       /*
14842bbb417fSDmitry Karpeev 	 Determine whether this domain intersects this processor's ownership range of pc->pmat.
14852bbb417fSDmitry Karpeev 	 Do this twice: first for the domains with overlaps, and once without.
14862bbb417fSDmitry Karpeev 	 During the first pass create the subcommunicators, and use them on the second pass as well.
14872bbb417fSDmitry Karpeev       */
14882bbb417fSDmitry Karpeev       for(q = 0; q < 2; ++q) {
14892bbb417fSDmitry Karpeev 	/*
14902bbb417fSDmitry Karpeev 	  domain limits, (xleft, xright) and (ylow, yheigh) are adjusted
14912bbb417fSDmitry Karpeev 	  according to whether the domain with an overlap or without is considered.
14922bbb417fSDmitry Karpeev 	*/
14932bbb417fSDmitry Karpeev 	xleft = x[q][0]; xright = x[q][1];
14942bbb417fSDmitry Karpeev 	ylow  = y[q][0]; yhigh  = y[q][1];
1495c3518bceSDmitry Karpeev         PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx));
1496af538404SDmitry Karpeev 	nidx *= dof;
1497eec7e3faSDmitry Karpeev         n[q] = nidx;
14982bbb417fSDmitry Karpeev         /*
1499eec7e3faSDmitry Karpeev          Based on the counted number of indices in the local domain *with an overlap*,
1500af538404SDmitry Karpeev          construct a subcommunicator of all the processors supporting this domain.
1501eec7e3faSDmitry Karpeev          Observe that a domain with an overlap might have nontrivial local support,
1502eec7e3faSDmitry Karpeev          while the domain without an overlap might not.  Hence, the decision to participate
1503eec7e3faSDmitry Karpeev          in the subcommunicator must be based on the domain with an overlap.
15042bbb417fSDmitry Karpeev          */
15052bbb417fSDmitry Karpeev 	if (q == 0) {
15062bbb417fSDmitry Karpeev 	  if(nidx) {
15072bbb417fSDmitry Karpeev 	    color = 1;
1508d34fcf5fSBarry Smith 	  } else {
15092bbb417fSDmitry Karpeev 	    color = MPI_UNDEFINED;
15102bbb417fSDmitry Karpeev 	  }
15112bbb417fSDmitry Karpeev 	  ierr = MPI_Comm_split(comm, color, rank, &subcomm);CHKERRQ(ierr);
15122bbb417fSDmitry Karpeev 	}
1513af538404SDmitry Karpeev         /*
1514eec7e3faSDmitry Karpeev          Proceed only if the number of local indices *with an overlap* is nonzero.
1515af538404SDmitry Karpeev          */
1516eec7e3faSDmitry Karpeev         if (n[0]) {
1517af538404SDmitry Karpeev           if(q == 0) {
1518eec7e3faSDmitry Karpeev             iis = is;
1519af538404SDmitry Karpeev           }
1520af538404SDmitry Karpeev           if (q == 1) {
1521af538404SDmitry Karpeev             /*
1522eec7e3faSDmitry Karpeev              The IS for the no-overlap subdomain shares a communicator with the overlapping domain.
1523af538404SDmitry Karpeev              Moreover, if the overlap is zero, the two ISs are identical.
1524af538404SDmitry Karpeev              */
1525b1a0a8a3SJed Brown             if (overlap == 0) {
1526eec7e3faSDmitry Karpeev               (*is_local)[s] = (*is)[s];
15272bbb417fSDmitry Karpeev               ierr = PetscObjectReference((PetscObject)(*is)[s]);CHKERRQ(ierr);
15282bbb417fSDmitry Karpeev               continue;
1529d34fcf5fSBarry Smith             } else {
1530eec7e3faSDmitry Karpeev               iis = is_local;
1531eec7e3faSDmitry Karpeev               subcomm = ((PetscObject)(*is)[s])->comm;
15322bbb417fSDmitry Karpeev             }
1533af538404SDmitry Karpeev           }/* if(q == 1) */
1534eec7e3faSDmitry Karpeev           idx = PETSC_NULL;
15352bbb417fSDmitry Karpeev 	  ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1536eec7e3faSDmitry Karpeev           if(nidx) {
15372bbb417fSDmitry Karpeev             k    = 0;
15382bbb417fSDmitry Karpeev             for (jj=ylow_loc; jj<yhigh_loc; ++jj) {
1539af538404SDmitry Karpeev               PetscInt x0 = (jj==ylow_loc)?xleft_loc:xleft;
1540af538404SDmitry Karpeev               PetscInt x1 = (jj==yhigh_loc-1)?xright_loc:xright;
1541af538404SDmitry Karpeev               kk = dof*(M*jj + x0);
15422bbb417fSDmitry Karpeev               for (ii=x0; ii<x1; ++ii) {
15432bbb417fSDmitry Karpeev                 for(d = 0; d < dof; ++d) {
15442bbb417fSDmitry Karpeev                   idx[k++] = kk++;
1545b1a0a8a3SJed Brown                 }
1546b1a0a8a3SJed Brown               }
1547b1a0a8a3SJed Brown             }
1548eec7e3faSDmitry Karpeev           }
15492bbb417fSDmitry Karpeev 	  ierr = ISCreateGeneral(subcomm,nidx,idx,PETSC_OWN_POINTER,(*iis)+s);CHKERRQ(ierr);
1550eec7e3faSDmitry Karpeev 	}/* if(n[0]) */
15512bbb417fSDmitry Karpeev       }/* for(q = 0; q < 2; ++q) */
1552eec7e3faSDmitry Karpeev       if(n[0]) {
15532bbb417fSDmitry Karpeev         ++s;
1554b1a0a8a3SJed Brown       }
1555af538404SDmitry Karpeev       xstart += maxwidth;
1556af538404SDmitry Karpeev     }/* for(i = 0; i < Mdomains; ++i) */
15572bbb417fSDmitry Karpeev     ystart += maxheight;
1558af538404SDmitry Karpeev   }/* for(j = 0; j < Ndomains; ++j) */
1559b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1560b1a0a8a3SJed Brown }
1561b1a0a8a3SJed Brown 
1562b1a0a8a3SJed Brown #undef __FUNCT__
1563f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubdomains"
1564b1a0a8a3SJed Brown /*@C
1565f746d493SDmitry Karpeev     PCGASMGetLocalSubdomains - Gets the local subdomains (for this processor
1566b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1567b1a0a8a3SJed Brown 
1568b1a0a8a3SJed Brown     Not Collective
1569b1a0a8a3SJed Brown 
1570b1a0a8a3SJed Brown     Input Parameter:
1571b1a0a8a3SJed Brown .   pc - the preconditioner context
1572b1a0a8a3SJed Brown 
1573b1a0a8a3SJed Brown     Output Parameters:
1574b1a0a8a3SJed Brown +   n - the number of subdomains for this processor (default value = 1)
1575b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for this processor
1576b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor (can be PETSC_NULL)
1577b1a0a8a3SJed Brown 
1578b1a0a8a3SJed Brown 
1579b1a0a8a3SJed Brown     Notes:
1580b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
1581b1a0a8a3SJed Brown 
1582b1a0a8a3SJed Brown     Level: advanced
1583b1a0a8a3SJed Brown 
1584f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
1585b1a0a8a3SJed Brown 
1586f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1587f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubmatrices()
1588b1a0a8a3SJed Brown @*/
15897087cfbeSBarry Smith PetscErrorCode  PCGASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[])
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 (is) PetscValidPointer(is,3);
1599f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1600b1a0a8a3SJed Brown   if (!match) {
1601b1a0a8a3SJed Brown     if (n)  *n  = 0;
1602b1a0a8a3SJed Brown     if (is) *is = PETSC_NULL;
1603b1a0a8a3SJed Brown   } else {
1604f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1605ab3e923fSDmitry Karpeev     if (n)  *n  = osm->n;
1606b1a0a8a3SJed Brown     if (is) *is = osm->is;
1607b1a0a8a3SJed Brown     if (is_local) *is_local = osm->is_local;
1608b1a0a8a3SJed Brown   }
1609b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1610b1a0a8a3SJed Brown }
1611b1a0a8a3SJed Brown 
1612b1a0a8a3SJed Brown #undef __FUNCT__
1613f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubmatrices"
1614b1a0a8a3SJed Brown /*@C
1615f746d493SDmitry Karpeev     PCGASMGetLocalSubmatrices - Gets the local submatrices (for this processor
1616b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1617b1a0a8a3SJed Brown 
1618b1a0a8a3SJed Brown     Not Collective
1619b1a0a8a3SJed Brown 
1620b1a0a8a3SJed Brown     Input Parameter:
1621b1a0a8a3SJed Brown .   pc - the preconditioner context
1622b1a0a8a3SJed Brown 
1623b1a0a8a3SJed Brown     Output Parameters:
1624b1a0a8a3SJed Brown +   n - the number of matrices for this processor (default value = 1)
1625b1a0a8a3SJed Brown -   mat - the matrices
1626b1a0a8a3SJed Brown 
1627b1a0a8a3SJed Brown 
1628b1a0a8a3SJed Brown     Level: advanced
1629b1a0a8a3SJed Brown 
1630f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz, block Jacobi
1631b1a0a8a3SJed Brown 
1632f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1633f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubdomains()
1634b1a0a8a3SJed Brown @*/
16357087cfbeSBarry Smith PetscErrorCode  PCGASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[])
1636b1a0a8a3SJed Brown {
1637f746d493SDmitry Karpeev   PC_GASM         *osm;
1638b1a0a8a3SJed Brown   PetscErrorCode ierr;
1639b1a0a8a3SJed Brown   PetscBool      match;
1640b1a0a8a3SJed Brown 
1641b1a0a8a3SJed Brown   PetscFunctionBegin;
1642b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1643b1a0a8a3SJed Brown   PetscValidIntPointer(n,2);
1644b1a0a8a3SJed Brown   if (mat) PetscValidPointer(mat,3);
1645b1a0a8a3SJed Brown   if (!pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp().");
1646f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1647b1a0a8a3SJed Brown   if (!match) {
1648b1a0a8a3SJed Brown     if (n)   *n   = 0;
1649b1a0a8a3SJed Brown     if (mat) *mat = PETSC_NULL;
1650b1a0a8a3SJed Brown   } else {
1651f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1652ab3e923fSDmitry Karpeev     if (n)   *n   = osm->n;
1653b1a0a8a3SJed Brown     if (mat) *mat = osm->pmat;
1654b1a0a8a3SJed Brown   }
1655b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1656b1a0a8a3SJed Brown }
1657