xref: /petsc/src/ksp/pc/impls/gasm/gasm.c (revision 69ca1f377ea5cc0030436e04084fc84669aee34d)
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;
213fdc48646SDmitry 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 
225*69ca1f37SDmitry Karpeev     /* Note: if osm->n has been set, it is at least 1. */
22644fe18e5SDmitry Karpeev     if (osm->N == PETSC_DECIDE && osm->n < 1) {
227*69ca1f37SDmitry Karpeev       /* no subdomains given */
228*69ca1f37SDmitry Karpeev       /* try pc->dm first */
229fdc48646SDmitry Karpeev       if(pc->dm) {
230fdc48646SDmitry Karpeev         char      ddm_name[1024];
231fdc48646SDmitry Karpeev         DM        ddm;
232fdc48646SDmitry Karpeev         PetscBool flg;
233fdc48646SDmitry Karpeev         PetscInt     num_domains, d;
234fdc48646SDmitry Karpeev         char         **domain_names;
235fdc48646SDmitry Karpeev         IS           *domain_is;
236fdc48646SDmitry Karpeev         /* Allow the user to request a decomposition DM by name */
237fdc48646SDmitry Karpeev         ierr = PetscStrncpy(ddm_name, "", 1024); CHKERRQ(ierr);
238fdc48646SDmitry Karpeev         ierr = PetscOptionsString("-pc_asm_decomposition_dm", "Name of the DM defining the composition", "PCSetDM", ddm_name, ddm_name,1024,&flg); CHKERRQ(ierr);
239fdc48646SDmitry Karpeev         if(flg) {
240fdc48646SDmitry Karpeev           ierr = DMCreateDecompositionDM(pc->dm, ddm_name, &ddm); CHKERRQ(ierr);
241fdc48646SDmitry Karpeev           if(!ddm) {
242fdc48646SDmitry Karpeev             SETERRQ1(((PetscObject)pc)->comm, PETSC_ERR_ARG_WRONGSTATE, "Uknown DM decomposition name %s", ddm_name);
243fdc48646SDmitry Karpeev           }
244fdc48646SDmitry Karpeev           ierr = PetscInfo(pc,"Using decomposition DM defined using options database\n");CHKERRQ(ierr);
245fdc48646SDmitry Karpeev           ierr = PCSetDM(pc,ddm); CHKERRQ(ierr);
246fdc48646SDmitry Karpeev         }
247fdc48646SDmitry Karpeev         ierr = DMCreateDecomposition(pc->dm, &num_domains, &domain_names, &domain_is, &domain_dm);    CHKERRQ(ierr);
248*69ca1f37SDmitry Karpeev         if(num_domains) {
249fdc48646SDmitry Karpeev           ierr = PCGASMSetLocalSubdomains(pc, num_domains, domain_is, PETSC_NULL);CHKERRQ(ierr);
250*69ca1f37SDmitry Karpeev         }
251fdc48646SDmitry Karpeev         for(d = 0; d < num_domains; ++d) {
252fdc48646SDmitry Karpeev           ierr = PetscFree(domain_names[d]); CHKERRQ(ierr);
253fdc48646SDmitry Karpeev           ierr = ISDestroy(&domain_is[d]);   CHKERRQ(ierr);
254fdc48646SDmitry Karpeev         }
255fdc48646SDmitry Karpeev         ierr = PetscFree(domain_names);CHKERRQ(ierr);
256fdc48646SDmitry Karpeev         ierr = PetscFree(domain_is);CHKERRQ(ierr);
257fdc48646SDmitry Karpeev       }
258*69ca1f37SDmitry Karpeev       if (osm->N == PETSC_DECIDE && osm->n < 1) { /* still no subdomains; use one per processor */
25944fe18e5SDmitry Karpeev         osm->nmax = osm->n = 1;
260b1a0a8a3SJed Brown         ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
261f746d493SDmitry Karpeev         osm->N = size;
262fdc48646SDmitry Karpeev       }
263f746d493SDmitry Karpeev     } else if (osm->N == PETSC_DECIDE) {
264b1a0a8a3SJed Brown       PetscInt inwork[2], outwork[2];
265f746d493SDmitry Karpeev       /* determine global number of subdomains and the max number of local subdomains */
266f746d493SDmitry Karpeev       inwork[0] = inwork[1] = osm->n;
267b1a0a8a3SJed Brown       ierr = MPI_Allreduce(inwork,outwork,1,MPIU_2INT,PetscMaxSum_Op,((PetscObject)pc)->comm);CHKERRQ(ierr);
268f746d493SDmitry Karpeev       osm->nmax = outwork[0];
269f746d493SDmitry Karpeev       osm->N    = outwork[1];
270b1a0a8a3SJed Brown     }
271b1a0a8a3SJed Brown     if (!osm->is){ /* create the index sets */
272f746d493SDmitry Karpeev       ierr = PCGASMCreateSubdomains(pc->pmat,osm->n,&osm->is);CHKERRQ(ierr);
273b1a0a8a3SJed Brown     }
27493c1ec32SDmitry Karpeev     if (!osm->is_local) {
27593c1ec32SDmitry Karpeev       /*
27693c1ec32SDmitry Karpeev 	 This indicates that osm->is should define a nonoverlapping decomposition
27793c1ec32SDmitry Karpeev 	 (there is no way to really guarantee that if subdomains are set by the user through PCGASMSetLocalSubdomains,
27893c1ec32SDmitry Karpeev 	  but the assumption is that either the user does the right thing, or subdomains in ossm->is have been created
27993c1ec32SDmitry Karpeev 	  via PCGASMCreateSubdomains, which guarantees a nonoverlapping decomposition).
28093c1ec32SDmitry Karpeev 	 Therefore, osm->is will be used to define osm->is_local.
28193c1ec32SDmitry Karpeev 	 If a nonzero overlap has been requested by the user, then osm->is will be expanded and will overlap,
28293c1ec32SDmitry Karpeev 	 so osm->is_local should obtain a copy of osm->is while they are still (presumably) nonoverlapping.
28393c1ec32SDmitry Karpeev 	 Otherwise (no overlap has been requested), osm->is_local are simply aliases for osm->is.
28493c1ec32SDmitry Karpeev       */
285f746d493SDmitry Karpeev       ierr = PetscMalloc(osm->n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
286f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
287b1a0a8a3SJed Brown         if (osm->overlap > 0) { /* With positive overlap, osm->is[i] will be modified */
288b1a0a8a3SJed Brown           ierr = ISDuplicate(osm->is[i],&osm->is_local[i]);CHKERRQ(ierr);
289b1a0a8a3SJed Brown           ierr = ISCopy(osm->is[i],osm->is_local[i]);CHKERRQ(ierr);
290b1a0a8a3SJed Brown         } else {
291b1a0a8a3SJed Brown           ierr = PetscObjectReference((PetscObject)osm->is[i]);CHKERRQ(ierr);
292b1a0a8a3SJed Brown           osm->is_local[i] = osm->is[i];
293b1a0a8a3SJed Brown         }
294b1a0a8a3SJed Brown       }
295b1a0a8a3SJed Brown     }
29693c1ec32SDmitry Karpeev     /* Beyond this point osm->is_local is not null. */
29793c1ec32SDmitry Karpeev     if (osm->overlap > 0) {
29893c1ec32SDmitry Karpeev       /* Extend the "overlapping" regions by a number of steps */
29993c1ec32SDmitry Karpeev       ierr = MatIncreaseOverlap(pc->pmat,osm->n,osm->is,osm->overlap);CHKERRQ(ierr);
30093c1ec32SDmitry Karpeev     }
301b1a0a8a3SJed Brown     ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
302b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
303f746d493SDmitry Karpeev     ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&flg,PETSC_NULL);CHKERRQ(ierr);
304f746d493SDmitry Karpeev     if (flg) { ierr = PCGASMPrintSubdomains(pc);CHKERRQ(ierr); }
305b1a0a8a3SJed Brown 
306b1a0a8a3SJed Brown     if (osm->sort_indices) {
307f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
308b1a0a8a3SJed Brown         ierr = ISSort(osm->is[i]);CHKERRQ(ierr);
309b1a0a8a3SJed Brown 	ierr = ISSort(osm->is_local[i]);CHKERRQ(ierr);
310b1a0a8a3SJed Brown       }
311b1a0a8a3SJed Brown     }
312f746d493SDmitry Karpeev     /* Merge the ISs, create merged vectors and scatter contexts. */
31393c1ec32SDmitry Karpeev     /* Restriction ISs. */
314f746d493SDmitry Karpeev     ddn = 0;
315f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
316f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
317f746d493SDmitry Karpeev       ddn += dn;
318f746d493SDmitry Karpeev     }
319f746d493SDmitry Karpeev     ierr = PetscMalloc(ddn*sizeof(PetscInt), &ddidx);CHKERRQ(ierr);
320f746d493SDmitry Karpeev     ddn = 0;
321f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
322f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
323f746d493SDmitry Karpeev       ierr = ISGetIndices(osm->is[i],&didx);CHKERRQ(ierr);
324f746d493SDmitry Karpeev       ierr = PetscMemcpy(ddidx+ddn, didx, sizeof(PetscInt)*dn);CHKERRQ(ierr);
325f746d493SDmitry Karpeev       ierr = ISRestoreIndices(osm->is[i], &didx);CHKERRQ(ierr);
32693c1ec32SDmitry Karpeev       ddn += dn;
327f746d493SDmitry Karpeev     }
328f746d493SDmitry Karpeev     ierr = ISCreateGeneral(((PetscObject)(pc))->comm, ddn, ddidx, PETSC_OWN_POINTER, &osm->gis);CHKERRQ(ierr);
329f746d493SDmitry Karpeev     ierr = MatGetVecs(pc->pmat,&x,&y);CHKERRQ(ierr);
330f746d493SDmitry Karpeev     ierr = VecCreateMPI(((PetscObject)pc)->comm, ddn, PETSC_DECIDE, &osm->gx);CHKERRQ(ierr);
331f746d493SDmitry Karpeev     ierr = VecDuplicate(osm->gx,&osm->gy);CHKERRQ(ierr);
3326d98aee9SDmitry Karpeev     ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast);CHKERRQ(ierr);
3336d98aee9SDmitry Karpeev     ierr = ISCreateStride(((PetscObject)pc)->comm,ddn,gfirst,1, &gid);CHKERRQ(ierr);
334f746d493SDmitry Karpeev     ierr = VecScatterCreate(x,osm->gis,osm->gx,gid, &(osm->grestriction));CHKERRQ(ierr);
335fcfd50ebSBarry Smith     ierr = ISDestroy(&gid);CHKERRQ(ierr);
33693c1ec32SDmitry Karpeev     /* Prolongation ISs */
33781a5c4aaSDmitry Karpeev     { PetscInt       dn_local;       /* Number of indices in the local part of a single domain assigned to this processor. */
338f746d493SDmitry Karpeev       const PetscInt *didx_local;    /* Global indices from the local part of a single domain assigned to this processor. */
339f746d493SDmitry Karpeev       PetscInt       ddn_local;      /* Number of indices in the local part of the disjoint union all domains assigned to this processor. */
340f746d493SDmitry Karpeev       PetscInt       *ddidx_local;   /* Global indices of the local part of the disjoint union of all domains assigned to this processor. */
341f746d493SDmitry Karpeev       /**/
34293c1ec32SDmitry Karpeev       ISLocalToGlobalMapping ltog;          /* Map from global to local indices on the disjoint union of subdomains: "local" ind's run from 0 to ddn-1. */
34393c1ec32SDmitry Karpeev       PetscInt              *ddidx_llocal;  /* Mapped local indices of the disjoint union of local parts of subdomains. */
344f746d493SDmitry 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. */
345f746d493SDmitry Karpeev       IS                     gis_llocal;    /* IS with ddidx_llocal indices. */
346f746d493SDmitry Karpeev       PetscInt               j;
347f746d493SDmitry Karpeev       ddn_local = 0;
348f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
349f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local);CHKERRQ(ierr);
350f746d493SDmitry Karpeev 	ddn_local += dn_local;
351f746d493SDmitry Karpeev       }
352f746d493SDmitry Karpeev       ierr = PetscMalloc(ddn_local*sizeof(PetscInt), &ddidx_local);CHKERRQ(ierr);
353f746d493SDmitry Karpeev       ddn_local = 0;
354f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
355f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local);CHKERRQ(ierr);
356f746d493SDmitry Karpeev 	ierr = ISGetIndices(osm->is_local[i],&didx_local);CHKERRQ(ierr);
357f746d493SDmitry Karpeev 	ierr = PetscMemcpy(ddidx_local+ddn_local, didx_local, sizeof(PetscInt)*dn_local);CHKERRQ(ierr);
358f746d493SDmitry Karpeev 	ierr = ISRestoreIndices(osm->is_local[i], &didx_local);CHKERRQ(ierr);
359f746d493SDmitry Karpeev 	ddn_local += dn_local;
360f746d493SDmitry Karpeev       }
361ab3e923fSDmitry Karpeev       ierr = PetscMalloc(sizeof(PetscInt)*ddn_local, &ddidx_llocal);CHKERRQ(ierr);
362f746d493SDmitry Karpeev       ierr = ISCreateGeneral(((PetscObject)pc)->comm, ddn_local, ddidx_local, PETSC_OWN_POINTER, &(osm->gis_local));CHKERRQ(ierr);
363f746d493SDmitry Karpeev       ierr = ISLocalToGlobalMappingCreateIS(osm->gis,&ltog);CHKERRQ(ierr);
36481a5c4aaSDmitry Karpeev       ierr = ISGlobalToLocalMappingApply(ltog,IS_GTOLM_DROP,ddn_local,ddidx_local,&ddn_llocal,ddidx_llocal);CHKERRQ(ierr);
3656bf464f9SBarry Smith       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
36693c1ec32SDmitry 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);
367f746d493SDmitry Karpeev       /* Now convert these localized indices into the global indices into the merged output vector. */
3686d98aee9SDmitry Karpeev       ierr = VecGetOwnershipRange(osm->gy, &gfirst, &glast);CHKERRQ(ierr);
369f746d493SDmitry Karpeev       for(j=0; j < ddn_llocal; ++j) {
3706d98aee9SDmitry Karpeev 	ddidx_llocal[j] += gfirst;
371f746d493SDmitry Karpeev       }
372f746d493SDmitry Karpeev       ierr = ISCreateGeneral(PETSC_COMM_SELF,ddn_llocal,ddidx_llocal,PETSC_OWN_POINTER,&gis_llocal);CHKERRQ(ierr);
373f746d493SDmitry Karpeev       ierr = VecScatterCreate(y,osm->gis_local,osm->gy,gis_llocal,&osm->gprolongation);CHKERRQ(ierr);
374fcfd50ebSBarry Smith       ierr = ISDestroy(&gis_llocal);CHKERRQ(ierr);
375b1a0a8a3SJed Brown     }
376f746d493SDmitry Karpeev     /* Create the subdomain work vectors. */
377f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->x);CHKERRQ(ierr);
378f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->y);CHKERRQ(ierr);
3796d98aee9SDmitry Karpeev     ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast);CHKERRQ(ierr);
380f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gx, &gxarray);CHKERRQ(ierr);
381f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gy, &gyarray);CHKERRQ(ierr);
382f746d493SDmitry Karpeev     for (i=0, ddn=0; i<osm->n; ++i, ddn += dn) {
38386b96d36SDmitry Karpeev       PetscInt dN;
384f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
38586b96d36SDmitry Karpeev       ierr = ISGetSize(osm->is[i],&dN);CHKERRQ(ierr);
38686b96d36SDmitry Karpeev       ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gxarray+ddn,&osm->x[i]);CHKERRQ(ierr);
38786b96d36SDmitry Karpeev       ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gyarray+ddn,&osm->y[i]);CHKERRQ(ierr);
388b1a0a8a3SJed Brown     }
389f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gx, &gxarray);CHKERRQ(ierr);
390f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gy, &gyarray);CHKERRQ(ierr);
3916bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
3926bf464f9SBarry Smith     ierr = VecDestroy(&y);CHKERRQ(ierr);
393b1a0a8a3SJed Brown     /* Create the local solvers */
394f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(KSP *),&osm->ksp);CHKERRQ(ierr);
39544fe18e5SDmitry Karpeev     for (i=0; i<osm->n; i++) { /* KSPs are local */
39686b96d36SDmitry Karpeev       ierr = KSPCreate(((PetscObject)(osm->is[i]))->comm,&ksp);CHKERRQ(ierr);
397b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,ksp);CHKERRQ(ierr);
398b1a0a8a3SJed Brown       ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1);CHKERRQ(ierr);
399b1a0a8a3SJed Brown       ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr);
400b1a0a8a3SJed Brown       ierr = KSPGetPC(ksp,&subpc);CHKERRQ(ierr);
401b1a0a8a3SJed Brown       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
402b1a0a8a3SJed Brown       ierr = KSPSetOptionsPrefix(ksp,prefix);CHKERRQ(ierr);
403b1a0a8a3SJed Brown       ierr = KSPAppendOptionsPrefix(ksp,"sub_");CHKERRQ(ierr);
404b1a0a8a3SJed Brown       osm->ksp[i] = ksp;
405b1a0a8a3SJed Brown     }
406b1a0a8a3SJed Brown     scall = MAT_INITIAL_MATRIX;
407b1a0a8a3SJed Brown 
408b1a0a8a3SJed Brown   } else {
409b1a0a8a3SJed Brown     /*
410b1a0a8a3SJed Brown        Destroy the blocks from the previous iteration
411b1a0a8a3SJed Brown     */
412b1a0a8a3SJed Brown     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
413f746d493SDmitry Karpeev       ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr);
414b1a0a8a3SJed Brown       scall = MAT_INITIAL_MATRIX;
415b1a0a8a3SJed Brown     }
416b1a0a8a3SJed Brown   }
417b1a0a8a3SJed Brown 
418b1a0a8a3SJed Brown   /*
419f746d493SDmitry Karpeev      Extract out the submatrices.
420b1a0a8a3SJed Brown   */
42181a5c4aaSDmitry Karpeev   if(size > 1) {
4226d42056aSDmitry Karpeev     ierr = MatGetSubMatricesParallel(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr);
42381a5c4aaSDmitry Karpeev   }
42481a5c4aaSDmitry Karpeev   else {
42581a5c4aaSDmitry Karpeev     ierr = MatGetSubMatrices(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr);
42681a5c4aaSDmitry Karpeev   }
427b1a0a8a3SJed Brown   if (scall == MAT_INITIAL_MATRIX) {
428b1a0a8a3SJed Brown     ierr = PetscObjectGetOptionsPrefix((PetscObject)pc->pmat,&pprefix);CHKERRQ(ierr);
429f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
430b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,osm->pmat[i]);CHKERRQ(ierr);
431b1a0a8a3SJed Brown       ierr = PetscObjectSetOptionsPrefix((PetscObject)osm->pmat[i],pprefix);CHKERRQ(ierr);
432b1a0a8a3SJed Brown     }
433b1a0a8a3SJed Brown   }
434b1a0a8a3SJed Brown 
435b1a0a8a3SJed Brown   /* Return control to the user so that the submatrices can be modified (e.g., to apply
436b1a0a8a3SJed Brown      different boundary conditions for the submatrices than for the global problem) */
437c10bc1a1SDmitry Karpeev   ierr = PCModifySubMatrices(pc,osm->n,osm->is,osm->is,osm->pmat,pc->modifysubmatricesP);CHKERRQ(ierr);
438b1a0a8a3SJed Brown 
439b1a0a8a3SJed Brown   /*
440f746d493SDmitry Karpeev      Loop over submatrices putting them into local ksp
441b1a0a8a3SJed Brown   */
442f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
443b1a0a8a3SJed Brown     ierr = KSPSetOperators(osm->ksp[i],osm->pmat[i],osm->pmat[i],pc->flag);CHKERRQ(ierr);
444b1a0a8a3SJed Brown     if (!pc->setupcalled) {
445b1a0a8a3SJed Brown       ierr = KSPSetFromOptions(osm->ksp[i]);CHKERRQ(ierr);
446b1a0a8a3SJed Brown     }
447b1a0a8a3SJed Brown   }
448b1a0a8a3SJed Brown 
449b1a0a8a3SJed Brown   PetscFunctionReturn(0);
450b1a0a8a3SJed Brown }
451b1a0a8a3SJed Brown 
452b1a0a8a3SJed Brown #undef __FUNCT__
453f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUpOnBlocks_GASM"
454f746d493SDmitry Karpeev static PetscErrorCode PCSetUpOnBlocks_GASM(PC pc)
455b1a0a8a3SJed Brown {
456f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
457b1a0a8a3SJed Brown   PetscErrorCode ierr;
458b1a0a8a3SJed Brown   PetscInt       i;
459b1a0a8a3SJed Brown 
460b1a0a8a3SJed Brown   PetscFunctionBegin;
461f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
462b1a0a8a3SJed Brown     ierr = KSPSetUp(osm->ksp[i]);CHKERRQ(ierr);
463b1a0a8a3SJed Brown   }
464b1a0a8a3SJed Brown   PetscFunctionReturn(0);
465b1a0a8a3SJed Brown }
466b1a0a8a3SJed Brown 
467b1a0a8a3SJed Brown #undef __FUNCT__
468f746d493SDmitry Karpeev #define __FUNCT__ "PCApply_GASM"
469f746d493SDmitry Karpeev static PetscErrorCode PCApply_GASM(PC pc,Vec x,Vec y)
470b1a0a8a3SJed Brown {
471f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
472b1a0a8a3SJed Brown   PetscErrorCode ierr;
473f746d493SDmitry Karpeev   PetscInt       i;
474b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
475b1a0a8a3SJed Brown 
476b1a0a8a3SJed Brown   PetscFunctionBegin;
477b1a0a8a3SJed Brown   /*
478b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
479b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
480b1a0a8a3SJed Brown   */
481f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
482b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
483b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
484f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr);
485b1a0a8a3SJed Brown   }
486f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
487b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
488b1a0a8a3SJed Brown   }
489b1a0a8a3SJed Brown 
490f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
491b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
492f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
49386b96d36SDmitry Karpeev   /* do the subdomain solves */
49486b96d36SDmitry Karpeev   for (i=0; i<osm->n; ++i) {
495b1a0a8a3SJed Brown     ierr = KSPSolve(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
496b1a0a8a3SJed Brown   }
497f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
498f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
499b1a0a8a3SJed Brown   PetscFunctionReturn(0);
500b1a0a8a3SJed Brown }
501b1a0a8a3SJed Brown 
502b1a0a8a3SJed Brown #undef __FUNCT__
503f746d493SDmitry Karpeev #define __FUNCT__ "PCApplyTranspose_GASM"
504f746d493SDmitry Karpeev static PetscErrorCode PCApplyTranspose_GASM(PC pc,Vec x,Vec y)
505b1a0a8a3SJed Brown {
506f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
507b1a0a8a3SJed Brown   PetscErrorCode ierr;
508f746d493SDmitry Karpeev   PetscInt       i;
509b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
510b1a0a8a3SJed Brown 
511b1a0a8a3SJed Brown   PetscFunctionBegin;
512b1a0a8a3SJed Brown   /*
513b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
514b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
515b1a0a8a3SJed Brown 
516f746d493SDmitry Karpeev      Note: these are reversed from the PCApply_GASM() because we are applying the
517b1a0a8a3SJed Brown      transpose of the three terms
518b1a0a8a3SJed Brown   */
519f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
520b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
521b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
522f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr);
523b1a0a8a3SJed Brown   }
524f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
525b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
526b1a0a8a3SJed Brown   }
527b1a0a8a3SJed Brown 
528ab3e923fSDmitry Karpeev   ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
529b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
530ab3e923fSDmitry Karpeev   ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
531b1a0a8a3SJed Brown   /* do the local solves */
532ab3e923fSDmitry 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. */
533b1a0a8a3SJed Brown     ierr = KSPSolveTranspose(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
534b1a0a8a3SJed Brown   }
535ab3e923fSDmitry Karpeev   ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
536ab3e923fSDmitry Karpeev   ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
537b1a0a8a3SJed Brown   PetscFunctionReturn(0);
538b1a0a8a3SJed Brown }
539b1a0a8a3SJed Brown 
540b1a0a8a3SJed Brown #undef __FUNCT__
541a06653b4SBarry Smith #define __FUNCT__ "PCReset_GASM"
542a06653b4SBarry Smith static PetscErrorCode PCReset_GASM(PC pc)
543b1a0a8a3SJed Brown {
544f746d493SDmitry Karpeev   PC_GASM        *osm = (PC_GASM*)pc->data;
545b1a0a8a3SJed Brown   PetscErrorCode ierr;
546b1a0a8a3SJed Brown   PetscInt       i;
547b1a0a8a3SJed Brown 
548b1a0a8a3SJed Brown   PetscFunctionBegin;
549b1a0a8a3SJed Brown   if (osm->ksp) {
550f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
551a06653b4SBarry Smith       ierr = KSPReset(osm->ksp[i]);CHKERRQ(ierr);
552b1a0a8a3SJed Brown     }
553b1a0a8a3SJed Brown   }
554b1a0a8a3SJed Brown   if (osm->pmat) {
555f746d493SDmitry Karpeev     if (osm->n > 0) {
556ab3e923fSDmitry Karpeev       ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr);
557b1a0a8a3SJed Brown     }
558b1a0a8a3SJed Brown   }
559d34fcf5fSBarry Smith   if (osm->x) {
560f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
561fcfd50ebSBarry Smith       ierr = VecDestroy(&osm->x[i]);CHKERRQ(ierr);
562fcfd50ebSBarry Smith       ierr = VecDestroy(&osm->y[i]);CHKERRQ(ierr);
563b1a0a8a3SJed Brown     }
564d34fcf5fSBarry Smith   }
5656bf464f9SBarry Smith   ierr = VecDestroy(&osm->gx);CHKERRQ(ierr);
5666bf464f9SBarry Smith   ierr = VecDestroy(&osm->gy);CHKERRQ(ierr);
567ab3e923fSDmitry Karpeev 
5686bf464f9SBarry Smith   ierr = VecScatterDestroy(&osm->grestriction);CHKERRQ(ierr);
5696bf464f9SBarry Smith   ierr = VecScatterDestroy(&osm->gprolongation);CHKERRQ(ierr);
570b6b0974bSDmitry Karpeev   if (osm->is) {
571b6b0974bSDmitry Karpeev     ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr);
572b6b0974bSDmitry Karpeev     osm->is = 0;
573b6b0974bSDmitry Karpeev     osm->is_local = 0;
574b6b0974bSDmitry Karpeev   }
575fcfd50ebSBarry Smith   ierr = ISDestroy(&osm->gis);CHKERRQ(ierr);
576fcfd50ebSBarry Smith   ierr = ISDestroy(&osm->gis_local);CHKERRQ(ierr);
577a06653b4SBarry Smith   PetscFunctionReturn(0);
578a06653b4SBarry Smith }
579a06653b4SBarry Smith 
580a06653b4SBarry Smith #undef __FUNCT__
581a06653b4SBarry Smith #define __FUNCT__ "PCDestroy_GASM"
582a06653b4SBarry Smith static PetscErrorCode PCDestroy_GASM(PC pc)
583a06653b4SBarry Smith {
584a06653b4SBarry Smith   PC_GASM         *osm = (PC_GASM*)pc->data;
585a06653b4SBarry Smith   PetscErrorCode ierr;
586a06653b4SBarry Smith   PetscInt       i;
587a06653b4SBarry Smith 
588a06653b4SBarry Smith   PetscFunctionBegin;
589a06653b4SBarry Smith   ierr = PCReset_GASM(pc);CHKERRQ(ierr);
590a06653b4SBarry Smith   if (osm->ksp) {
591a06653b4SBarry Smith     for (i=0; i<osm->n; i++) {
5926bf464f9SBarry Smith       ierr = KSPDestroy(&osm->ksp[i]);CHKERRQ(ierr);
593a06653b4SBarry Smith     }
594a06653b4SBarry Smith     ierr = PetscFree(osm->ksp);CHKERRQ(ierr);
595a06653b4SBarry Smith   }
596a06653b4SBarry Smith   ierr = PetscFree(osm->x);CHKERRQ(ierr);
597a06653b4SBarry Smith   ierr = PetscFree(osm->y);CHKERRQ(ierr);
598c31cb41cSBarry Smith   ierr = PetscFree(pc->data);CHKERRQ(ierr);
599b1a0a8a3SJed Brown   PetscFunctionReturn(0);
600b1a0a8a3SJed Brown }
601b1a0a8a3SJed Brown 
602b1a0a8a3SJed Brown #undef __FUNCT__
603f746d493SDmitry Karpeev #define __FUNCT__ "PCSetFromOptions_GASM"
604ab3e923fSDmitry Karpeev static PetscErrorCode PCSetFromOptions_GASM(PC pc) {
605f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
606b1a0a8a3SJed Brown   PetscErrorCode ierr;
607b1a0a8a3SJed Brown   PetscInt       blocks,ovl;
608b1a0a8a3SJed Brown   PetscBool      symset,flg;
609f746d493SDmitry Karpeev   PCGASMType      gasmtype;
610b1a0a8a3SJed Brown 
611b1a0a8a3SJed Brown   PetscFunctionBegin;
612b1a0a8a3SJed Brown   /* set the type to symmetric if matrix is symmetric */
613b1a0a8a3SJed Brown   if (!osm->type_set && pc->pmat) {
614b1a0a8a3SJed Brown     ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr);
615f746d493SDmitry Karpeev     if (symset && flg) { osm->type = PC_GASM_BASIC; }
616b1a0a8a3SJed Brown   }
61744fe18e5SDmitry Karpeev   ierr = PetscOptionsHead("Generalized additive Schwarz options");CHKERRQ(ierr);
618f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_blocks","Number of subdomains","PCGASMSetTotalSubdomains",osm->n,&blocks,&flg);CHKERRQ(ierr);
619ab3e923fSDmitry Karpeev     if (flg) {ierr = PCGASMSetTotalSubdomains(pc,blocks);CHKERRQ(ierr); }
620f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_overlap","Number of grid points overlap","PCGASMSetOverlap",osm->overlap,&ovl,&flg);CHKERRQ(ierr);
621f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetOverlap(pc,ovl);CHKERRQ(ierr); }
622b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
623f746d493SDmitry Karpeev     ierr = PetscOptionsEnum("-pc_gasm_type","Type of restriction/extension","PCGASMSetType",PCGASMTypes,(PetscEnum)osm->type,(PetscEnum*)&gasmtype,&flg);CHKERRQ(ierr);
624f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetType(pc,gasmtype);CHKERRQ(ierr); }
625b1a0a8a3SJed Brown   ierr = PetscOptionsTail();CHKERRQ(ierr);
626b1a0a8a3SJed Brown   PetscFunctionReturn(0);
627b1a0a8a3SJed Brown }
628b1a0a8a3SJed Brown 
629b1a0a8a3SJed Brown /*------------------------------------------------------------------------------------*/
630b1a0a8a3SJed Brown 
631b1a0a8a3SJed Brown EXTERN_C_BEGIN
632b1a0a8a3SJed Brown #undef __FUNCT__
633f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains_GASM"
6347087cfbeSBarry Smith PetscErrorCode  PCGASMSetLocalSubdomains_GASM(PC pc,PetscInt n,IS is[],IS is_local[])
635b1a0a8a3SJed Brown {
636f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
637b1a0a8a3SJed Brown   PetscErrorCode ierr;
638b1a0a8a3SJed Brown   PetscInt       i;
639b1a0a8a3SJed Brown 
640b1a0a8a3SJed Brown   PetscFunctionBegin;
641*69ca1f37SDmitry Karpeev   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Each process must have 1 or more subdomains, n = %D",n);
642f746d493SDmitry Karpeev   if (pc->setupcalled && (n != osm->n || is)) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetLocalSubdomains() should be called before calling PCSetUp().");
643b1a0a8a3SJed Brown 
644b1a0a8a3SJed Brown   if (!pc->setupcalled) {
64593c1ec32SDmitry Karpeev     osm->n            = n;
64693c1ec32SDmitry Karpeev     osm->is           = 0;
64793c1ec32SDmitry Karpeev     osm->is_local     = 0;
648b1a0a8a3SJed Brown     if (is) {
649b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is[i]);CHKERRQ(ierr);}
650b1a0a8a3SJed Brown     }
651b1a0a8a3SJed Brown     if (is_local) {
652b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is_local[i]);CHKERRQ(ierr);}
653b1a0a8a3SJed Brown     }
654b1a0a8a3SJed Brown     if (osm->is) {
655ab3e923fSDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr);
656b1a0a8a3SJed Brown     }
657b1a0a8a3SJed Brown     if (is) {
658b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is);CHKERRQ(ierr);
659b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is[i] = is[i]; }
660f746d493SDmitry Karpeev       /* Flag indicating that the user has set overlapping subdomains so PCGASM should not increase their size. */
661b1a0a8a3SJed Brown       osm->overlap = -1;
662b1a0a8a3SJed Brown     }
663b1a0a8a3SJed Brown     if (is_local) {
664b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
665b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is_local[i] = is_local[i]; }
666b1a0a8a3SJed Brown     }
667b1a0a8a3SJed Brown   }
668b1a0a8a3SJed Brown   PetscFunctionReturn(0);
669b1a0a8a3SJed Brown }
670b1a0a8a3SJed Brown EXTERN_C_END
671b1a0a8a3SJed Brown 
672b1a0a8a3SJed Brown EXTERN_C_BEGIN
673b1a0a8a3SJed Brown #undef __FUNCT__
674f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains_GASM"
6757087cfbeSBarry Smith PetscErrorCode  PCGASMSetTotalSubdomains_GASM(PC pc,PetscInt N) {
676f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
677b1a0a8a3SJed Brown   PetscErrorCode ierr;
678b1a0a8a3SJed Brown   PetscMPIInt    rank,size;
679b1a0a8a3SJed Brown   PetscInt       n;
680b1a0a8a3SJed Brown 
681b1a0a8a3SJed Brown   PetscFunctionBegin;
682b1a0a8a3SJed Brown   if (N < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of total blocks must be > 0, N = %D",N);
683b1a0a8a3SJed Brown 
684b1a0a8a3SJed Brown   /*
685b1a0a8a3SJed Brown      Split the subdomains equally among all processors
686b1a0a8a3SJed Brown   */
687b1a0a8a3SJed Brown   ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
688b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
689b1a0a8a3SJed Brown   n = N/size + ((N % size) > rank);
690b1a0a8a3SJed 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);
691f746d493SDmitry Karpeev   if (pc->setupcalled && n != osm->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetTotalSubdomains() should be called before PCSetUp().");
692b1a0a8a3SJed Brown   if (!pc->setupcalled) {
693b1a0a8a3SJed Brown     if (osm->is) {
694ab3e923fSDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr);
695b1a0a8a3SJed Brown     }
69693c1ec32SDmitry Karpeev     osm->N            = N;
697f746d493SDmitry Karpeev     osm->n            = n;
698b1a0a8a3SJed Brown     osm->is           = 0;
699b1a0a8a3SJed Brown     osm->is_local     = 0;
700b1a0a8a3SJed Brown   }
701b1a0a8a3SJed Brown   PetscFunctionReturn(0);
702ab3e923fSDmitry Karpeev }/* PCGASMSetTotalSubdomains_GASM() */
703b1a0a8a3SJed Brown EXTERN_C_END
704b1a0a8a3SJed Brown 
705b1a0a8a3SJed Brown EXTERN_C_BEGIN
706b1a0a8a3SJed Brown #undef __FUNCT__
707f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap_GASM"
7087087cfbeSBarry Smith PetscErrorCode  PCGASMSetOverlap_GASM(PC pc,PetscInt ovl)
709b1a0a8a3SJed Brown {
710f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
711b1a0a8a3SJed Brown 
712b1a0a8a3SJed Brown   PetscFunctionBegin;
713b1a0a8a3SJed Brown   if (ovl < 0) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Negative overlap value requested");
714f746d493SDmitry Karpeev   if (pc->setupcalled && ovl != osm->overlap) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetOverlap() should be called before PCSetUp().");
715b1a0a8a3SJed Brown   if (!pc->setupcalled) {
716b1a0a8a3SJed Brown     osm->overlap = ovl;
717b1a0a8a3SJed Brown   }
718b1a0a8a3SJed Brown   PetscFunctionReturn(0);
719b1a0a8a3SJed Brown }
720b1a0a8a3SJed Brown EXTERN_C_END
721b1a0a8a3SJed Brown 
722b1a0a8a3SJed Brown EXTERN_C_BEGIN
723b1a0a8a3SJed Brown #undef __FUNCT__
724f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType_GASM"
7257087cfbeSBarry Smith PetscErrorCode  PCGASMSetType_GASM(PC pc,PCGASMType type)
726b1a0a8a3SJed Brown {
727f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
728b1a0a8a3SJed Brown 
729b1a0a8a3SJed Brown   PetscFunctionBegin;
730b1a0a8a3SJed Brown   osm->type     = type;
731b1a0a8a3SJed Brown   osm->type_set = PETSC_TRUE;
732b1a0a8a3SJed Brown   PetscFunctionReturn(0);
733b1a0a8a3SJed Brown }
734b1a0a8a3SJed Brown EXTERN_C_END
735b1a0a8a3SJed Brown 
736b1a0a8a3SJed Brown EXTERN_C_BEGIN
737b1a0a8a3SJed Brown #undef __FUNCT__
738f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices_GASM"
7397087cfbeSBarry Smith PetscErrorCode  PCGASMSetSortIndices_GASM(PC pc,PetscBool  doSort)
740b1a0a8a3SJed Brown {
741f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
742b1a0a8a3SJed Brown 
743b1a0a8a3SJed Brown   PetscFunctionBegin;
744b1a0a8a3SJed Brown   osm->sort_indices = doSort;
745b1a0a8a3SJed Brown   PetscFunctionReturn(0);
746b1a0a8a3SJed Brown }
747b1a0a8a3SJed Brown EXTERN_C_END
748b1a0a8a3SJed Brown 
749b1a0a8a3SJed Brown EXTERN_C_BEGIN
750b1a0a8a3SJed Brown #undef __FUNCT__
751f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP_GASM"
75244fe18e5SDmitry Karpeev /*
75344fe18e5SDmitry Karpeev    FIX: This routine might need to be modified once multiple ranks per subdomain are allowed.
75444fe18e5SDmitry Karpeev         In particular, it would upset the global subdomain number calculation.
75544fe18e5SDmitry Karpeev */
7567087cfbeSBarry Smith PetscErrorCode  PCGASMGetSubKSP_GASM(PC pc,PetscInt *n,PetscInt *first,KSP **ksp)
757b1a0a8a3SJed Brown {
758f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
759b1a0a8a3SJed Brown   PetscErrorCode ierr;
760b1a0a8a3SJed Brown 
761b1a0a8a3SJed Brown   PetscFunctionBegin;
762ab3e923fSDmitry 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");
763b1a0a8a3SJed Brown 
764ab3e923fSDmitry Karpeev   if (n) {
765ab3e923fSDmitry Karpeev     *n = osm->n;
766b1a0a8a3SJed Brown   }
767ab3e923fSDmitry Karpeev   if (first) {
768ab3e923fSDmitry Karpeev     ierr = MPI_Scan(&osm->n,first,1,MPIU_INT,MPI_SUM,((PetscObject)pc)->comm);CHKERRQ(ierr);
769ab3e923fSDmitry Karpeev     *first -= osm->n;
770b1a0a8a3SJed Brown   }
771b1a0a8a3SJed Brown   if (ksp) {
772b1a0a8a3SJed Brown     /* Assume that local solves are now different; not necessarily
773f746d493SDmitry Karpeev        true though!  This flag is used only for PCView_GASM() */
774b1a0a8a3SJed Brown     *ksp                   = osm->ksp;
775b1a0a8a3SJed Brown     osm->same_local_solves = PETSC_FALSE;
776b1a0a8a3SJed Brown   }
777b1a0a8a3SJed Brown   PetscFunctionReturn(0);
778ab3e923fSDmitry Karpeev }/* PCGASMGetSubKSP_GASM() */
779b1a0a8a3SJed Brown EXTERN_C_END
780b1a0a8a3SJed Brown 
781b1a0a8a3SJed Brown 
782b1a0a8a3SJed Brown #undef __FUNCT__
783f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains"
784b1a0a8a3SJed Brown /*@C
785f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains - Sets the local subdomains (for this processor
786b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
787b1a0a8a3SJed Brown 
788b1a0a8a3SJed Brown     Collective on PC
789b1a0a8a3SJed Brown 
790b1a0a8a3SJed Brown     Input Parameters:
791b1a0a8a3SJed Brown +   pc - the preconditioner context
792b1a0a8a3SJed Brown .   n - the number of subdomains for this processor (default value = 1)
793b1a0a8a3SJed Brown .   is - the index set that defines the subdomains for this processor
794b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
795b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
796b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
797b1a0a8a3SJed Brown 
798b1a0a8a3SJed Brown     Notes:
799b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
800b1a0a8a3SJed Brown 
801f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
802b1a0a8a3SJed Brown 
803f746d493SDmitry Karpeev     Use PCGASMSetTotalSubdomains() to set the subdomains for all processors.
804b1a0a8a3SJed Brown 
805b1a0a8a3SJed Brown     Level: advanced
806b1a0a8a3SJed Brown 
807f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
808b1a0a8a3SJed Brown 
809f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
810f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
811b1a0a8a3SJed Brown @*/
8127087cfbeSBarry Smith PetscErrorCode  PCGASMSetLocalSubdomains(PC pc,PetscInt n,IS is[],IS is_local[])
813b1a0a8a3SJed Brown {
814b1a0a8a3SJed Brown   PetscErrorCode ierr;
815b1a0a8a3SJed Brown 
816b1a0a8a3SJed Brown   PetscFunctionBegin;
817b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
818f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetLocalSubdomains_C",(PC,PetscInt,IS[],IS[]),(pc,n,is,is_local));CHKERRQ(ierr);
819b1a0a8a3SJed Brown   PetscFunctionReturn(0);
820b1a0a8a3SJed Brown }
821b1a0a8a3SJed Brown 
822b1a0a8a3SJed Brown #undef __FUNCT__
823f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains"
824b1a0a8a3SJed Brown /*@C
825f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains - Sets the subdomains for all processor for the
826b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
827b1a0a8a3SJed Brown     PC communicator must call this routine, with the same index sets.
828b1a0a8a3SJed Brown 
829b1a0a8a3SJed Brown     Collective on PC
830b1a0a8a3SJed Brown 
831b1a0a8a3SJed Brown     Input Parameters:
832b1a0a8a3SJed Brown +   pc - the preconditioner context
833b1a0a8a3SJed Brown .   n - the number of subdomains for all processors
834b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for all processor
835b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
836b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
837b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
838b1a0a8a3SJed Brown 
839b1a0a8a3SJed Brown     Options Database Key:
840b1a0a8a3SJed Brown     To set the total number of subdomain blocks rather than specify the
841b1a0a8a3SJed Brown     index sets, use the option
842f746d493SDmitry Karpeev .    -pc_gasm_blocks <blks> - Sets total blocks
843b1a0a8a3SJed Brown 
844b1a0a8a3SJed Brown     Notes:
845b1a0a8a3SJed Brown     Currently you cannot use this to set the actual subdomains with the argument is.
846b1a0a8a3SJed Brown 
847f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
848b1a0a8a3SJed Brown 
849b1a0a8a3SJed Brown     These index sets cannot be destroyed until after completion of the
850f746d493SDmitry Karpeev     linear solves for which the GASM preconditioner is being used.
851b1a0a8a3SJed Brown 
852f746d493SDmitry Karpeev     Use PCGASMSetLocalSubdomains() to set local subdomains.
853b1a0a8a3SJed Brown 
854b1a0a8a3SJed Brown     Level: advanced
855b1a0a8a3SJed Brown 
856f746d493SDmitry Karpeev .keywords: PC, GASM, set, total, global, subdomains, additive Schwarz
857b1a0a8a3SJed Brown 
858f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
859f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
860b1a0a8a3SJed Brown @*/
8617087cfbeSBarry Smith PetscErrorCode  PCGASMSetTotalSubdomains(PC pc,PetscInt N)
862b1a0a8a3SJed Brown {
863b1a0a8a3SJed Brown   PetscErrorCode ierr;
864b1a0a8a3SJed Brown 
865b1a0a8a3SJed Brown   PetscFunctionBegin;
866b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
867f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetTotalSubdomains_C",(PC,PetscInt),(pc,N));CHKERRQ(ierr);
868b1a0a8a3SJed Brown   PetscFunctionReturn(0);
869b1a0a8a3SJed Brown }
870b1a0a8a3SJed Brown 
871b1a0a8a3SJed Brown #undef __FUNCT__
872f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap"
873b1a0a8a3SJed Brown /*@
874f746d493SDmitry Karpeev     PCGASMSetOverlap - Sets the overlap between a pair of subdomains for the
875b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
876b1a0a8a3SJed Brown     PC communicator must call this routine.
877b1a0a8a3SJed Brown 
878b1a0a8a3SJed Brown     Logically Collective on PC
879b1a0a8a3SJed Brown 
880b1a0a8a3SJed Brown     Input Parameters:
881b1a0a8a3SJed Brown +   pc  - the preconditioner context
882b1a0a8a3SJed Brown -   ovl - the amount of overlap between subdomains (ovl >= 0, default value = 1)
883b1a0a8a3SJed Brown 
884b1a0a8a3SJed Brown     Options Database Key:
885f746d493SDmitry Karpeev .   -pc_gasm_overlap <ovl> - Sets overlap
886b1a0a8a3SJed Brown 
887b1a0a8a3SJed Brown     Notes:
888f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.  To use
889f746d493SDmitry Karpeev     multiple blocks per perocessor, see PCGASMSetTotalSubdomains() and
890f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains() (and the option -pc_gasm_blocks <blks>).
891b1a0a8a3SJed Brown 
892b1a0a8a3SJed Brown     The overlap defaults to 1, so if one desires that no additional
893b1a0a8a3SJed Brown     overlap be computed beyond what may have been set with a call to
894f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(), then ovl
895b1a0a8a3SJed Brown     must be set to be 0.  In particular, if one does not explicitly set
896b1a0a8a3SJed Brown     the subdomains an application code, then all overlap would be computed
897f746d493SDmitry Karpeev     internally by PETSc, and using an overlap of 0 would result in an GASM
898b1a0a8a3SJed Brown     variant that is equivalent to the block Jacobi preconditioner.
899b1a0a8a3SJed Brown 
900b1a0a8a3SJed Brown     Note that one can define initial index sets with any overlap via
901f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(); the routine
902f746d493SDmitry Karpeev     PCGASMSetOverlap() merely allows PETSc to extend that overlap further
903b1a0a8a3SJed Brown     if desired.
904b1a0a8a3SJed Brown 
905b1a0a8a3SJed Brown     Level: intermediate
906b1a0a8a3SJed Brown 
907f746d493SDmitry Karpeev .keywords: PC, GASM, set, overlap
908b1a0a8a3SJed Brown 
909f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
910f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
911b1a0a8a3SJed Brown @*/
9127087cfbeSBarry Smith PetscErrorCode  PCGASMSetOverlap(PC pc,PetscInt ovl)
913b1a0a8a3SJed Brown {
914b1a0a8a3SJed Brown   PetscErrorCode ierr;
915b1a0a8a3SJed Brown 
916b1a0a8a3SJed Brown   PetscFunctionBegin;
917b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
918b1a0a8a3SJed Brown   PetscValidLogicalCollectiveInt(pc,ovl,2);
919f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetOverlap_C",(PC,PetscInt),(pc,ovl));CHKERRQ(ierr);
920b1a0a8a3SJed Brown   PetscFunctionReturn(0);
921b1a0a8a3SJed Brown }
922b1a0a8a3SJed Brown 
923b1a0a8a3SJed Brown #undef __FUNCT__
924f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType"
925b1a0a8a3SJed Brown /*@
926f746d493SDmitry Karpeev     PCGASMSetType - Sets the type of restriction and interpolation used
927b1a0a8a3SJed Brown     for local problems in the additive Schwarz method.
928b1a0a8a3SJed Brown 
929b1a0a8a3SJed Brown     Logically Collective on PC
930b1a0a8a3SJed Brown 
931b1a0a8a3SJed Brown     Input Parameters:
932b1a0a8a3SJed Brown +   pc  - the preconditioner context
933f746d493SDmitry Karpeev -   type - variant of GASM, one of
934b1a0a8a3SJed Brown .vb
935f746d493SDmitry Karpeev       PC_GASM_BASIC       - full interpolation and restriction
936f746d493SDmitry Karpeev       PC_GASM_RESTRICT    - full restriction, local processor interpolation
937f746d493SDmitry Karpeev       PC_GASM_INTERPOLATE - full interpolation, local processor restriction
938f746d493SDmitry Karpeev       PC_GASM_NONE        - local processor restriction and interpolation
939b1a0a8a3SJed Brown .ve
940b1a0a8a3SJed Brown 
941b1a0a8a3SJed Brown     Options Database Key:
942f746d493SDmitry Karpeev .   -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
943b1a0a8a3SJed Brown 
944b1a0a8a3SJed Brown     Level: intermediate
945b1a0a8a3SJed Brown 
946f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
947b1a0a8a3SJed Brown 
948f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
949f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
950b1a0a8a3SJed Brown @*/
9517087cfbeSBarry Smith PetscErrorCode  PCGASMSetType(PC pc,PCGASMType type)
952b1a0a8a3SJed Brown {
953b1a0a8a3SJed Brown   PetscErrorCode ierr;
954b1a0a8a3SJed Brown 
955b1a0a8a3SJed Brown   PetscFunctionBegin;
956b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
957b1a0a8a3SJed Brown   PetscValidLogicalCollectiveEnum(pc,type,2);
958f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetType_C",(PC,PCGASMType),(pc,type));CHKERRQ(ierr);
959b1a0a8a3SJed Brown   PetscFunctionReturn(0);
960b1a0a8a3SJed Brown }
961b1a0a8a3SJed Brown 
962b1a0a8a3SJed Brown #undef __FUNCT__
963f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices"
964b1a0a8a3SJed Brown /*@
965f746d493SDmitry Karpeev     PCGASMSetSortIndices - Determines whether subdomain indices are sorted.
966b1a0a8a3SJed Brown 
967b1a0a8a3SJed Brown     Logically Collective on PC
968b1a0a8a3SJed Brown 
969b1a0a8a3SJed Brown     Input Parameters:
970b1a0a8a3SJed Brown +   pc  - the preconditioner context
971b1a0a8a3SJed Brown -   doSort - sort the subdomain indices
972b1a0a8a3SJed Brown 
973b1a0a8a3SJed Brown     Level: intermediate
974b1a0a8a3SJed Brown 
975f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
976b1a0a8a3SJed Brown 
977f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
978f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
979b1a0a8a3SJed Brown @*/
9807087cfbeSBarry Smith PetscErrorCode  PCGASMSetSortIndices(PC pc,PetscBool  doSort)
981b1a0a8a3SJed Brown {
982b1a0a8a3SJed Brown   PetscErrorCode ierr;
983b1a0a8a3SJed Brown 
984b1a0a8a3SJed Brown   PetscFunctionBegin;
985b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
986b1a0a8a3SJed Brown   PetscValidLogicalCollectiveBool(pc,doSort,2);
987f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetSortIndices_C",(PC,PetscBool),(pc,doSort));CHKERRQ(ierr);
988b1a0a8a3SJed Brown   PetscFunctionReturn(0);
989b1a0a8a3SJed Brown }
990b1a0a8a3SJed Brown 
991b1a0a8a3SJed Brown #undef __FUNCT__
992f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP"
993b1a0a8a3SJed Brown /*@C
994f746d493SDmitry Karpeev    PCGASMGetSubKSP - Gets the local KSP contexts for all blocks on
995b1a0a8a3SJed Brown    this processor.
996b1a0a8a3SJed Brown 
997b1a0a8a3SJed Brown    Collective on PC iff first_local is requested
998b1a0a8a3SJed Brown 
999b1a0a8a3SJed Brown    Input Parameter:
1000b1a0a8a3SJed Brown .  pc - the preconditioner context
1001b1a0a8a3SJed Brown 
1002b1a0a8a3SJed Brown    Output Parameters:
1003b1a0a8a3SJed Brown +  n_local - the number of blocks on this processor or PETSC_NULL
1004b1a0a8a3SJed Brown .  first_local - the global number of the first block on this processor or PETSC_NULL,
1005b1a0a8a3SJed Brown                  all processors must request or all must pass PETSC_NULL
1006b1a0a8a3SJed Brown -  ksp - the array of KSP contexts
1007b1a0a8a3SJed Brown 
1008b1a0a8a3SJed Brown    Note:
1009f746d493SDmitry Karpeev    After PCGASMGetSubKSP() the array of KSPes is not to be freed
1010b1a0a8a3SJed Brown 
1011b1a0a8a3SJed Brown    Currently for some matrix implementations only 1 block per processor
1012b1a0a8a3SJed Brown    is supported.
1013b1a0a8a3SJed Brown 
1014f746d493SDmitry Karpeev    You must call KSPSetUp() before calling PCGASMGetSubKSP().
1015b1a0a8a3SJed Brown 
1016b1a0a8a3SJed Brown    Level: advanced
1017b1a0a8a3SJed Brown 
1018f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, get, sub, KSP, context
1019b1a0a8a3SJed Brown 
1020f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMSetOverlap(),
1021f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(),
1022b1a0a8a3SJed Brown @*/
10237087cfbeSBarry Smith PetscErrorCode  PCGASMGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[])
1024b1a0a8a3SJed Brown {
1025b1a0a8a3SJed Brown   PetscErrorCode ierr;
1026b1a0a8a3SJed Brown 
1027b1a0a8a3SJed Brown   PetscFunctionBegin;
1028b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1029f746d493SDmitry Karpeev   ierr = PetscUseMethod(pc,"PCGASMGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));CHKERRQ(ierr);
1030b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1031b1a0a8a3SJed Brown }
1032b1a0a8a3SJed Brown 
1033b1a0a8a3SJed Brown /* -------------------------------------------------------------------------------------*/
1034b1a0a8a3SJed Brown /*MC
1035f746d493SDmitry Karpeev    PCGASM - Use the (restricted) additive Schwarz method, each block is (approximately) solved with
1036b1a0a8a3SJed Brown            its own KSP object.
1037b1a0a8a3SJed Brown 
1038b1a0a8a3SJed Brown    Options Database Keys:
1039f746d493SDmitry Karpeev +  -pc_gasm_truelocal - Activates PCGGASMSetUseTrueLocal()
1040f746d493SDmitry Karpeev .  -pc_gasm_blocks <blks> - Sets total blocks
1041f746d493SDmitry Karpeev .  -pc_gasm_overlap <ovl> - Sets overlap
1042f746d493SDmitry Karpeev -  -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
1043b1a0a8a3SJed Brown 
1044b1a0a8a3SJed Brown      IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you
1045f746d493SDmitry Karpeev       will get a different convergence rate due to the default option of -pc_gasm_type restrict. Use
1046f746d493SDmitry Karpeev       -pc_gasm_type basic to use the standard GASM.
1047b1a0a8a3SJed Brown 
1048b1a0a8a3SJed Brown    Notes: Each processor can have one or more blocks, but a block cannot be shared by more
1049b1a0a8a3SJed Brown      than one processor. Defaults to one block per processor.
1050b1a0a8a3SJed Brown 
1051b1a0a8a3SJed Brown      To set options on the solvers for each block append -sub_ to all the KSP, and PC
1052b1a0a8a3SJed Brown         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
1053b1a0a8a3SJed Brown 
1054f746d493SDmitry Karpeev      To set the options on the solvers separate for each block call PCGASMGetSubKSP()
1055b1a0a8a3SJed Brown          and set the options directly on the resulting KSP object (you can access its PC
1056b1a0a8a3SJed Brown          with KSPGetPC())
1057b1a0a8a3SJed Brown 
1058b1a0a8a3SJed Brown 
1059b1a0a8a3SJed Brown    Level: beginner
1060b1a0a8a3SJed Brown 
1061b1a0a8a3SJed Brown    Concepts: additive Schwarz method
1062b1a0a8a3SJed Brown 
1063b1a0a8a3SJed Brown     References:
1064b1a0a8a3SJed Brown     An additive variant of the Schwarz alternating method for the case of many subregions
1065b1a0a8a3SJed Brown     M Dryja, OB Widlund - Courant Institute, New York University Technical report
1066b1a0a8a3SJed Brown 
1067b1a0a8a3SJed Brown     Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations,
1068b1a0a8a3SJed Brown     Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X.
1069b1a0a8a3SJed Brown 
1070b1a0a8a3SJed Brown .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
1071f746d493SDmitry Karpeev            PCBJACOBI, PCGASMSetUseTrueLocal(), PCGASMGetSubKSP(), PCGASMSetLocalSubdomains(),
1072f746d493SDmitry Karpeev            PCGASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCGASMSetOverlap(), PCGASMSetType()
1073b1a0a8a3SJed Brown 
1074b1a0a8a3SJed Brown M*/
1075b1a0a8a3SJed Brown 
1076b1a0a8a3SJed Brown EXTERN_C_BEGIN
1077b1a0a8a3SJed Brown #undef __FUNCT__
1078f746d493SDmitry Karpeev #define __FUNCT__ "PCCreate_GASM"
10797087cfbeSBarry Smith PetscErrorCode  PCCreate_GASM(PC pc)
1080b1a0a8a3SJed Brown {
1081b1a0a8a3SJed Brown   PetscErrorCode ierr;
1082f746d493SDmitry Karpeev   PC_GASM         *osm;
1083b1a0a8a3SJed Brown 
1084b1a0a8a3SJed Brown   PetscFunctionBegin;
1085f746d493SDmitry Karpeev   ierr = PetscNewLog(pc,PC_GASM,&osm);CHKERRQ(ierr);
1086ab3e923fSDmitry Karpeev   osm->N                 = PETSC_DECIDE;
1087ab3e923fSDmitry Karpeev   osm->n                 = 0;
1088ab3e923fSDmitry Karpeev   osm->nmax              = 0;
1089b1a0a8a3SJed Brown   osm->overlap           = 1;
1090b1a0a8a3SJed Brown   osm->ksp               = 0;
1091ab3e923fSDmitry Karpeev   osm->grestriction      = 0;
1092ab3e923fSDmitry Karpeev   osm->gprolongation     = 0;
1093ab3e923fSDmitry Karpeev   osm->gx                = 0;
1094ab3e923fSDmitry Karpeev   osm->gy                = 0;
1095b1a0a8a3SJed Brown   osm->x                 = 0;
1096b1a0a8a3SJed Brown   osm->y                 = 0;
1097b1a0a8a3SJed Brown   osm->is                = 0;
1098b1a0a8a3SJed Brown   osm->is_local          = 0;
1099b1a0a8a3SJed Brown   osm->pmat              = 0;
1100f746d493SDmitry Karpeev   osm->type              = PC_GASM_RESTRICT;
1101b1a0a8a3SJed Brown   osm->same_local_solves = PETSC_TRUE;
1102b1a0a8a3SJed Brown   osm->sort_indices      = PETSC_TRUE;
1103b1a0a8a3SJed Brown 
1104b1a0a8a3SJed Brown   pc->data                   = (void*)osm;
1105f746d493SDmitry Karpeev   pc->ops->apply             = PCApply_GASM;
1106f746d493SDmitry Karpeev   pc->ops->applytranspose    = PCApplyTranspose_GASM;
1107f746d493SDmitry Karpeev   pc->ops->setup             = PCSetUp_GASM;
1108a06653b4SBarry Smith   pc->ops->reset             = PCReset_GASM;
1109f746d493SDmitry Karpeev   pc->ops->destroy           = PCDestroy_GASM;
1110f746d493SDmitry Karpeev   pc->ops->setfromoptions    = PCSetFromOptions_GASM;
1111f746d493SDmitry Karpeev   pc->ops->setuponblocks     = PCSetUpOnBlocks_GASM;
1112f746d493SDmitry Karpeev   pc->ops->view              = PCView_GASM;
1113b1a0a8a3SJed Brown   pc->ops->applyrichardson   = 0;
1114b1a0a8a3SJed Brown 
1115f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetLocalSubdomains_C","PCGASMSetLocalSubdomains_GASM",
1116f746d493SDmitry Karpeev                     PCGASMSetLocalSubdomains_GASM);CHKERRQ(ierr);
1117f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetTotalSubdomains_C","PCGASMSetTotalSubdomains_GASM",
1118f746d493SDmitry Karpeev                     PCGASMSetTotalSubdomains_GASM);CHKERRQ(ierr);
1119f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetOverlap_C","PCGASMSetOverlap_GASM",
1120f746d493SDmitry Karpeev                     PCGASMSetOverlap_GASM);CHKERRQ(ierr);
1121f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetType_C","PCGASMSetType_GASM",
1122f746d493SDmitry Karpeev                     PCGASMSetType_GASM);CHKERRQ(ierr);
1123f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetSortIndices_C","PCGASMSetSortIndices_GASM",
1124f746d493SDmitry Karpeev                     PCGASMSetSortIndices_GASM);CHKERRQ(ierr);
1125f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMGetSubKSP_C","PCGASMGetSubKSP_GASM",
1126f746d493SDmitry Karpeev                     PCGASMGetSubKSP_GASM);CHKERRQ(ierr);
1127b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1128b1a0a8a3SJed Brown }
1129b1a0a8a3SJed Brown EXTERN_C_END
1130b1a0a8a3SJed Brown 
1131b1a0a8a3SJed Brown 
1132b1a0a8a3SJed Brown #undef __FUNCT__
1133f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains"
1134b1a0a8a3SJed Brown /*@C
1135f746d493SDmitry Karpeev    PCGASMCreateSubdomains - Creates the index sets for the overlapping Schwarz
1136b1a0a8a3SJed Brown    preconditioner for a any problem on a general grid.
1137b1a0a8a3SJed Brown 
1138b1a0a8a3SJed Brown    Collective
1139b1a0a8a3SJed Brown 
1140b1a0a8a3SJed Brown    Input Parameters:
1141b1a0a8a3SJed Brown +  A - The global matrix operator
1142b1a0a8a3SJed Brown -  n - the number of local blocks
1143b1a0a8a3SJed Brown 
1144b1a0a8a3SJed Brown    Output Parameters:
1145b1a0a8a3SJed Brown .  outis - the array of index sets defining the subdomains
1146b1a0a8a3SJed Brown 
1147b1a0a8a3SJed Brown    Level: advanced
1148b1a0a8a3SJed Brown 
1149f746d493SDmitry Karpeev    Note: this generates nonoverlapping subdomains; the PCGASM will generate the overlap
1150f746d493SDmitry Karpeev     from these if you use PCGASMSetLocalSubdomains()
1151b1a0a8a3SJed Brown 
1152b1a0a8a3SJed Brown     In the Fortran version you must provide the array outis[] already allocated of length n.
1153b1a0a8a3SJed Brown 
1154f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1155b1a0a8a3SJed Brown 
1156f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMDestroySubdomains()
1157b1a0a8a3SJed Brown @*/
11587087cfbeSBarry Smith PetscErrorCode  PCGASMCreateSubdomains(Mat A, PetscInt n, IS* outis[])
1159b1a0a8a3SJed Brown {
1160b1a0a8a3SJed Brown   MatPartitioning           mpart;
1161b1a0a8a3SJed Brown   const char                *prefix;
116211bd1e4dSLisandro Dalcin   PetscErrorCode            (*f)(Mat,MatReuse,Mat*);
1163b1a0a8a3SJed Brown   PetscMPIInt               size;
1164b1a0a8a3SJed Brown   PetscInt                  i,j,rstart,rend,bs;
116511bd1e4dSLisandro Dalcin   PetscBool                 isbaij = PETSC_FALSE,foundpart = PETSC_FALSE;
1166b1a0a8a3SJed Brown   Mat                       Ad = PETSC_NULL, adj;
1167b1a0a8a3SJed Brown   IS                        ispart,isnumb,*is;
1168b1a0a8a3SJed Brown   PetscErrorCode            ierr;
1169b1a0a8a3SJed Brown 
1170b1a0a8a3SJed Brown   PetscFunctionBegin;
1171b1a0a8a3SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1172b1a0a8a3SJed Brown   PetscValidPointer(outis,3);
1173b1a0a8a3SJed Brown   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n);
1174b1a0a8a3SJed Brown 
1175b1a0a8a3SJed Brown   /* Get prefix, row distribution, and block size */
1176b1a0a8a3SJed Brown   ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr);
1177b1a0a8a3SJed Brown   ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);
1178b1a0a8a3SJed Brown   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1179b1a0a8a3SJed 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);
1180b1a0a8a3SJed Brown 
1181b1a0a8a3SJed Brown   /* Get diagonal block from matrix if possible */
1182b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
1183b1a0a8a3SJed Brown   ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**)(void))&f);CHKERRQ(ierr);
1184b1a0a8a3SJed Brown   if (f) {
118511bd1e4dSLisandro Dalcin     ierr = MatGetDiagonalBlock(A,&Ad);CHKERRQ(ierr);
1186b1a0a8a3SJed Brown   } else if (size == 1) {
118711bd1e4dSLisandro Dalcin     Ad = A;
1188b1a0a8a3SJed Brown   }
1189b1a0a8a3SJed Brown   if (Ad) {
1190b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr);
1191b1a0a8a3SJed Brown     if (!isbaij) {ierr = PetscTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);}
1192b1a0a8a3SJed Brown   }
1193b1a0a8a3SJed Brown   if (Ad && n > 1) {
1194b1a0a8a3SJed Brown     PetscBool  match,done;
1195b1a0a8a3SJed Brown     /* Try to setup a good matrix partitioning if available */
1196b1a0a8a3SJed Brown     ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr);
1197b1a0a8a3SJed Brown     ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr);
1198b1a0a8a3SJed Brown     ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr);
1199b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr);
1200b1a0a8a3SJed Brown     if (!match) {
1201b1a0a8a3SJed Brown       ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr);
1202b1a0a8a3SJed Brown     }
1203b1a0a8a3SJed Brown     if (!match) { /* assume a "good" partitioner is available */
1204b1a0a8a3SJed Brown       PetscInt na,*ia,*ja;
1205b1a0a8a3SJed Brown       ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1206b1a0a8a3SJed Brown       if (done) {
1207b1a0a8a3SJed Brown         /* Build adjacency matrix by hand. Unfortunately a call to
1208b1a0a8a3SJed Brown            MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will
1209b1a0a8a3SJed Brown            remove the block-aij structure and we cannot expect
1210b1a0a8a3SJed Brown            MatPartitioning to split vertices as we need */
1211b1a0a8a3SJed Brown         PetscInt i,j,*row,len,nnz,cnt,*iia=0,*jja=0;
1212b1a0a8a3SJed Brown         nnz = 0;
1213b1a0a8a3SJed Brown         for (i=0; i<na; i++) { /* count number of nonzeros */
1214b1a0a8a3SJed Brown           len = ia[i+1] - ia[i];
1215b1a0a8a3SJed Brown           row = ja + ia[i];
1216b1a0a8a3SJed Brown           for (j=0; j<len; j++) {
1217b1a0a8a3SJed Brown             if (row[j] == i) { /* don't count diagonal */
1218b1a0a8a3SJed Brown               len--; break;
1219b1a0a8a3SJed Brown             }
1220b1a0a8a3SJed Brown           }
1221b1a0a8a3SJed Brown           nnz += len;
1222b1a0a8a3SJed Brown         }
1223b1a0a8a3SJed Brown         ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr);
1224b1a0a8a3SJed Brown         ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr);
1225b1a0a8a3SJed Brown         nnz    = 0;
1226b1a0a8a3SJed Brown         iia[0] = 0;
1227b1a0a8a3SJed Brown         for (i=0; i<na; i++) { /* fill adjacency */
1228b1a0a8a3SJed Brown           cnt = 0;
1229b1a0a8a3SJed Brown           len = ia[i+1] - ia[i];
1230b1a0a8a3SJed Brown           row = ja + ia[i];
1231b1a0a8a3SJed Brown           for (j=0; j<len; j++) {
1232b1a0a8a3SJed Brown             if (row[j] != i) { /* if not diagonal */
1233b1a0a8a3SJed Brown               jja[nnz+cnt++] = row[j];
1234b1a0a8a3SJed Brown             }
1235b1a0a8a3SJed Brown           }
1236b1a0a8a3SJed Brown           nnz += cnt;
1237b1a0a8a3SJed Brown           iia[i+1] = nnz;
1238b1a0a8a3SJed Brown         }
1239b1a0a8a3SJed Brown         /* Partitioning of the adjacency matrix */
1240b1a0a8a3SJed Brown         ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,PETSC_NULL,&adj);CHKERRQ(ierr);
1241b1a0a8a3SJed Brown         ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr);
1242b1a0a8a3SJed Brown         ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr);
1243b1a0a8a3SJed Brown         ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr);
1244b1a0a8a3SJed Brown         ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr);
12456bf464f9SBarry Smith         ierr = MatDestroy(&adj);CHKERRQ(ierr);
1246b1a0a8a3SJed Brown         foundpart = PETSC_TRUE;
1247b1a0a8a3SJed Brown       }
1248b1a0a8a3SJed Brown       ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1249b1a0a8a3SJed Brown     }
12506bf464f9SBarry Smith     ierr = MatPartitioningDestroy(&mpart);CHKERRQ(ierr);
1251b1a0a8a3SJed Brown   }
1252b1a0a8a3SJed Brown 
1253b1a0a8a3SJed Brown   ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr);
1254b1a0a8a3SJed Brown   *outis = is;
1255b1a0a8a3SJed Brown 
1256b1a0a8a3SJed Brown   if (!foundpart) {
1257b1a0a8a3SJed Brown 
1258b1a0a8a3SJed Brown     /* Partitioning by contiguous chunks of rows */
1259b1a0a8a3SJed Brown 
1260b1a0a8a3SJed Brown     PetscInt mbs   = (rend-rstart)/bs;
1261b1a0a8a3SJed Brown     PetscInt start = rstart;
1262b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1263b1a0a8a3SJed Brown       PetscInt count = (mbs/n + ((mbs % n) > i)) * bs;
1264b1a0a8a3SJed Brown       ierr   = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr);
1265b1a0a8a3SJed Brown       start += count;
1266b1a0a8a3SJed Brown     }
1267b1a0a8a3SJed Brown 
1268b1a0a8a3SJed Brown   } else {
1269b1a0a8a3SJed Brown 
1270b1a0a8a3SJed Brown     /* Partitioning by adjacency of diagonal block  */
1271b1a0a8a3SJed Brown 
1272b1a0a8a3SJed Brown     const PetscInt *numbering;
1273b1a0a8a3SJed Brown     PetscInt       *count,nidx,*indices,*newidx,start=0;
1274b1a0a8a3SJed Brown     /* Get node count in each partition */
1275b1a0a8a3SJed Brown     ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr);
1276b1a0a8a3SJed Brown     ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr);
1277b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1278b1a0a8a3SJed Brown       for (i=0; i<n; i++) count[i] *= bs;
1279b1a0a8a3SJed Brown     }
1280b1a0a8a3SJed Brown     /* Build indices from node numbering */
1281b1a0a8a3SJed Brown     ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr);
1282b1a0a8a3SJed Brown     ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1283b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */
1284b1a0a8a3SJed Brown     ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr);
1285b1a0a8a3SJed Brown     ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr);
1286b1a0a8a3SJed Brown     ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr);
1287b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1288b1a0a8a3SJed Brown       ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr);
1289b1a0a8a3SJed Brown       for (i=0; i<nidx; i++)
1290b1a0a8a3SJed Brown         for (j=0; j<bs; j++)
1291b1a0a8a3SJed Brown           newidx[i*bs+j] = indices[i]*bs + j;
1292b1a0a8a3SJed Brown       ierr = PetscFree(indices);CHKERRQ(ierr);
1293b1a0a8a3SJed Brown       nidx   *= bs;
1294b1a0a8a3SJed Brown       indices = newidx;
1295b1a0a8a3SJed Brown     }
1296b1a0a8a3SJed Brown     /* Shift to get global indices */
1297b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] += rstart;
1298b1a0a8a3SJed Brown 
1299b1a0a8a3SJed Brown     /* Build the index sets for each block */
1300b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1301b1a0a8a3SJed Brown       ierr   = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],PETSC_COPY_VALUES,&is[i]);CHKERRQ(ierr);
1302b1a0a8a3SJed Brown       ierr   = ISSort(is[i]);CHKERRQ(ierr);
1303b1a0a8a3SJed Brown       start += count[i];
1304b1a0a8a3SJed Brown     }
1305b1a0a8a3SJed Brown 
1306b1a0a8a3SJed Brown     ierr = PetscFree(count);
1307b1a0a8a3SJed Brown     ierr = PetscFree(indices);
1308fcfd50ebSBarry Smith     ierr = ISDestroy(&isnumb);CHKERRQ(ierr);
1309fcfd50ebSBarry Smith     ierr = ISDestroy(&ispart);CHKERRQ(ierr);
1310b1a0a8a3SJed Brown   }
1311b1a0a8a3SJed Brown 
1312b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1313b1a0a8a3SJed Brown }
1314b1a0a8a3SJed Brown 
1315b1a0a8a3SJed Brown #undef __FUNCT__
1316f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMDestroySubdomains"
1317b1a0a8a3SJed Brown /*@C
1318f746d493SDmitry Karpeev    PCGASMDestroySubdomains - Destroys the index sets created with
1319f746d493SDmitry Karpeev    PCGASMCreateSubdomains(). Should be called after setting subdomains
1320f746d493SDmitry Karpeev    with PCGASMSetLocalSubdomains().
1321b1a0a8a3SJed Brown 
1322b1a0a8a3SJed Brown    Collective
1323b1a0a8a3SJed Brown 
1324b1a0a8a3SJed Brown    Input Parameters:
1325b1a0a8a3SJed Brown +  n - the number of index sets
1326b1a0a8a3SJed Brown .  is - the array of index sets
1327b1a0a8a3SJed Brown -  is_local - the array of local index sets, can be PETSC_NULL
1328b1a0a8a3SJed Brown 
1329b1a0a8a3SJed Brown    Level: advanced
1330b1a0a8a3SJed Brown 
1331f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1332b1a0a8a3SJed Brown 
1333f746d493SDmitry Karpeev .seealso: PCGASMCreateSubdomains(), PCGASMSetLocalSubdomains()
1334b1a0a8a3SJed Brown @*/
13357087cfbeSBarry Smith PetscErrorCode  PCGASMDestroySubdomains(PetscInt n, IS is[], IS is_local[])
1336b1a0a8a3SJed Brown {
1337b1a0a8a3SJed Brown   PetscInt       i;
1338b1a0a8a3SJed Brown   PetscErrorCode ierr;
1339b1a0a8a3SJed Brown   PetscFunctionBegin;
1340b1a0a8a3SJed Brown   if (n <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n must be > 0: n = %D",n);
1341b1a0a8a3SJed Brown   PetscValidPointer(is,2);
1342fcfd50ebSBarry Smith   for (i=0; i<n; i++) { ierr = ISDestroy(&is[i]);CHKERRQ(ierr); }
1343b1a0a8a3SJed Brown   ierr = PetscFree(is);CHKERRQ(ierr);
1344b1a0a8a3SJed Brown   if (is_local) {
1345b1a0a8a3SJed Brown     PetscValidPointer(is_local,3);
1346fcfd50ebSBarry Smith     for (i=0; i<n; i++) { ierr = ISDestroy(&is_local[i]);CHKERRQ(ierr); }
1347b1a0a8a3SJed Brown     ierr = PetscFree(is_local);CHKERRQ(ierr);
1348b1a0a8a3SJed Brown   }
1349b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1350b1a0a8a3SJed Brown }
1351b1a0a8a3SJed Brown 
1352af538404SDmitry Karpeev 
1353af538404SDmitry Karpeev #define PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,xleft_loc,ylow_loc,xright_loc,yhigh_loc,n) \
1354af538404SDmitry Karpeev {                                                                                                       \
1355af538404SDmitry Karpeev  PetscInt first_row = first/M, last_row = last/M+1;                                                     \
1356af538404SDmitry Karpeev   /*                                                                                                    \
1357af538404SDmitry Karpeev    Compute ylow_loc and yhigh_loc so that (ylow_loc,xleft) and (yhigh_loc,xright) are the corners       \
1358af538404SDmitry Karpeev    of the bounding box of the intersection of the subdomain with the local ownership range (local       \
1359af538404SDmitry Karpeev    subdomain).                                                                                          \
1360af538404SDmitry Karpeev    Also compute xleft_loc and xright_loc as the lower and upper bounds on the first and last rows       \
1361af538404SDmitry Karpeev    of the intersection.                                                                                 \
1362af538404SDmitry Karpeev   */                                                                                                    \
1363af538404SDmitry Karpeev   /* ylow_loc is the grid row containing the first element of the local sumbdomain */                   \
1364eec7e3faSDmitry Karpeev   *ylow_loc = PetscMax(first_row,ylow);                                                                    \
1365af538404SDmitry Karpeev   /* xleft_loc is the offset of first element of the local subdomain within its grid row (might actually be outside the local subdomain) */ \
1366eec7e3faSDmitry Karpeev   *xleft_loc = *ylow_loc==first_row?PetscMax(first%M,xleft):xleft;                                                                            \
1367af538404SDmitry Karpeev   /* yhigh_loc is the grid row above the last local subdomain element */                                                                    \
1368eec7e3faSDmitry Karpeev   *yhigh_loc = PetscMin(last_row,yhigh);                                                                                                     \
1369af538404SDmitry Karpeev   /* xright is the offset of the end of the  local subdomain within its grid row (might actually be outside the local subdomain) */         \
1370eec7e3faSDmitry Karpeev   *xright_loc = *yhigh_loc==last_row?PetscMin(xright,last%M):xright;                                                                          \
1371af538404SDmitry Karpeev   /* Now compute the size of the local subdomain n. */ \
1372c3518bceSDmitry Karpeev   *n = 0;                                               \
1373eec7e3faSDmitry Karpeev   if(*ylow_loc < *yhigh_loc) {                           \
1374af538404SDmitry Karpeev     PetscInt width = xright-xleft;                     \
1375eec7e3faSDmitry Karpeev     *n += width*(*yhigh_loc-*ylow_loc-1);                 \
1376eec7e3faSDmitry Karpeev     *n += PetscMin(PetscMax(*xright_loc-xleft,0),width); \
1377eec7e3faSDmitry Karpeev     *n -= PetscMin(PetscMax(*xleft_loc-xleft,0), width); \
1378af538404SDmitry Karpeev   }\
1379af538404SDmitry Karpeev }
1380af538404SDmitry Karpeev 
1381c3518bceSDmitry Karpeev 
1382eec7e3faSDmitry Karpeev 
1383eec7e3faSDmitry Karpeev #undef __FUNCT__
1384f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains2D"
1385b1a0a8a3SJed Brown /*@
1386f746d493SDmitry Karpeev    PCGASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz
1387b1a0a8a3SJed Brown    preconditioner for a two-dimensional problem on a regular grid.
1388b1a0a8a3SJed Brown 
1389af538404SDmitry Karpeev    Collective
1390b1a0a8a3SJed Brown 
1391b1a0a8a3SJed Brown    Input Parameters:
1392af538404SDmitry Karpeev +  M, N - the global number of mesh points in the x and y directions
1393af538404SDmitry Karpeev .  Mdomains, Ndomains - the global number of subdomains in the x and y directions
1394b1a0a8a3SJed Brown .  dof - degrees of freedom per node
1395b1a0a8a3SJed Brown -  overlap - overlap in mesh lines
1396b1a0a8a3SJed Brown 
1397b1a0a8a3SJed Brown    Output Parameters:
1398af538404SDmitry Karpeev +  Nsub - the number of local subdomains created
1399b1a0a8a3SJed Brown .  is - array of index sets defining overlapping (if overlap > 0) subdomains
1400b1a0a8a3SJed Brown -  is_local - array of index sets defining non-overlapping subdomains
1401b1a0a8a3SJed Brown 
1402b1a0a8a3SJed Brown    Note:
1403b1a0a8a3SJed Brown    Presently PCAMSCreateSubdomains2d() is valid only for sequential
1404b1a0a8a3SJed Brown    preconditioners.  More general related routines are
1405f746d493SDmitry Karpeev    PCGASMSetTotalSubdomains() and PCGASMSetLocalSubdomains().
1406b1a0a8a3SJed Brown 
1407b1a0a8a3SJed Brown    Level: advanced
1408b1a0a8a3SJed Brown 
1409f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, 2D, regular grid
1410b1a0a8a3SJed Brown 
1411f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
1412f746d493SDmitry Karpeev           PCGASMSetOverlap()
1413b1a0a8a3SJed Brown @*/
14147087cfbeSBarry Smith PetscErrorCode  PCGASMCreateSubdomains2D(PC pc, PetscInt M,PetscInt N,PetscInt Mdomains,PetscInt Ndomains,PetscInt dof,PetscInt overlap, PetscInt *nsub,IS **is,IS **is_local)
1415b1a0a8a3SJed Brown {
1416b1a0a8a3SJed Brown   PetscErrorCode ierr;
14172bbb417fSDmitry Karpeev   PetscMPIInt    size, rank;
14182bbb417fSDmitry Karpeev   PetscInt       i, j;
14192bbb417fSDmitry Karpeev   PetscInt       maxheight, maxwidth;
14202bbb417fSDmitry Karpeev   PetscInt       xstart, xleft, xright, xleft_loc, xright_loc;
14212bbb417fSDmitry Karpeev   PetscInt       ystart, ylow,  yhigh,  ylow_loc,  yhigh_loc;
1422eec7e3faSDmitry Karpeev   PetscInt       x[2][2], y[2][2], n[2];
14232bbb417fSDmitry Karpeev   PetscInt       first, last;
14242bbb417fSDmitry Karpeev   PetscInt       nidx, *idx;
14252bbb417fSDmitry Karpeev   PetscInt       ii,jj,s,q,d;
1426af538404SDmitry Karpeev   PetscInt       k,kk;
14272bbb417fSDmitry Karpeev   PetscMPIInt    color;
14282bbb417fSDmitry Karpeev   MPI_Comm       comm, subcomm;
14295d38c402SBarry Smith   IS             **iis = 0;
1430d34fcf5fSBarry Smith 
1431b1a0a8a3SJed Brown   PetscFunctionBegin;
14322bbb417fSDmitry Karpeev   ierr = PetscObjectGetComm((PetscObject)pc, &comm);CHKERRQ(ierr);
14332bbb417fSDmitry Karpeev   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
14342bbb417fSDmitry Karpeev   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
14352bbb417fSDmitry Karpeev   ierr = MatGetOwnershipRange(pc->pmat, &first, &last);CHKERRQ(ierr);
1436d34fcf5fSBarry 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) "
14372bbb417fSDmitry Karpeev 	     "does not respect the number of degrees of freedom per grid point %D", first, last, dof);
1438d34fcf5fSBarry Smith 
1439af538404SDmitry Karpeev   /* Determine the number of domains with nonzero intersections with the local ownership range. */
14402bbb417fSDmitry Karpeev   s = 0;
1441af538404SDmitry Karpeev   ystart = 0;
1442af538404SDmitry Karpeev   for (j=0; j<Ndomains; ++j) {
1443af538404SDmitry Karpeev     maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */
1444af538404SDmitry 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);
1445eec7e3faSDmitry Karpeev     /* Vertical domain limits with an overlap. */
1446eec7e3faSDmitry Karpeev     ylow = PetscMax(ystart - overlap,0);
1447eec7e3faSDmitry Karpeev     yhigh = PetscMin(ystart + maxheight + overlap,N);
1448b1a0a8a3SJed Brown     xstart = 0;
1449af538404SDmitry Karpeev     for (i=0; i<Mdomains; ++i) {
1450af538404SDmitry Karpeev       maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */
1451af538404SDmitry 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);
1452eec7e3faSDmitry Karpeev       /* Horizontal domain limits with an overlap. */
1453eec7e3faSDmitry Karpeev       xleft   = PetscMax(xstart - overlap,0);
1454eec7e3faSDmitry Karpeev       xright  = PetscMin(xstart + maxwidth + overlap,M);
1455af538404SDmitry Karpeev       /*
1456af538404SDmitry Karpeev 	 Determine whether this subdomain intersects this processor's ownership range of pc->pmat.
1457af538404SDmitry Karpeev       */
1458c3518bceSDmitry Karpeev       PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx));
1459af538404SDmitry Karpeev       if(nidx) {
1460af538404SDmitry Karpeev         ++s;
1461af538404SDmitry Karpeev       }
1462af538404SDmitry Karpeev       xstart += maxwidth;
1463af538404SDmitry Karpeev     }/* for(i = 0; i < Mdomains; ++i) */
1464af538404SDmitry Karpeev     ystart += maxheight;
1465af538404SDmitry Karpeev   }/* for(j = 0; j < Ndomains; ++j) */
1466af538404SDmitry Karpeev   /* Now we can allocate the necessary number of ISs. */
1467af538404SDmitry Karpeev   *nsub = s;
1468af538404SDmitry Karpeev   ierr = PetscMalloc((*nsub)*sizeof(IS*),is);CHKERRQ(ierr);
1469af538404SDmitry Karpeev   ierr = PetscMalloc((*nsub)*sizeof(IS*),is_local);CHKERRQ(ierr);
1470af538404SDmitry Karpeev   s = 0;
1471af538404SDmitry Karpeev   ystart = 0;
1472af538404SDmitry Karpeev   for (j=0; j<Ndomains; ++j) {
1473af538404SDmitry Karpeev     maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */
1474af538404SDmitry 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);
1475af538404SDmitry Karpeev     /* Vertical domain limits with an overlap. */
1476eec7e3faSDmitry Karpeev     y[0][0] = PetscMax(ystart - overlap,0);
1477eec7e3faSDmitry Karpeev     y[0][1] = PetscMin(ystart + maxheight + overlap,N);
1478eec7e3faSDmitry Karpeev     /* Vertical domain limits without an overlap. */
1479eec7e3faSDmitry Karpeev     y[1][0] = ystart;
1480eec7e3faSDmitry Karpeev     y[1][1] = PetscMin(ystart + maxheight,N);
1481eec7e3faSDmitry Karpeev     xstart = 0;
1482af538404SDmitry Karpeev     for (i=0; i<Mdomains; ++i) {
1483af538404SDmitry Karpeev       maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */
1484af538404SDmitry 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);
1485af538404SDmitry Karpeev       /* Horizontal domain limits with an overlap. */
1486eec7e3faSDmitry Karpeev       x[0][0]  = PetscMax(xstart - overlap,0);
1487eec7e3faSDmitry Karpeev       x[0][1]  = PetscMin(xstart + maxwidth + overlap,M);
1488eec7e3faSDmitry Karpeev       /* Horizontal domain limits without an overlap. */
1489eec7e3faSDmitry Karpeev       x[1][0] = xstart;
1490eec7e3faSDmitry Karpeev       x[1][1] = PetscMin(xstart+maxwidth,M);
14912bbb417fSDmitry Karpeev       /*
14922bbb417fSDmitry Karpeev 	 Determine whether this domain intersects this processor's ownership range of pc->pmat.
14932bbb417fSDmitry Karpeev 	 Do this twice: first for the domains with overlaps, and once without.
14942bbb417fSDmitry Karpeev 	 During the first pass create the subcommunicators, and use them on the second pass as well.
14952bbb417fSDmitry Karpeev       */
14962bbb417fSDmitry Karpeev       for(q = 0; q < 2; ++q) {
14972bbb417fSDmitry Karpeev 	/*
14982bbb417fSDmitry Karpeev 	  domain limits, (xleft, xright) and (ylow, yheigh) are adjusted
14992bbb417fSDmitry Karpeev 	  according to whether the domain with an overlap or without is considered.
15002bbb417fSDmitry Karpeev 	*/
15012bbb417fSDmitry Karpeev 	xleft = x[q][0]; xright = x[q][1];
15022bbb417fSDmitry Karpeev 	ylow  = y[q][0]; yhigh  = y[q][1];
1503c3518bceSDmitry Karpeev         PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx));
1504af538404SDmitry Karpeev 	nidx *= dof;
1505eec7e3faSDmitry Karpeev         n[q] = nidx;
15062bbb417fSDmitry Karpeev         /*
1507eec7e3faSDmitry Karpeev          Based on the counted number of indices in the local domain *with an overlap*,
1508af538404SDmitry Karpeev          construct a subcommunicator of all the processors supporting this domain.
1509eec7e3faSDmitry Karpeev          Observe that a domain with an overlap might have nontrivial local support,
1510eec7e3faSDmitry Karpeev          while the domain without an overlap might not.  Hence, the decision to participate
1511eec7e3faSDmitry Karpeev          in the subcommunicator must be based on the domain with an overlap.
15122bbb417fSDmitry Karpeev          */
15132bbb417fSDmitry Karpeev 	if (q == 0) {
15142bbb417fSDmitry Karpeev 	  if(nidx) {
15152bbb417fSDmitry Karpeev 	    color = 1;
1516d34fcf5fSBarry Smith 	  } else {
15172bbb417fSDmitry Karpeev 	    color = MPI_UNDEFINED;
15182bbb417fSDmitry Karpeev 	  }
15192bbb417fSDmitry Karpeev 	  ierr = MPI_Comm_split(comm, color, rank, &subcomm);CHKERRQ(ierr);
15202bbb417fSDmitry Karpeev 	}
1521af538404SDmitry Karpeev         /*
1522eec7e3faSDmitry Karpeev          Proceed only if the number of local indices *with an overlap* is nonzero.
1523af538404SDmitry Karpeev          */
1524eec7e3faSDmitry Karpeev         if (n[0]) {
1525af538404SDmitry Karpeev           if(q == 0) {
1526eec7e3faSDmitry Karpeev             iis = is;
1527af538404SDmitry Karpeev           }
1528af538404SDmitry Karpeev           if (q == 1) {
1529af538404SDmitry Karpeev             /*
1530eec7e3faSDmitry Karpeev              The IS for the no-overlap subdomain shares a communicator with the overlapping domain.
1531af538404SDmitry Karpeev              Moreover, if the overlap is zero, the two ISs are identical.
1532af538404SDmitry Karpeev              */
1533b1a0a8a3SJed Brown             if (overlap == 0) {
1534eec7e3faSDmitry Karpeev               (*is_local)[s] = (*is)[s];
15352bbb417fSDmitry Karpeev               ierr = PetscObjectReference((PetscObject)(*is)[s]);CHKERRQ(ierr);
15362bbb417fSDmitry Karpeev               continue;
1537d34fcf5fSBarry Smith             } else {
1538eec7e3faSDmitry Karpeev               iis = is_local;
1539eec7e3faSDmitry Karpeev               subcomm = ((PetscObject)(*is)[s])->comm;
15402bbb417fSDmitry Karpeev             }
1541af538404SDmitry Karpeev           }/* if(q == 1) */
1542eec7e3faSDmitry Karpeev           idx = PETSC_NULL;
15432bbb417fSDmitry Karpeev 	  ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1544eec7e3faSDmitry Karpeev           if(nidx) {
15452bbb417fSDmitry Karpeev             k    = 0;
15462bbb417fSDmitry Karpeev             for (jj=ylow_loc; jj<yhigh_loc; ++jj) {
1547af538404SDmitry Karpeev               PetscInt x0 = (jj==ylow_loc)?xleft_loc:xleft;
1548af538404SDmitry Karpeev               PetscInt x1 = (jj==yhigh_loc-1)?xright_loc:xright;
1549af538404SDmitry Karpeev               kk = dof*(M*jj + x0);
15502bbb417fSDmitry Karpeev               for (ii=x0; ii<x1; ++ii) {
15512bbb417fSDmitry Karpeev                 for(d = 0; d < dof; ++d) {
15522bbb417fSDmitry Karpeev                   idx[k++] = kk++;
1553b1a0a8a3SJed Brown                 }
1554b1a0a8a3SJed Brown               }
1555b1a0a8a3SJed Brown             }
1556eec7e3faSDmitry Karpeev           }
15572bbb417fSDmitry Karpeev 	  ierr = ISCreateGeneral(subcomm,nidx,idx,PETSC_OWN_POINTER,(*iis)+s);CHKERRQ(ierr);
1558eec7e3faSDmitry Karpeev 	}/* if(n[0]) */
15592bbb417fSDmitry Karpeev       }/* for(q = 0; q < 2; ++q) */
1560eec7e3faSDmitry Karpeev       if(n[0]) {
15612bbb417fSDmitry Karpeev         ++s;
1562b1a0a8a3SJed Brown       }
1563af538404SDmitry Karpeev       xstart += maxwidth;
1564af538404SDmitry Karpeev     }/* for(i = 0; i < Mdomains; ++i) */
15652bbb417fSDmitry Karpeev     ystart += maxheight;
1566af538404SDmitry Karpeev   }/* for(j = 0; j < Ndomains; ++j) */
1567b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1568b1a0a8a3SJed Brown }
1569b1a0a8a3SJed Brown 
1570b1a0a8a3SJed Brown #undef __FUNCT__
1571f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubdomains"
1572b1a0a8a3SJed Brown /*@C
1573f746d493SDmitry Karpeev     PCGASMGetLocalSubdomains - Gets the local subdomains (for this processor
1574b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1575b1a0a8a3SJed Brown 
1576b1a0a8a3SJed Brown     Not Collective
1577b1a0a8a3SJed Brown 
1578b1a0a8a3SJed Brown     Input Parameter:
1579b1a0a8a3SJed Brown .   pc - the preconditioner context
1580b1a0a8a3SJed Brown 
1581b1a0a8a3SJed Brown     Output Parameters:
1582b1a0a8a3SJed Brown +   n - the number of subdomains for this processor (default value = 1)
1583b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for this processor
1584b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor (can be PETSC_NULL)
1585b1a0a8a3SJed Brown 
1586b1a0a8a3SJed Brown 
1587b1a0a8a3SJed Brown     Notes:
1588b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
1589b1a0a8a3SJed Brown 
1590b1a0a8a3SJed Brown     Level: advanced
1591b1a0a8a3SJed Brown 
1592f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
1593b1a0a8a3SJed Brown 
1594f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1595f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubmatrices()
1596b1a0a8a3SJed Brown @*/
15977087cfbeSBarry Smith PetscErrorCode  PCGASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[])
1598b1a0a8a3SJed Brown {
1599f746d493SDmitry Karpeev   PC_GASM         *osm;
1600b1a0a8a3SJed Brown   PetscErrorCode ierr;
1601b1a0a8a3SJed Brown   PetscBool      match;
1602b1a0a8a3SJed Brown 
1603b1a0a8a3SJed Brown   PetscFunctionBegin;
1604b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1605b1a0a8a3SJed Brown   PetscValidIntPointer(n,2);
1606b1a0a8a3SJed Brown   if (is) PetscValidPointer(is,3);
1607f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1608b1a0a8a3SJed Brown   if (!match) {
1609b1a0a8a3SJed Brown     if (n)  *n  = 0;
1610b1a0a8a3SJed Brown     if (is) *is = PETSC_NULL;
1611b1a0a8a3SJed Brown   } else {
1612f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1613ab3e923fSDmitry Karpeev     if (n)  *n  = osm->n;
1614b1a0a8a3SJed Brown     if (is) *is = osm->is;
1615b1a0a8a3SJed Brown     if (is_local) *is_local = osm->is_local;
1616b1a0a8a3SJed Brown   }
1617b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1618b1a0a8a3SJed Brown }
1619b1a0a8a3SJed Brown 
1620b1a0a8a3SJed Brown #undef __FUNCT__
1621f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubmatrices"
1622b1a0a8a3SJed Brown /*@C
1623f746d493SDmitry Karpeev     PCGASMGetLocalSubmatrices - Gets the local submatrices (for this processor
1624b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1625b1a0a8a3SJed Brown 
1626b1a0a8a3SJed Brown     Not Collective
1627b1a0a8a3SJed Brown 
1628b1a0a8a3SJed Brown     Input Parameter:
1629b1a0a8a3SJed Brown .   pc - the preconditioner context
1630b1a0a8a3SJed Brown 
1631b1a0a8a3SJed Brown     Output Parameters:
1632b1a0a8a3SJed Brown +   n - the number of matrices for this processor (default value = 1)
1633b1a0a8a3SJed Brown -   mat - the matrices
1634b1a0a8a3SJed Brown 
1635b1a0a8a3SJed Brown 
1636b1a0a8a3SJed Brown     Level: advanced
1637b1a0a8a3SJed Brown 
1638f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz, block Jacobi
1639b1a0a8a3SJed Brown 
1640f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1641f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubdomains()
1642b1a0a8a3SJed Brown @*/
16437087cfbeSBarry Smith PetscErrorCode  PCGASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[])
1644b1a0a8a3SJed Brown {
1645f746d493SDmitry Karpeev   PC_GASM         *osm;
1646b1a0a8a3SJed Brown   PetscErrorCode ierr;
1647b1a0a8a3SJed Brown   PetscBool      match;
1648b1a0a8a3SJed Brown 
1649b1a0a8a3SJed Brown   PetscFunctionBegin;
1650b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1651b1a0a8a3SJed Brown   PetscValidIntPointer(n,2);
1652b1a0a8a3SJed Brown   if (mat) PetscValidPointer(mat,3);
1653b1a0a8a3SJed Brown   if (!pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp().");
1654f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1655b1a0a8a3SJed Brown   if (!match) {
1656b1a0a8a3SJed Brown     if (n)   *n   = 0;
1657b1a0a8a3SJed Brown     if (mat) *mat = PETSC_NULL;
1658b1a0a8a3SJed Brown   } else {
1659f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1660ab3e923fSDmitry Karpeev     if (n)   *n   = osm->n;
1661b1a0a8a3SJed Brown     if (mat) *mat = osm->pmat;
1662b1a0a8a3SJed Brown   }
1663b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1664b1a0a8a3SJed Brown }
1665