xref: /petsc/src/ksp/pc/impls/gasm/gasm.c (revision f746d493859b98ed4db71345f1a8e48bd86b1a81)
1b1a0a8a3SJed Brown #define PETSCKSP_DLL
2b1a0a8a3SJed Brown 
3b1a0a8a3SJed Brown /*
4*f746d493SDmitry Karpeev   This file defines an "generalized" additive Schwarz preconditioner for any Mat implementation.
5*f746d493SDmitry Karpeev   Note that each processor may have any number of subdomains and a subdomain may live on multiple
6*f746d493SDmitry Karpeev   processors.
7b1a0a8a3SJed Brown 
8*f746d493SDmitry Karpeev        N    - total number of true subdomains on all processors
9*f746d493SDmitry Karpeev        n    - actual number of subdomains on this processor
10*f746d493SDmitry Karpeev        nmax - maximum number of subdomains per processor
11b1a0a8a3SJed Brown */
12b1a0a8a3SJed Brown #include "private/pcimpl.h"     /*I "petscpc.h" I*/
13b1a0a8a3SJed Brown 
14b1a0a8a3SJed Brown typedef struct {
15*f746d493SDmitry Karpeev   PetscInt   N,n,nmax;
16b1a0a8a3SJed Brown   PetscInt   overlap;             /* overlap requested by user */
17b1a0a8a3SJed Brown   KSP        *ksp;                /* linear solvers for each block */
18*f746d493SDmitry Karpeev   Vec        gx,gy;               /* Merged work vectors */
19*f746d493SDmitry Karpeev   Vec        *x,*y;               /* Split work vectors; storage aliases pieces of storage of the above merged vectors. */
20*f746d493SDmitry Karpeev   IS         gis, gis_local;      /* merged ISs */
21*f746d493SDmitry Karpeev   VecScatter grestriction;        /* merged restriction */
22*f746d493SDmitry Karpeev   VecScatter gprolongation;       /* merged prolongation */
23b1a0a8a3SJed Brown   IS         *is;                 /* index set that defines each overlapping subdomain */
24*f746d493SDmitry Karpeev   IS         *is_local;           /* index set that defines each local subdomain (same as subdomain with the overlap removed); may be NULL */
25*f746d493SDmitry Karpeev   Mat        *pmat;               /* subdomain block matrices */
26*f746d493SDmitry Karpeev   PCGASMType  type;               /* use reduced interpolation, restriction or both */
27b1a0a8a3SJed Brown   PetscBool  type_set;            /* if user set this value (so won't change it for symmetric problems) */
28b1a0a8a3SJed Brown   PetscBool  same_local_solves;   /* flag indicating whether all local solvers are same */
29b1a0a8a3SJed Brown   PetscBool  sort_indices;        /* flag to sort subdomain indices */
30*f746d493SDmitry Karpeev } PC_GASM;
31b1a0a8a3SJed Brown 
32b1a0a8a3SJed Brown #undef __FUNCT__
33*f746d493SDmitry Karpeev #define __FUNCT__ "PCView_GASM"
34*f746d493SDmitry Karpeev static PetscErrorCode PCView_GASM(PC pc,PetscViewer viewer)
35b1a0a8a3SJed Brown {
36*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
37b1a0a8a3SJed Brown   PetscErrorCode ierr;
38b1a0a8a3SJed Brown   PetscMPIInt    rank;
39b1a0a8a3SJed Brown   PetscInt       i,bsz;
40b1a0a8a3SJed Brown   PetscBool      iascii,isstring;
41b1a0a8a3SJed Brown   PetscViewer    sviewer;
42b1a0a8a3SJed Brown 
43b1a0a8a3SJed Brown 
44b1a0a8a3SJed Brown   PetscFunctionBegin;
45b1a0a8a3SJed Brown   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
46b1a0a8a3SJed Brown   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr);
47b1a0a8a3SJed Brown   if (iascii) {
48b1a0a8a3SJed Brown     char overlaps[256] = "user-defined overlap",blocks[256] = "total subdomain blocks not yet set";
49b1a0a8a3SJed Brown     if (osm->overlap >= 0) {ierr = PetscSNPrintf(overlaps,sizeof overlaps,"amount of overlap = %D",osm->overlap);CHKERRQ(ierr);}
50*f746d493SDmitry Karpeev     if (osm->n > 0) {ierr = PetscSNPrintf(blocks,sizeof blocks,"max number of  subdomain blocks = %D",osm->nmax);CHKERRQ(ierr);}
51*f746d493SDmitry Karpeev     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"  [%d] number of local blocks = %D\n",(int)rank,osm->n);CHKERRQ(ierr);
52*f746d493SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer,"  Generalized additive Schwarz: %s, %s\n",blocks,overlaps);CHKERRQ(ierr);
53*f746d493SDmitry Karpeev     ierr = PetscViewerASCIIPrintf(viewer,"  Generalized additive Schwarz: restriction/interpolation type - %s\n",PCGASMTypes[osm->type]);CHKERRQ(ierr);
54b1a0a8a3SJed Brown     ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
55b1a0a8a3SJed Brown     if (osm->same_local_solves) {
56b1a0a8a3SJed Brown       if (osm->ksp) {
57b1a0a8a3SJed Brown         ierr = PetscViewerASCIIPrintf(viewer,"  Local solve is same for all blocks, in the following KSP and PC objects:\n");CHKERRQ(ierr);
58b1a0a8a3SJed Brown         ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
59b1a0a8a3SJed Brown         if (!rank) {
60b1a0a8a3SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
61b1a0a8a3SJed Brown           ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);
62b1a0a8a3SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
63b1a0a8a3SJed Brown         }
64b1a0a8a3SJed Brown         ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
65b1a0a8a3SJed Brown       }
66b1a0a8a3SJed Brown     } else {
67b1a0a8a3SJed Brown       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
68b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"  Local solve info for each block is in the following KSP and PC objects:\n");CHKERRQ(ierr);
69b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
70b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr);
71*f746d493SDmitry Karpeev       for (i=0; i<osm->nmax; i++) {
72b1a0a8a3SJed Brown         ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
73*f746d493SDmitry Karpeev         if (i < osm->n) {
74b1a0a8a3SJed Brown           ierr = ISGetLocalSize(osm->is[i],&bsz);CHKERRQ(ierr);
75b1a0a8a3SJed Brown           ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"[%d] local block number %D, size = %D\n",(int)rank,i,bsz);CHKERRQ(ierr);
76b1a0a8a3SJed Brown           ierr = KSPView(osm->ksp[i],sviewer);CHKERRQ(ierr);
77b1a0a8a3SJed Brown           ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr);
78b1a0a8a3SJed Brown         }
79b1a0a8a3SJed Brown         ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
80b1a0a8a3SJed Brown       }
81b1a0a8a3SJed Brown       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
82b1a0a8a3SJed Brown       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
83b1a0a8a3SJed Brown     }
84b1a0a8a3SJed Brown   } else if (isstring) {
85*f746d493SDmitry Karpeev     ierr = PetscViewerStringSPrintf(viewer," blocks=%D, overlap=%D, type=%s",osm->n,osm->overlap,PCGASMTypes[osm->type]);CHKERRQ(ierr);
86b1a0a8a3SJed Brown     ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
87b1a0a8a3SJed Brown     if (osm->ksp) {ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);}
88b1a0a8a3SJed Brown     ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
89b1a0a8a3SJed Brown   } else {
90*f746d493SDmitry Karpeev     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCGASM",((PetscObject)viewer)->type_name);
91b1a0a8a3SJed Brown   }
92b1a0a8a3SJed Brown   PetscFunctionReturn(0);
93b1a0a8a3SJed Brown }
94b1a0a8a3SJed Brown 
95b1a0a8a3SJed Brown #undef __FUNCT__
96*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMPrintSubdomains"
97*f746d493SDmitry Karpeev static PetscErrorCode PCGASMPrintSubdomains(PC pc)
98b1a0a8a3SJed Brown {
99*f746d493SDmitry Karpeev   PC_GASM         *osm  = (PC_GASM*)pc->data;
100b1a0a8a3SJed Brown   const char     *prefix;
101b1a0a8a3SJed Brown   char           fname[PETSC_MAX_PATH_LEN+1];
102b1a0a8a3SJed Brown   PetscViewer    viewer;
103b1a0a8a3SJed Brown   PetscInt       i,j,nidx;
104b1a0a8a3SJed Brown   const PetscInt *idx;
105b1a0a8a3SJed Brown   PetscErrorCode ierr;
106b1a0a8a3SJed Brown 
107b1a0a8a3SJed Brown   PetscFunctionBegin;
108b1a0a8a3SJed Brown   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
109*f746d493SDmitry Karpeev   ierr = PetscOptionsGetString(prefix,"-pc_gasm_print_subdomains",fname,PETSC_MAX_PATH_LEN,PETSC_NULL);CHKERRQ(ierr);
110b1a0a8a3SJed Brown   if (fname[0] == 0) { ierr = PetscStrcpy(fname,"stdout");CHKERRQ(ierr); };
111b1a0a8a3SJed Brown   ierr = PetscViewerASCIIOpen(((PetscObject)pc)->comm,fname,&viewer);CHKERRQ(ierr);
112*f746d493SDmitry Karpeev   for (i=0;i<osm->n;++i) {
113b1a0a8a3SJed Brown     ierr = ISGetLocalSize(osm->is[i],&nidx);CHKERRQ(ierr);
114b1a0a8a3SJed Brown     ierr = ISGetIndices(osm->is[i],&idx);CHKERRQ(ierr);
115b1a0a8a3SJed Brown     for (j=0; j<nidx; j++) {
116b1a0a8a3SJed Brown       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"%D ",idx[j]);CHKERRQ(ierr);
117b1a0a8a3SJed Brown     }
118b1a0a8a3SJed Brown     ierr = ISRestoreIndices(osm->is[i],&idx);CHKERRQ(ierr);
119b1a0a8a3SJed Brown     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
120b1a0a8a3SJed Brown     if (osm->is_local) {
121b1a0a8a3SJed Brown       ierr = ISGetLocalSize(osm->is_local[i],&nidx);CHKERRQ(ierr);
122b1a0a8a3SJed Brown       ierr = ISGetIndices(osm->is_local[i],&idx);CHKERRQ(ierr);
123b1a0a8a3SJed Brown       for (j=0; j<nidx; j++) {
124b1a0a8a3SJed Brown         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"%D ",idx[j]);CHKERRQ(ierr);
125b1a0a8a3SJed Brown       }
126b1a0a8a3SJed Brown       ierr = ISRestoreIndices(osm->is_local[i],&idx);CHKERRQ(ierr);
127b1a0a8a3SJed Brown       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
128b1a0a8a3SJed Brown     }
129b1a0a8a3SJed Brown   }
130b1a0a8a3SJed Brown   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
131b1a0a8a3SJed Brown   ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr);
132b1a0a8a3SJed Brown   PetscFunctionReturn(0);
133b1a0a8a3SJed Brown }
134b1a0a8a3SJed Brown 
135b1a0a8a3SJed Brown #undef __FUNCT__
136*f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUp_GASM"
137*f746d493SDmitry Karpeev static PetscErrorCode PCSetUp_GASM(PC pc)
138b1a0a8a3SJed Brown {
139*f746d493SDmitry Karpeev   PC_GASM         *osm  = (PC_GASM*)pc->data;
140b1a0a8a3SJed Brown   PetscErrorCode ierr;
141b1a0a8a3SJed Brown   PetscBool      symset,flg;
142*f746d493SDmitry Karpeev   PetscInt       i,firstRow,lastRow;
143b1a0a8a3SJed Brown   PetscMPIInt    size;
144b1a0a8a3SJed Brown   MatReuse       scall = MAT_REUSE_MATRIX;
145b1a0a8a3SJed Brown   KSP            ksp;
146b1a0a8a3SJed Brown   PC             subpc;
147b1a0a8a3SJed Brown   const char     *prefix,*pprefix;
148*f746d493SDmitry Karpeev   PetscInt       dn;       /* Number of indices in a single subdomain assigned to this processor. */
149*f746d493SDmitry Karpeev   const PetscInt *didx;    /* Indices from a single subdomain assigned to this processor. */
150*f746d493SDmitry Karpeev   PetscInt       ddn;      /* Number of indices in all subdomains assigned to this processor. */
151*f746d493SDmitry Karpeev   PetscInt       *ddidx;   /* Indices of all subdomains assigned to this processor. */
152*f746d493SDmitry Karpeev   IS             gid;      /* Identity IS of the size of all subdomains assigned to this processor. */
153*f746d493SDmitry Karpeev   Vec            x,y;
154*f746d493SDmitry Karpeev   PetscScalar    *gxarray, *gyarray;
155*f746d493SDmitry Karpeev   IS             *is;
156b1a0a8a3SJed Brown 
157b1a0a8a3SJed Brown   PetscFunctionBegin;
158b1a0a8a3SJed Brown   if (!pc->setupcalled) {
159b1a0a8a3SJed Brown 
160b1a0a8a3SJed Brown     if (!osm->type_set) {
161b1a0a8a3SJed Brown       ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr);
162*f746d493SDmitry Karpeev       if (symset && flg) { osm->type = PC_GASM_BASIC; }
163b1a0a8a3SJed Brown     }
164b1a0a8a3SJed Brown 
165*f746d493SDmitry Karpeev     if (osm->n == PETSC_DECIDE) {
166b1a0a8a3SJed Brown       /* no subdomains given, use one per processor */
167*f746d493SDmitry Karpeev       osm->n = 1;
168b1a0a8a3SJed Brown       ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
169*f746d493SDmitry Karpeev       osm->N = size;
170*f746d493SDmitry Karpeev     } else if (osm->N == PETSC_DECIDE) {
171b1a0a8a3SJed Brown       PetscInt inwork[2], outwork[2];
172*f746d493SDmitry Karpeev       /* determine global number of subdomains and the max number of local subdomains */
173*f746d493SDmitry Karpeev       inwork[0] = inwork[1] = osm->n;
174b1a0a8a3SJed Brown       ierr = MPI_Allreduce(inwork,outwork,1,MPIU_2INT,PetscMaxSum_Op,((PetscObject)pc)->comm);CHKERRQ(ierr);
175*f746d493SDmitry Karpeev       osm->nmax = outwork[0];
176*f746d493SDmitry Karpeev       osm->N    = outwork[1];
177b1a0a8a3SJed Brown     }
178b1a0a8a3SJed Brown     if (!osm->is){ /* create the index sets */
179*f746d493SDmitry Karpeev       ierr = PCGASMCreateSubdomains(pc->pmat,osm->n,&osm->is);CHKERRQ(ierr);
180b1a0a8a3SJed Brown     }
181*f746d493SDmitry Karpeev     if (osm->n > 1 && !osm->is_local) {
182*f746d493SDmitry Karpeev       ierr = PetscMalloc(osm->n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
183*f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
184b1a0a8a3SJed Brown         if (osm->overlap > 0) { /* With positive overlap, osm->is[i] will be modified */
185b1a0a8a3SJed Brown           ierr = ISDuplicate(osm->is[i],&osm->is_local[i]);CHKERRQ(ierr);
186b1a0a8a3SJed Brown           ierr = ISCopy(osm->is[i],osm->is_local[i]);CHKERRQ(ierr);
187b1a0a8a3SJed Brown         } else {
188b1a0a8a3SJed Brown           ierr = PetscObjectReference((PetscObject)osm->is[i]);CHKERRQ(ierr);
189b1a0a8a3SJed Brown           osm->is_local[i] = osm->is[i];
190b1a0a8a3SJed Brown         }
191b1a0a8a3SJed Brown       }
192b1a0a8a3SJed Brown     }
193b1a0a8a3SJed Brown     ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
194b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
195*f746d493SDmitry Karpeev     ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&flg,PETSC_NULL);CHKERRQ(ierr);
196*f746d493SDmitry Karpeev     if (flg) { ierr = PCGASMPrintSubdomains(pc);CHKERRQ(ierr); }
197b1a0a8a3SJed Brown 
198b1a0a8a3SJed Brown     if (osm->overlap > 0) {
199b1a0a8a3SJed Brown       /* Extend the "overlapping" regions by a number of steps */
200*f746d493SDmitry Karpeev       ierr = MatIncreaseOverlap(pc->pmat,osm->n,osm->is,osm->overlap);CHKERRQ(ierr);
201b1a0a8a3SJed Brown     }
202b1a0a8a3SJed Brown     if (osm->sort_indices) {
203*f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
204b1a0a8a3SJed Brown         ierr = ISSort(osm->is[i]);CHKERRQ(ierr);
205b1a0a8a3SJed Brown         if (osm->is_local) {
206b1a0a8a3SJed Brown           ierr = ISSort(osm->is_local[i]);CHKERRQ(ierr);
207b1a0a8a3SJed Brown         }
208b1a0a8a3SJed Brown       }
209b1a0a8a3SJed Brown     }
210*f746d493SDmitry Karpeev     /* Merge the ISs, create merged vectors and scatter contexts. */
211*f746d493SDmitry Karpeev     /* Domain IS. */
212*f746d493SDmitry Karpeev     ddn = 0;
213*f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
214*f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);          CHKERRQ(ierr);
215*f746d493SDmitry Karpeev       ddn += dn;
216*f746d493SDmitry Karpeev     }
217*f746d493SDmitry Karpeev     ierr = PetscMalloc(ddn*sizeof(PetscInt), &ddidx); CHKERRQ(ierr);
218*f746d493SDmitry Karpeev     ddn = 0;
219*f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
220*f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn); CHKERRQ(ierr);
221*f746d493SDmitry Karpeev       ierr = ISGetIndices(osm->is[i],&didx); CHKERRQ(ierr);
222*f746d493SDmitry Karpeev       ierr = PetscMemcpy(ddidx+ddn, didx, sizeof(PetscInt)*dn); CHKERRQ(ierr);
223*f746d493SDmitry Karpeev       ierr = ISRestoreIndices(osm->is[i], &didx); CHKERRQ(ierr);
224*f746d493SDmitry Karpeev     }
225*f746d493SDmitry Karpeev     ierr = ISCreateGeneral(((PetscObject)(pc))->comm, ddn, ddidx, PETSC_OWN_POINTER, &osm->gis); CHKERRQ(ierr);
226*f746d493SDmitry Karpeev     ierr = MatGetVecs(pc->pmat,&x,&y);CHKERRQ(ierr);
227*f746d493SDmitry Karpeev     ierr = VecCreateMPI(((PetscObject)pc)->comm, ddn, PETSC_DECIDE, &osm->gx); CHKERRQ(ierr);
228*f746d493SDmitry Karpeev     ierr = VecDuplicate(osm->gx,&osm->gy);                                     CHKERRQ(ierr);
229*f746d493SDmitry Karpeev     ierr = ISCreateStride(((PetscObject)pc)->comm,ddn,0,1, &gid);              CHKERRQ(ierr);
230*f746d493SDmitry Karpeev     ierr = VecScatterCreate(x,osm->gis,osm->gx,gid, &(osm->grestriction));   CHKERRQ(ierr);
231*f746d493SDmitry Karpeev     ierr = ISDestroy(gid);                                                     CHKERRQ(ierr);
232*f746d493SDmitry Karpeev     /* Local domain IS */
233*f746d493SDmitry Karpeev     if(osm->is_local) { /* All ranks either have this or not, so collective calls within this branch are okay. */
234*f746d493SDmitry Karpeev       PetscInt       dn_local;       /* Number of indices in the local part of single domain assigned to this processor. */
235*f746d493SDmitry Karpeev       const PetscInt *didx_local;    /* Global indices from the local part of a single domain assigned to this processor. */
236*f746d493SDmitry Karpeev       PetscInt       ddn_local;      /* Number of indices in the local part of the disjoint union all domains assigned to this processor. */
237*f746d493SDmitry Karpeev       PetscInt       *ddidx_local;  /* Global indices of the local part of the disjoint union of all domains assigned to this processor. */
238*f746d493SDmitry Karpeev       /**/
239*f746d493SDmitry Karpeev       ISLocalToGlobalMapping ltog;          /* Mapping from global to local indices on the disjoint union of subdomains: local run from 0 to ddn-1. */
240*f746d493SDmitry Karpeev       PetscInt              *ddidx_llocal;  /* Local (within disjoint union of subdomains) indices of the disjoint union of local parts of subdomains. */
241*f746d493SDmitry 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. */
242*f746d493SDmitry Karpeev       IS                     gis_llocal;    /* IS with ddidx_llocal indices. */
243*f746d493SDmitry Karpeev       PetscInt               j;
244*f746d493SDmitry Karpeev       ddn_local = 0;
245*f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
246*f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local); CHKERRQ(ierr);
247*f746d493SDmitry Karpeev 	ddn_local += dn_local;
248*f746d493SDmitry Karpeev       }
249*f746d493SDmitry Karpeev       ierr = PetscMalloc(ddn_local*sizeof(PetscInt), &ddidx_local); CHKERRQ(ierr);
250*f746d493SDmitry Karpeev       ddn_local = 0;
251*f746d493SDmitry Karpeev       for (i=0; i<osm->n; i++) {
252*f746d493SDmitry Karpeev 	ierr = ISGetLocalSize(osm->is_local[i],&dn_local); CHKERRQ(ierr);
253*f746d493SDmitry Karpeev 	ierr = ISGetIndices(osm->is_local[i],&didx_local); CHKERRQ(ierr);
254*f746d493SDmitry Karpeev 	ierr = PetscMemcpy(ddidx_local+ddn_local, didx_local, sizeof(PetscInt)*dn_local); CHKERRQ(ierr);
255*f746d493SDmitry Karpeev 	ierr = ISRestoreIndices(osm->is_local[i], &didx_local); CHKERRQ(ierr);
256*f746d493SDmitry Karpeev 	ddn_local += dn_local;
257*f746d493SDmitry Karpeev       }
258*f746d493SDmitry Karpeev       ierr = VecGetOwnershipRange(y, &firstRow, &lastRow); CHKERRQ(ierr);
259*f746d493SDmitry Karpeev       if(ddn_local != lastRow-firstRow) {
260*f746d493SDmitry Karpeev 	SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Specified local domains of total size %D do not cover the local vector range [%D,%D)",
261*f746d493SDmitry Karpeev 		 ddn_local, firstRow, lastRow);
262*f746d493SDmitry Karpeev       }
263*f746d493SDmitry Karpeev       ierr = ISCreateGeneral(((PetscObject)pc)->comm, ddn_local, ddidx_local, PETSC_OWN_POINTER, &(osm->gis_local)); CHKERRQ(ierr);
264*f746d493SDmitry Karpeev       ierr = ISLocalToGlobalMappingCreateIS(osm->gis,&ltog);CHKERRQ(ierr);
265*f746d493SDmitry Karpeev       ierr = ISGlobalToLocalMappingApply(ltog,IS_GTOLM_DROP,dn_local,ddidx_local,&ddn_llocal,ddidx_llocal);CHKERRQ(ierr);
266b1a0a8a3SJed Brown       ierr = ISLocalToGlobalMappingDestroy(ltog);CHKERRQ(ierr);
267*f746d493SDmitry Karpeev       if (ddn_llocal != ddn_local) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"gis_local contains %D nonlocal indices", ddn_llocal - ddn_local);
268*f746d493SDmitry Karpeev       /* Now convert these localized indices into the global indices into the merged output vector. */
269*f746d493SDmitry Karpeev       ierr = VecGetOwnershipRange(osm->gy, &firstRow, &lastRow); CHKERRQ(ierr);
270*f746d493SDmitry Karpeev       for(j=0; j < ddn_llocal; ++j) {
271*f746d493SDmitry Karpeev 	ddidx_llocal[j] += firstRow;
272*f746d493SDmitry Karpeev       }
273*f746d493SDmitry Karpeev       ierr = ISCreateGeneral(PETSC_COMM_SELF,ddn_llocal,ddidx_llocal,PETSC_OWN_POINTER,&gis_llocal); CHKERRQ(ierr);
274*f746d493SDmitry Karpeev       ierr = VecScatterCreate(y,osm->gis_local,osm->gy,gis_llocal,&osm->gprolongation);              CHKERRQ(ierr);
275*f746d493SDmitry Karpeev       ierr = ISDestroy(gis_llocal);CHKERRQ(ierr);
276b1a0a8a3SJed Brown 
277b1a0a8a3SJed Brown     }
278*f746d493SDmitry Karpeev     /* Create the subdomain work vectors. */
279*f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->x);CHKERRQ(ierr);
280*f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->y);CHKERRQ(ierr);
281*f746d493SDmitry Karpeev     ierr = VecGetOwnershipRange(osm->gx, &firstRow, &lastRow);CHKERRQ(ierr);
282*f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gx, &gxarray);                                     CHKERRQ(ierr);
283*f746d493SDmitry Karpeev     ierr = VecGetArray(osm->gy, &gyarray);                                     CHKERRQ(ierr);
284*f746d493SDmitry Karpeev     for (i=0, ddn=0; i<osm->n; ++i, ddn += dn) {
285*f746d493SDmitry Karpeev       ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr);
286*f746d493SDmitry Karpeev       ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,dn,gxarray+ddn,&osm->x[i]);CHKERRQ(ierr);
287*f746d493SDmitry Karpeev       ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,dn,gyarray+ddn,&osm->y[i]);CHKERRQ(ierr);
288b1a0a8a3SJed Brown     }
289*f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gx, &gxarray); CHKERRQ(ierr);
290*f746d493SDmitry Karpeev     ierr = VecRestoreArray(osm->gy, &gyarray); CHKERRQ(ierr);
291*f746d493SDmitry Karpeev     ierr = VecDestroy(x); CHKERRQ(ierr);
292*f746d493SDmitry Karpeev     ierr = VecDestroy(y); CHKERRQ(ierr);
293b1a0a8a3SJed Brown     /* Create the local solvers */
294*f746d493SDmitry Karpeev     ierr = PetscMalloc(osm->n*sizeof(KSP *),&osm->ksp);CHKERRQ(ierr);
295*f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
296b1a0a8a3SJed Brown       ierr = KSPCreate(PETSC_COMM_SELF,&ksp);CHKERRQ(ierr);
297b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,ksp);CHKERRQ(ierr);
298b1a0a8a3SJed Brown       ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1);CHKERRQ(ierr);
299b1a0a8a3SJed Brown       ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr);
300b1a0a8a3SJed Brown       ierr = KSPGetPC(ksp,&subpc);CHKERRQ(ierr);
301b1a0a8a3SJed Brown       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
302b1a0a8a3SJed Brown       ierr = KSPSetOptionsPrefix(ksp,prefix);CHKERRQ(ierr);
303b1a0a8a3SJed Brown       ierr = KSPAppendOptionsPrefix(ksp,"sub_");CHKERRQ(ierr);
304b1a0a8a3SJed Brown       osm->ksp[i] = ksp;
305b1a0a8a3SJed Brown     }
306b1a0a8a3SJed Brown     scall = MAT_INITIAL_MATRIX;
307b1a0a8a3SJed Brown 
308b1a0a8a3SJed Brown   } else {
309b1a0a8a3SJed Brown     /*
310b1a0a8a3SJed Brown        Destroy the blocks from the previous iteration
311b1a0a8a3SJed Brown     */
312b1a0a8a3SJed Brown     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
313*f746d493SDmitry Karpeev       ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr);
314b1a0a8a3SJed Brown       scall = MAT_INITIAL_MATRIX;
315b1a0a8a3SJed Brown     }
316b1a0a8a3SJed Brown   }
317b1a0a8a3SJed Brown 
318b1a0a8a3SJed Brown   /*
319*f746d493SDmitry Karpeev      Extract out the submatrices.
320*f746d493SDmitry Karpeev      Here we need to use the same number of submatrices per processor across the whole comm,
321*f746d493SDmitry Karpeev      since we can't very well merge the submatrix extraction.
322b1a0a8a3SJed Brown   */
323*f746d493SDmitry Karpeev   ierr = PetscMalloc(sizeof(IS)*osm->nmax, &is); CHKERRQ(ierr);
324*f746d493SDmitry Karpeev   for(i=0; i<osm->n; ++i) {
325*f746d493SDmitry Karpeev     is[i] = osm->is[i];
326*f746d493SDmitry Karpeev   }
327*f746d493SDmitry Karpeev   for (i=osm->n; i<osm->nmax; i++) {
328*f746d493SDmitry Karpeev     ierr = ISCreateStride(((PetscObject)pc)->comm,0,0,1,&is[i]);CHKERRQ(ierr);
329*f746d493SDmitry Karpeev   }
330*f746d493SDmitry Karpeev 
331b1a0a8a3SJed Brown   if (scall == MAT_INITIAL_MATRIX) {
332b1a0a8a3SJed Brown     ierr = PetscObjectGetOptionsPrefix((PetscObject)pc->pmat,&pprefix);CHKERRQ(ierr);
333*f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
334b1a0a8a3SJed Brown       ierr = PetscLogObjectParent(pc,osm->pmat[i]);CHKERRQ(ierr);
335b1a0a8a3SJed Brown       ierr = PetscObjectSetOptionsPrefix((PetscObject)osm->pmat[i],pprefix);CHKERRQ(ierr);
336b1a0a8a3SJed Brown     }
337b1a0a8a3SJed Brown   }
338b1a0a8a3SJed Brown 
339b1a0a8a3SJed Brown   /* Return control to the user so that the submatrices can be modified (e.g., to apply
340b1a0a8a3SJed Brown      different boundary conditions for the submatrices than for the global problem) */
341*f746d493SDmitry Karpeev   ierr = PCModifySubMatrices(pc,osm->nmax,is,is,osm->pmat,pc->modifysubmatricesP);CHKERRQ(ierr);
342*f746d493SDmitry Karpeev   for (i=osm->n; i<osm->nmax; i++) {
343*f746d493SDmitry Karpeev     ierr = ISDestroy(is[i]);CHKERRQ(ierr);
344*f746d493SDmitry Karpeev   }
345*f746d493SDmitry Karpeev   ierr = PetscFree(is); CHKERRQ(ierr);
346b1a0a8a3SJed Brown 
347b1a0a8a3SJed Brown   /*
348*f746d493SDmitry Karpeev      Loop over submatrices putting them into local ksp
349b1a0a8a3SJed Brown   */
350*f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
351b1a0a8a3SJed Brown     ierr = KSPSetOperators(osm->ksp[i],osm->pmat[i],osm->pmat[i],pc->flag);CHKERRQ(ierr);
352b1a0a8a3SJed Brown     if (!pc->setupcalled) {
353b1a0a8a3SJed Brown       ierr = KSPSetFromOptions(osm->ksp[i]);CHKERRQ(ierr);
354b1a0a8a3SJed Brown     }
355b1a0a8a3SJed Brown   }
356b1a0a8a3SJed Brown 
357b1a0a8a3SJed Brown   PetscFunctionReturn(0);
358b1a0a8a3SJed Brown }
359b1a0a8a3SJed Brown 
360b1a0a8a3SJed Brown #undef __FUNCT__
361*f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUpOnBlocks_GASM"
362*f746d493SDmitry Karpeev static PetscErrorCode PCSetUpOnBlocks_GASM(PC pc)
363b1a0a8a3SJed Brown {
364*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
365b1a0a8a3SJed Brown   PetscErrorCode ierr;
366b1a0a8a3SJed Brown   PetscInt       i;
367b1a0a8a3SJed Brown 
368b1a0a8a3SJed Brown   PetscFunctionBegin;
369*f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
370b1a0a8a3SJed Brown     ierr = KSPSetUp(osm->ksp[i]);CHKERRQ(ierr);
371b1a0a8a3SJed Brown   }
372b1a0a8a3SJed Brown   PetscFunctionReturn(0);
373b1a0a8a3SJed Brown }
374b1a0a8a3SJed Brown 
375b1a0a8a3SJed Brown #undef __FUNCT__
376*f746d493SDmitry Karpeev #define __FUNCT__ "PCApply_GASM"
377*f746d493SDmitry Karpeev static PetscErrorCode PCApply_GASM(PC pc,Vec x,Vec y)
378b1a0a8a3SJed Brown {
379*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
380b1a0a8a3SJed Brown   PetscErrorCode ierr;
381*f746d493SDmitry Karpeev   PetscInt       i;
382b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
383b1a0a8a3SJed Brown 
384b1a0a8a3SJed Brown   PetscFunctionBegin;
385b1a0a8a3SJed Brown   /*
386b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
387b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
388b1a0a8a3SJed Brown   */
389*f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
390b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
391b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
392*f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx); CHKERRQ(ierr);
393b1a0a8a3SJed Brown   }
394*f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
395b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
396b1a0a8a3SJed Brown   }
397b1a0a8a3SJed Brown 
398*f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
399b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
400*f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
401b1a0a8a3SJed Brown   /* do the local solves */
402*f746d493SDmitry 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. */
403b1a0a8a3SJed Brown     ierr = KSPSolve(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
404b1a0a8a3SJed Brown   }
405*f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
406*f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
407b1a0a8a3SJed Brown   PetscFunctionReturn(0);
408b1a0a8a3SJed Brown }
409b1a0a8a3SJed Brown 
410b1a0a8a3SJed Brown #undef __FUNCT__
411*f746d493SDmitry Karpeev #define __FUNCT__ "PCApplyTranspose_GASM"
412*f746d493SDmitry Karpeev static PetscErrorCode PCApplyTranspose_GASM(PC pc,Vec x,Vec y)
413b1a0a8a3SJed Brown {
414*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
415b1a0a8a3SJed Brown   PetscErrorCode ierr;
416*f746d493SDmitry Karpeev   PetscInt       i;
417b1a0a8a3SJed Brown   ScatterMode    forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE;
418b1a0a8a3SJed Brown 
419b1a0a8a3SJed Brown   PetscFunctionBegin;
420b1a0a8a3SJed Brown   /*
421b1a0a8a3SJed Brown      Support for limiting the restriction or interpolation to only local
422b1a0a8a3SJed Brown      subdomain values (leaving the other values 0).
423b1a0a8a3SJed Brown 
424*f746d493SDmitry Karpeev      Note: these are reversed from the PCApply_GASM() because we are applying the
425b1a0a8a3SJed Brown      transpose of the three terms
426b1a0a8a3SJed Brown   */
427*f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_INTERPOLATE)) {
428b1a0a8a3SJed Brown     forward = SCATTER_FORWARD_LOCAL;
429b1a0a8a3SJed Brown     /* have to zero the work RHS since scatter may leave some slots empty */
430*f746d493SDmitry Karpeev     ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr);
431b1a0a8a3SJed Brown   }
432*f746d493SDmitry Karpeev   if (!(osm->type & PC_GASM_RESTRICT)) {
433b1a0a8a3SJed Brown     reverse = SCATTER_REVERSE_LOCAL;
434b1a0a8a3SJed Brown   }
435b1a0a8a3SJed Brown 
436*f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->restriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
437b1a0a8a3SJed Brown   ierr = VecZeroEntries(y);CHKERRQ(ierr);
438*f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->restriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr);
439b1a0a8a3SJed Brown   /* do the local solves */
440*f746d493SDmitry Karpeev   for (i=0; i<osm->n; ++i) {
441b1a0a8a3SJed Brown     ierr = KSPSolveTranspose(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr);
442b1a0a8a3SJed Brown   }
443*f746d493SDmitry Karpeev   ierr = VecScatterBegin(osm->prolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
444*f746d493SDmitry Karpeev   ierr = VecScatterEnd(osm->prolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr);
445b1a0a8a3SJed Brown   PetscFunctionReturn(0);
446b1a0a8a3SJed Brown }
447b1a0a8a3SJed Brown 
448b1a0a8a3SJed Brown #undef __FUNCT__
449*f746d493SDmitry Karpeev #define __FUNCT__ "PCDestroy_GASM"
450*f746d493SDmitry Karpeev static PetscErrorCode PCDestroy_GASM(PC pc)
451b1a0a8a3SJed Brown {
452*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
453b1a0a8a3SJed Brown   PetscErrorCode ierr;
454b1a0a8a3SJed Brown   PetscInt       i;
455b1a0a8a3SJed Brown 
456b1a0a8a3SJed Brown   PetscFunctionBegin;
457b1a0a8a3SJed Brown   if (osm->ksp) {
458*f746d493SDmitry Karpeev     for (i=0; i<osm->n; i++) {
459b1a0a8a3SJed Brown       ierr = KSPDestroy(osm->ksp[i]);CHKERRQ(ierr);
460b1a0a8a3SJed Brown     }
461b1a0a8a3SJed Brown     ierr = PetscFree(osm->ksp);CHKERRQ(ierr);
462b1a0a8a3SJed Brown   }
463b1a0a8a3SJed Brown   if (osm->pmat) {
464*f746d493SDmitry Karpeev     if (osm->n > 0) {
465b1a0a8a3SJed Brown       ierr = MatDestroyMatrices(osm->n_local_true,&osm->pmat);CHKERRQ(ierr);
466b1a0a8a3SJed Brown     }
467b1a0a8a3SJed Brown   }
468*f746d493SDmitry Karpeev   for (i=0; i<osm->n; i++) {
469b1a0a8a3SJed Brown     ierr = VecDestroy(osm->x[i]);CHKERRQ(ierr);
470b1a0a8a3SJed Brown     ierr = VecDestroy(osm->y[i]);CHKERRQ(ierr);
471b1a0a8a3SJed Brown   }
472b1a0a8a3SJed Brown   ierr = PetscFree(osm->x);CHKERRQ(ierr);
473b1a0a8a3SJed Brown   ierr = PetscFree(osm->y);CHKERRQ(ierr);
474*f746d493SDmitry Karpeev   ierr = VecDestroy(osm->gx); CHKERRQ(ierr);
475*f746d493SDmitry Karpeev 
476b1a0a8a3SJed Brown   if (osm->is) {
477*f746d493SDmitry Karpeev     ierr = PCGASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr);
478b1a0a8a3SJed Brown   }
479b1a0a8a3SJed Brown   ierr = PetscFree(osm);CHKERRQ(ierr);
480b1a0a8a3SJed Brown   PetscFunctionReturn(0);
481b1a0a8a3SJed Brown }
482b1a0a8a3SJed Brown 
483b1a0a8a3SJed Brown #undef __FUNCT__
484*f746d493SDmitry Karpeev #define __FUNCT__ "PCSetFromOptions_GASM"
485*f746d493SDmitry Karpeev static PetscErrorCode PCSetFromOptions_GASM(PC pc)
486b1a0a8a3SJed Brown {
487*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
488b1a0a8a3SJed Brown   PetscErrorCode ierr;
489b1a0a8a3SJed Brown   PetscInt       blocks,ovl;
490b1a0a8a3SJed Brown   PetscBool      symset,flg;
491*f746d493SDmitry Karpeev   PCGASMType      gasmtype;
492b1a0a8a3SJed Brown 
493b1a0a8a3SJed Brown   PetscFunctionBegin;
494b1a0a8a3SJed Brown   /* set the type to symmetric if matrix is symmetric */
495b1a0a8a3SJed Brown   if (!osm->type_set && pc->pmat) {
496b1a0a8a3SJed Brown     ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr);
497*f746d493SDmitry Karpeev     if (symset && flg) { osm->type = PC_GASM_BASIC; }
498b1a0a8a3SJed Brown   }
499b1a0a8a3SJed Brown   ierr = PetscOptionsHead("Additive Schwarz options");CHKERRQ(ierr);
500*f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_blocks","Number of subdomains","PCGASMSetTotalSubdomains",osm->n,&blocks,&flg);CHKERRQ(ierr);
501*f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetTotalSubdomains(pc,blocks,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); }
502*f746d493SDmitry Karpeev     ierr = PetscOptionsInt("-pc_gasm_overlap","Number of grid points overlap","PCGASMSetOverlap",osm->overlap,&ovl,&flg);CHKERRQ(ierr);
503*f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetOverlap(pc,ovl);CHKERRQ(ierr); }
504b1a0a8a3SJed Brown     flg  = PETSC_FALSE;
505*f746d493SDmitry Karpeev     ierr = PetscOptionsEnum("-pc_gasm_type","Type of restriction/extension","PCGASMSetType",PCGASMTypes,(PetscEnum)osm->type,(PetscEnum*)&gasmtype,&flg);CHKERRQ(ierr);
506*f746d493SDmitry Karpeev     if (flg) {ierr = PCGASMSetType(pc,gasmtype);CHKERRQ(ierr); }
507b1a0a8a3SJed Brown   ierr = PetscOptionsTail();CHKERRQ(ierr);
508b1a0a8a3SJed Brown   PetscFunctionReturn(0);
509b1a0a8a3SJed Brown }
510b1a0a8a3SJed Brown 
511b1a0a8a3SJed Brown /*------------------------------------------------------------------------------------*/
512b1a0a8a3SJed Brown 
513b1a0a8a3SJed Brown EXTERN_C_BEGIN
514b1a0a8a3SJed Brown #undef __FUNCT__
515*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains_GASM"
516*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetLocalSubdomains_GASM(PC pc,PetscInt n,IS is[],IS is_local[])
517b1a0a8a3SJed Brown {
518*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
519b1a0a8a3SJed Brown   PetscErrorCode ierr;
520b1a0a8a3SJed Brown   PetscInt       i;
521b1a0a8a3SJed Brown 
522b1a0a8a3SJed Brown   PetscFunctionBegin;
523b1a0a8a3SJed Brown   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Each process must have 1 or more blocks, n = %D",n);
524*f746d493SDmitry Karpeev   if (pc->setupcalled && (n != osm->n || is)) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetLocalSubdomains() should be called before calling PCSetUp().");
525b1a0a8a3SJed Brown 
526b1a0a8a3SJed Brown   if (!pc->setupcalled) {
527b1a0a8a3SJed Brown     if (is) {
528b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is[i]);CHKERRQ(ierr);}
529b1a0a8a3SJed Brown     }
530b1a0a8a3SJed Brown     if (is_local) {
531b1a0a8a3SJed Brown       for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is_local[i]);CHKERRQ(ierr);}
532b1a0a8a3SJed Brown     }
533b1a0a8a3SJed Brown     if (osm->is) {
534*f746d493SDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr);
535b1a0a8a3SJed Brown     }
536*f746d493SDmitry Karpeev     osm->n            = n;
537b1a0a8a3SJed Brown     osm->is           = 0;
538b1a0a8a3SJed Brown     osm->is_local     = 0;
539b1a0a8a3SJed Brown     if (is) {
540b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is);CHKERRQ(ierr);
541b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is[i] = is[i]; }
542*f746d493SDmitry Karpeev       /* Flag indicating that the user has set overlapping subdomains so PCGASM should not increase their size. */
543b1a0a8a3SJed Brown       osm->overlap = -1;
544b1a0a8a3SJed Brown     }
545b1a0a8a3SJed Brown     if (is_local) {
546b1a0a8a3SJed Brown       ierr = PetscMalloc(n*sizeof(IS),&osm->is_local);CHKERRQ(ierr);
547b1a0a8a3SJed Brown       for (i=0; i<n; i++) { osm->is_local[i] = is_local[i]; }
548b1a0a8a3SJed Brown     }
549b1a0a8a3SJed Brown   }
550b1a0a8a3SJed Brown   PetscFunctionReturn(0);
551b1a0a8a3SJed Brown }
552b1a0a8a3SJed Brown EXTERN_C_END
553b1a0a8a3SJed Brown 
554b1a0a8a3SJed Brown EXTERN_C_BEGIN
555b1a0a8a3SJed Brown #undef __FUNCT__
556*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains_GASM"
557*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetTotalSubdomains_GASM(PC pc,PetscInt N)
558b1a0a8a3SJed Brown {
559*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
560b1a0a8a3SJed Brown   PetscErrorCode ierr;
561b1a0a8a3SJed Brown   PetscMPIInt    rank,size;
562b1a0a8a3SJed Brown   PetscInt       n;
563b1a0a8a3SJed Brown 
564b1a0a8a3SJed Brown   PetscFunctionBegin;
565b1a0a8a3SJed Brown   if (N < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of total blocks must be > 0, N = %D",N);
566b1a0a8a3SJed Brown 
567b1a0a8a3SJed Brown   /*
568b1a0a8a3SJed Brown      Split the subdomains equally among all processors
569b1a0a8a3SJed Brown   */
570b1a0a8a3SJed Brown   ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
571b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr);
572b1a0a8a3SJed Brown   n = N/size + ((N % size) > rank);
573b1a0a8a3SJed 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);
574*f746d493SDmitry Karpeev   if (pc->setupcalled && n != osm->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetTotalSubdomains() should be called before PCSetUp().");
575b1a0a8a3SJed Brown   if (!pc->setupcalled) {
576b1a0a8a3SJed Brown     if (osm->is) {
577*f746d493SDmitry Karpeev       ierr = PCGASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr);
578b1a0a8a3SJed Brown     }
579*f746d493SDmitry Karpeev     osm->n            = n;
580b1a0a8a3SJed Brown     osm->is           = 0;
581b1a0a8a3SJed Brown     osm->is_local     = 0;
582b1a0a8a3SJed Brown   }
583b1a0a8a3SJed Brown   PetscFunctionReturn(0);
584b1a0a8a3SJed Brown }
585b1a0a8a3SJed Brown EXTERN_C_END
586b1a0a8a3SJed Brown 
587b1a0a8a3SJed Brown EXTERN_C_BEGIN
588b1a0a8a3SJed Brown #undef __FUNCT__
589*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap_GASM"
590*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetOverlap_GASM(PC pc,PetscInt ovl)
591b1a0a8a3SJed Brown {
592*f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
593b1a0a8a3SJed Brown 
594b1a0a8a3SJed Brown   PetscFunctionBegin;
595b1a0a8a3SJed Brown   if (ovl < 0) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Negative overlap value requested");
596*f746d493SDmitry Karpeev   if (pc->setupcalled && ovl != osm->overlap) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetOverlap() should be called before PCSetUp().");
597b1a0a8a3SJed Brown   if (!pc->setupcalled) {
598b1a0a8a3SJed Brown     osm->overlap = ovl;
599b1a0a8a3SJed Brown   }
600b1a0a8a3SJed Brown   PetscFunctionReturn(0);
601b1a0a8a3SJed Brown }
602b1a0a8a3SJed Brown EXTERN_C_END
603b1a0a8a3SJed Brown 
604b1a0a8a3SJed Brown EXTERN_C_BEGIN
605b1a0a8a3SJed Brown #undef __FUNCT__
606*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType_GASM"
607*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetType_GASM(PC pc,PCGASMType type)
608b1a0a8a3SJed Brown {
609*f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
610b1a0a8a3SJed Brown 
611b1a0a8a3SJed Brown   PetscFunctionBegin;
612b1a0a8a3SJed Brown   osm->type     = type;
613b1a0a8a3SJed Brown   osm->type_set = PETSC_TRUE;
614b1a0a8a3SJed Brown   PetscFunctionReturn(0);
615b1a0a8a3SJed Brown }
616b1a0a8a3SJed Brown EXTERN_C_END
617b1a0a8a3SJed Brown 
618b1a0a8a3SJed Brown EXTERN_C_BEGIN
619b1a0a8a3SJed Brown #undef __FUNCT__
620*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices_GASM"
621*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetSortIndices_GASM(PC pc,PetscBool  doSort)
622b1a0a8a3SJed Brown {
623*f746d493SDmitry Karpeev   PC_GASM *osm = (PC_GASM*)pc->data;
624b1a0a8a3SJed Brown 
625b1a0a8a3SJed Brown   PetscFunctionBegin;
626b1a0a8a3SJed Brown   osm->sort_indices = doSort;
627b1a0a8a3SJed Brown   PetscFunctionReturn(0);
628b1a0a8a3SJed Brown }
629b1a0a8a3SJed Brown EXTERN_C_END
630b1a0a8a3SJed Brown 
631b1a0a8a3SJed Brown EXTERN_C_BEGIN
632b1a0a8a3SJed Brown #undef __FUNCT__
633*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP_GASM"
634*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMGetSubKSP_GASM(PC pc,PetscInt *n_local,PetscInt *first_local,KSP **ksp)
635b1a0a8a3SJed Brown {
636*f746d493SDmitry Karpeev   PC_GASM         *osm = (PC_GASM*)pc->data;
637b1a0a8a3SJed Brown   PetscErrorCode ierr;
638b1a0a8a3SJed Brown 
639b1a0a8a3SJed Brown   PetscFunctionBegin;
640b1a0a8a3SJed Brown   if (osm->n_local_true < 1) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ORDER,"Need to call PCSetUP() on PC (or KSPSetUp() on the outer KSP object) before calling here");
641b1a0a8a3SJed Brown 
642b1a0a8a3SJed Brown   if (n_local) {
643b1a0a8a3SJed Brown     *n_local = osm->n_local_true;
644b1a0a8a3SJed Brown   }
645b1a0a8a3SJed Brown   if (first_local) {
646b1a0a8a3SJed Brown     ierr = MPI_Scan(&osm->n_local_true,first_local,1,MPIU_INT,MPI_SUM,((PetscObject)pc)->comm);CHKERRQ(ierr);
647b1a0a8a3SJed Brown     *first_local -= osm->n_local_true;
648b1a0a8a3SJed Brown   }
649b1a0a8a3SJed Brown   if (ksp) {
650b1a0a8a3SJed Brown     /* Assume that local solves are now different; not necessarily
651*f746d493SDmitry Karpeev        true though!  This flag is used only for PCView_GASM() */
652b1a0a8a3SJed Brown     *ksp                   = osm->ksp;
653b1a0a8a3SJed Brown     osm->same_local_solves = PETSC_FALSE;
654b1a0a8a3SJed Brown   }
655b1a0a8a3SJed Brown   PetscFunctionReturn(0);
656b1a0a8a3SJed Brown }
657b1a0a8a3SJed Brown EXTERN_C_END
658b1a0a8a3SJed Brown 
659b1a0a8a3SJed Brown 
660b1a0a8a3SJed Brown #undef __FUNCT__
661*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains"
662b1a0a8a3SJed Brown /*@C
663*f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains - Sets the local subdomains (for this processor
664b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
665b1a0a8a3SJed Brown 
666b1a0a8a3SJed Brown     Collective on PC
667b1a0a8a3SJed Brown 
668b1a0a8a3SJed Brown     Input Parameters:
669b1a0a8a3SJed Brown +   pc - the preconditioner context
670b1a0a8a3SJed Brown .   n - the number of subdomains for this processor (default value = 1)
671b1a0a8a3SJed Brown .   is - the index set that defines the subdomains for this processor
672b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
673b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
674b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
675b1a0a8a3SJed Brown 
676b1a0a8a3SJed Brown     Notes:
677b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
678b1a0a8a3SJed Brown 
679*f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
680b1a0a8a3SJed Brown 
681*f746d493SDmitry Karpeev     Use PCGASMSetTotalSubdomains() to set the subdomains for all processors.
682b1a0a8a3SJed Brown 
683b1a0a8a3SJed Brown     Level: advanced
684b1a0a8a3SJed Brown 
685*f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
686b1a0a8a3SJed Brown 
687*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
688*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
689b1a0a8a3SJed Brown @*/
690*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetLocalSubdomains(PC pc,PetscInt n,IS is[],IS is_local[])
691b1a0a8a3SJed Brown {
692b1a0a8a3SJed Brown   PetscErrorCode ierr;
693b1a0a8a3SJed Brown 
694b1a0a8a3SJed Brown   PetscFunctionBegin;
695b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
696*f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetLocalSubdomains_C",(PC,PetscInt,IS[],IS[]),(pc,n,is,is_local));CHKERRQ(ierr);
697b1a0a8a3SJed Brown   PetscFunctionReturn(0);
698b1a0a8a3SJed Brown }
699b1a0a8a3SJed Brown 
700b1a0a8a3SJed Brown #undef __FUNCT__
701*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains"
702b1a0a8a3SJed Brown /*@C
703*f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains - Sets the subdomains for all processor for the
704b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
705b1a0a8a3SJed Brown     PC communicator must call this routine, with the same index sets.
706b1a0a8a3SJed Brown 
707b1a0a8a3SJed Brown     Collective on PC
708b1a0a8a3SJed Brown 
709b1a0a8a3SJed Brown     Input Parameters:
710b1a0a8a3SJed Brown +   pc - the preconditioner context
711b1a0a8a3SJed Brown .   n - the number of subdomains for all processors
712b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for all processor
713b1a0a8a3SJed Brown          (or PETSC_NULL for PETSc to determine subdomains)
714b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor
715b1a0a8a3SJed Brown          (or PETSC_NULL to use the default of 1 subdomain per process)
716b1a0a8a3SJed Brown 
717b1a0a8a3SJed Brown     Options Database Key:
718b1a0a8a3SJed Brown     To set the total number of subdomain blocks rather than specify the
719b1a0a8a3SJed Brown     index sets, use the option
720*f746d493SDmitry Karpeev .    -pc_gasm_blocks <blks> - Sets total blocks
721b1a0a8a3SJed Brown 
722b1a0a8a3SJed Brown     Notes:
723b1a0a8a3SJed Brown     Currently you cannot use this to set the actual subdomains with the argument is.
724b1a0a8a3SJed Brown 
725*f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.
726b1a0a8a3SJed Brown 
727b1a0a8a3SJed Brown     These index sets cannot be destroyed until after completion of the
728*f746d493SDmitry Karpeev     linear solves for which the GASM preconditioner is being used.
729b1a0a8a3SJed Brown 
730*f746d493SDmitry Karpeev     Use PCGASMSetLocalSubdomains() to set local subdomains.
731b1a0a8a3SJed Brown 
732b1a0a8a3SJed Brown     Level: advanced
733b1a0a8a3SJed Brown 
734*f746d493SDmitry Karpeev .keywords: PC, GASM, set, total, global, subdomains, additive Schwarz
735b1a0a8a3SJed Brown 
736*f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
737*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
738b1a0a8a3SJed Brown @*/
739*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetTotalSubdomains(PC pc,PetscInt N)
740b1a0a8a3SJed Brown {
741b1a0a8a3SJed Brown   PetscErrorCode ierr;
742b1a0a8a3SJed Brown 
743b1a0a8a3SJed Brown   PetscFunctionBegin;
744b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
745*f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetTotalSubdomains_C",(PC,PetscInt),(pc,N));CHKERRQ(ierr);
746b1a0a8a3SJed Brown   PetscFunctionReturn(0);
747b1a0a8a3SJed Brown }
748b1a0a8a3SJed Brown 
749b1a0a8a3SJed Brown #undef __FUNCT__
750*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap"
751b1a0a8a3SJed Brown /*@
752*f746d493SDmitry Karpeev     PCGASMSetOverlap - Sets the overlap between a pair of subdomains for the
753b1a0a8a3SJed Brown     additive Schwarz preconditioner.  Either all or no processors in the
754b1a0a8a3SJed Brown     PC communicator must call this routine.
755b1a0a8a3SJed Brown 
756b1a0a8a3SJed Brown     Logically Collective on PC
757b1a0a8a3SJed Brown 
758b1a0a8a3SJed Brown     Input Parameters:
759b1a0a8a3SJed Brown +   pc  - the preconditioner context
760b1a0a8a3SJed Brown -   ovl - the amount of overlap between subdomains (ovl >= 0, default value = 1)
761b1a0a8a3SJed Brown 
762b1a0a8a3SJed Brown     Options Database Key:
763*f746d493SDmitry Karpeev .   -pc_gasm_overlap <ovl> - Sets overlap
764b1a0a8a3SJed Brown 
765b1a0a8a3SJed Brown     Notes:
766*f746d493SDmitry Karpeev     By default the GASM preconditioner uses 1 block per processor.  To use
767*f746d493SDmitry Karpeev     multiple blocks per perocessor, see PCGASMSetTotalSubdomains() and
768*f746d493SDmitry Karpeev     PCGASMSetLocalSubdomains() (and the option -pc_gasm_blocks <blks>).
769b1a0a8a3SJed Brown 
770b1a0a8a3SJed Brown     The overlap defaults to 1, so if one desires that no additional
771b1a0a8a3SJed Brown     overlap be computed beyond what may have been set with a call to
772*f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(), then ovl
773b1a0a8a3SJed Brown     must be set to be 0.  In particular, if one does not explicitly set
774b1a0a8a3SJed Brown     the subdomains an application code, then all overlap would be computed
775*f746d493SDmitry Karpeev     internally by PETSc, and using an overlap of 0 would result in an GASM
776b1a0a8a3SJed Brown     variant that is equivalent to the block Jacobi preconditioner.
777b1a0a8a3SJed Brown 
778b1a0a8a3SJed Brown     Note that one can define initial index sets with any overlap via
779*f746d493SDmitry Karpeev     PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(); the routine
780*f746d493SDmitry Karpeev     PCGASMSetOverlap() merely allows PETSc to extend that overlap further
781b1a0a8a3SJed Brown     if desired.
782b1a0a8a3SJed Brown 
783b1a0a8a3SJed Brown     Level: intermediate
784b1a0a8a3SJed Brown 
785*f746d493SDmitry Karpeev .keywords: PC, GASM, set, overlap
786b1a0a8a3SJed Brown 
787*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
788*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains()
789b1a0a8a3SJed Brown @*/
790*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetOverlap(PC pc,PetscInt ovl)
791b1a0a8a3SJed Brown {
792b1a0a8a3SJed Brown   PetscErrorCode ierr;
793b1a0a8a3SJed Brown 
794b1a0a8a3SJed Brown   PetscFunctionBegin;
795b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
796b1a0a8a3SJed Brown   PetscValidLogicalCollectiveInt(pc,ovl,2);
797*f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetOverlap_C",(PC,PetscInt),(pc,ovl));CHKERRQ(ierr);
798b1a0a8a3SJed Brown   PetscFunctionReturn(0);
799b1a0a8a3SJed Brown }
800b1a0a8a3SJed Brown 
801b1a0a8a3SJed Brown #undef __FUNCT__
802*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType"
803b1a0a8a3SJed Brown /*@
804*f746d493SDmitry Karpeev     PCGASMSetType - Sets the type of restriction and interpolation used
805b1a0a8a3SJed Brown     for local problems in the additive Schwarz method.
806b1a0a8a3SJed Brown 
807b1a0a8a3SJed Brown     Logically Collective on PC
808b1a0a8a3SJed Brown 
809b1a0a8a3SJed Brown     Input Parameters:
810b1a0a8a3SJed Brown +   pc  - the preconditioner context
811*f746d493SDmitry Karpeev -   type - variant of GASM, one of
812b1a0a8a3SJed Brown .vb
813*f746d493SDmitry Karpeev       PC_GASM_BASIC       - full interpolation and restriction
814*f746d493SDmitry Karpeev       PC_GASM_RESTRICT    - full restriction, local processor interpolation
815*f746d493SDmitry Karpeev       PC_GASM_INTERPOLATE - full interpolation, local processor restriction
816*f746d493SDmitry Karpeev       PC_GASM_NONE        - local processor restriction and interpolation
817b1a0a8a3SJed Brown .ve
818b1a0a8a3SJed Brown 
819b1a0a8a3SJed Brown     Options Database Key:
820*f746d493SDmitry Karpeev .   -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
821b1a0a8a3SJed Brown 
822b1a0a8a3SJed Brown     Level: intermediate
823b1a0a8a3SJed Brown 
824*f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
825b1a0a8a3SJed Brown 
826*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
827*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
828b1a0a8a3SJed Brown @*/
829*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetType(PC pc,PCGASMType type)
830b1a0a8a3SJed Brown {
831b1a0a8a3SJed Brown   PetscErrorCode ierr;
832b1a0a8a3SJed Brown 
833b1a0a8a3SJed Brown   PetscFunctionBegin;
834b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
835b1a0a8a3SJed Brown   PetscValidLogicalCollectiveEnum(pc,type,2);
836*f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetType_C",(PC,PCGASMType),(pc,type));CHKERRQ(ierr);
837b1a0a8a3SJed Brown   PetscFunctionReturn(0);
838b1a0a8a3SJed Brown }
839b1a0a8a3SJed Brown 
840b1a0a8a3SJed Brown #undef __FUNCT__
841*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices"
842b1a0a8a3SJed Brown /*@
843*f746d493SDmitry Karpeev     PCGASMSetSortIndices - Determines whether subdomain indices are sorted.
844b1a0a8a3SJed Brown 
845b1a0a8a3SJed Brown     Logically Collective on PC
846b1a0a8a3SJed Brown 
847b1a0a8a3SJed Brown     Input Parameters:
848b1a0a8a3SJed Brown +   pc  - the preconditioner context
849b1a0a8a3SJed Brown -   doSort - sort the subdomain indices
850b1a0a8a3SJed Brown 
851b1a0a8a3SJed Brown     Level: intermediate
852b1a0a8a3SJed Brown 
853*f746d493SDmitry Karpeev .keywords: PC, GASM, set, type
854b1a0a8a3SJed Brown 
855*f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(),
856*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D()
857b1a0a8a3SJed Brown @*/
858*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMSetSortIndices(PC pc,PetscBool  doSort)
859b1a0a8a3SJed Brown {
860b1a0a8a3SJed Brown   PetscErrorCode ierr;
861b1a0a8a3SJed Brown 
862b1a0a8a3SJed Brown   PetscFunctionBegin;
863b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
864b1a0a8a3SJed Brown   PetscValidLogicalCollectiveBool(pc,doSort,2);
865*f746d493SDmitry Karpeev   ierr = PetscTryMethod(pc,"PCGASMSetSortIndices_C",(PC,PetscBool),(pc,doSort));CHKERRQ(ierr);
866b1a0a8a3SJed Brown   PetscFunctionReturn(0);
867b1a0a8a3SJed Brown }
868b1a0a8a3SJed Brown 
869b1a0a8a3SJed Brown #undef __FUNCT__
870*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP"
871b1a0a8a3SJed Brown /*@C
872*f746d493SDmitry Karpeev    PCGASMGetSubKSP - Gets the local KSP contexts for all blocks on
873b1a0a8a3SJed Brown    this processor.
874b1a0a8a3SJed Brown 
875b1a0a8a3SJed Brown    Collective on PC iff first_local is requested
876b1a0a8a3SJed Brown 
877b1a0a8a3SJed Brown    Input Parameter:
878b1a0a8a3SJed Brown .  pc - the preconditioner context
879b1a0a8a3SJed Brown 
880b1a0a8a3SJed Brown    Output Parameters:
881b1a0a8a3SJed Brown +  n_local - the number of blocks on this processor or PETSC_NULL
882b1a0a8a3SJed Brown .  first_local - the global number of the first block on this processor or PETSC_NULL,
883b1a0a8a3SJed Brown                  all processors must request or all must pass PETSC_NULL
884b1a0a8a3SJed Brown -  ksp - the array of KSP contexts
885b1a0a8a3SJed Brown 
886b1a0a8a3SJed Brown    Note:
887*f746d493SDmitry Karpeev    After PCGASMGetSubKSP() the array of KSPes is not to be freed
888b1a0a8a3SJed Brown 
889b1a0a8a3SJed Brown    Currently for some matrix implementations only 1 block per processor
890b1a0a8a3SJed Brown    is supported.
891b1a0a8a3SJed Brown 
892*f746d493SDmitry Karpeev    You must call KSPSetUp() before calling PCGASMGetSubKSP().
893b1a0a8a3SJed Brown 
894b1a0a8a3SJed Brown    Level: advanced
895b1a0a8a3SJed Brown 
896*f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, get, sub, KSP, context
897b1a0a8a3SJed Brown 
898*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMSetOverlap(),
899*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(),
900b1a0a8a3SJed Brown @*/
901*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[])
902b1a0a8a3SJed Brown {
903b1a0a8a3SJed Brown   PetscErrorCode ierr;
904b1a0a8a3SJed Brown 
905b1a0a8a3SJed Brown   PetscFunctionBegin;
906b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
907*f746d493SDmitry Karpeev   ierr = PetscUseMethod(pc,"PCGASMGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));CHKERRQ(ierr);
908b1a0a8a3SJed Brown   PetscFunctionReturn(0);
909b1a0a8a3SJed Brown }
910b1a0a8a3SJed Brown 
911b1a0a8a3SJed Brown /* -------------------------------------------------------------------------------------*/
912b1a0a8a3SJed Brown /*MC
913*f746d493SDmitry Karpeev    PCGASM - Use the (restricted) additive Schwarz method, each block is (approximately) solved with
914b1a0a8a3SJed Brown            its own KSP object.
915b1a0a8a3SJed Brown 
916b1a0a8a3SJed Brown    Options Database Keys:
917*f746d493SDmitry Karpeev +  -pc_gasm_truelocal - Activates PCGGASMSetUseTrueLocal()
918*f746d493SDmitry Karpeev .  -pc_gasm_blocks <blks> - Sets total blocks
919*f746d493SDmitry Karpeev .  -pc_gasm_overlap <ovl> - Sets overlap
920*f746d493SDmitry Karpeev -  -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type
921b1a0a8a3SJed Brown 
922b1a0a8a3SJed Brown      IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you
923*f746d493SDmitry Karpeev       will get a different convergence rate due to the default option of -pc_gasm_type restrict. Use
924*f746d493SDmitry Karpeev       -pc_gasm_type basic to use the standard GASM.
925b1a0a8a3SJed Brown 
926b1a0a8a3SJed Brown    Notes: Each processor can have one or more blocks, but a block cannot be shared by more
927b1a0a8a3SJed Brown      than one processor. Defaults to one block per processor.
928b1a0a8a3SJed Brown 
929b1a0a8a3SJed Brown      To set options on the solvers for each block append -sub_ to all the KSP, and PC
930b1a0a8a3SJed Brown         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
931b1a0a8a3SJed Brown 
932*f746d493SDmitry Karpeev      To set the options on the solvers separate for each block call PCGASMGetSubKSP()
933b1a0a8a3SJed Brown          and set the options directly on the resulting KSP object (you can access its PC
934b1a0a8a3SJed Brown          with KSPGetPC())
935b1a0a8a3SJed Brown 
936b1a0a8a3SJed Brown 
937b1a0a8a3SJed Brown    Level: beginner
938b1a0a8a3SJed Brown 
939b1a0a8a3SJed Brown    Concepts: additive Schwarz method
940b1a0a8a3SJed Brown 
941b1a0a8a3SJed Brown     References:
942b1a0a8a3SJed Brown     An additive variant of the Schwarz alternating method for the case of many subregions
943b1a0a8a3SJed Brown     M Dryja, OB Widlund - Courant Institute, New York University Technical report
944b1a0a8a3SJed Brown 
945b1a0a8a3SJed Brown     Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations,
946b1a0a8a3SJed Brown     Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X.
947b1a0a8a3SJed Brown 
948b1a0a8a3SJed Brown .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
949*f746d493SDmitry Karpeev            PCBJACOBI, PCGASMSetUseTrueLocal(), PCGASMGetSubKSP(), PCGASMSetLocalSubdomains(),
950*f746d493SDmitry Karpeev            PCGASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCGASMSetOverlap(), PCGASMSetType()
951b1a0a8a3SJed Brown 
952b1a0a8a3SJed Brown M*/
953b1a0a8a3SJed Brown 
954b1a0a8a3SJed Brown EXTERN_C_BEGIN
955b1a0a8a3SJed Brown #undef __FUNCT__
956*f746d493SDmitry Karpeev #define __FUNCT__ "PCCreate_GASM"
957*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_GASM(PC pc)
958b1a0a8a3SJed Brown {
959b1a0a8a3SJed Brown   PetscErrorCode ierr;
960*f746d493SDmitry Karpeev   PC_GASM         *osm;
961b1a0a8a3SJed Brown 
962b1a0a8a3SJed Brown   PetscFunctionBegin;
963*f746d493SDmitry Karpeev   ierr = PetscNewLog(pc,PC_GASM,&osm);CHKERRQ(ierr);
964b1a0a8a3SJed Brown   osm->n                 = PETSC_DECIDE;
965b1a0a8a3SJed Brown   osm->n_local           = 0;
966b1a0a8a3SJed Brown   osm->n_local_true      = 0;
967b1a0a8a3SJed Brown   osm->overlap           = 1;
968b1a0a8a3SJed Brown   osm->ksp               = 0;
969b1a0a8a3SJed Brown   osm->restriction       = 0;
970b1a0a8a3SJed Brown   osm->localization      = 0;
971b1a0a8a3SJed Brown   osm->prolongation      = 0;
972b1a0a8a3SJed Brown   osm->x                 = 0;
973b1a0a8a3SJed Brown   osm->y                 = 0;
974b1a0a8a3SJed Brown   osm->y_local           = 0;
975b1a0a8a3SJed Brown   osm->is                = 0;
976b1a0a8a3SJed Brown   osm->is_local          = 0;
977b1a0a8a3SJed Brown   osm->mat               = 0;
978b1a0a8a3SJed Brown   osm->pmat              = 0;
979*f746d493SDmitry Karpeev   osm->type              = PC_GASM_RESTRICT;
980b1a0a8a3SJed Brown   osm->same_local_solves = PETSC_TRUE;
981b1a0a8a3SJed Brown   osm->sort_indices      = PETSC_TRUE;
982b1a0a8a3SJed Brown 
983b1a0a8a3SJed Brown   pc->data                   = (void*)osm;
984*f746d493SDmitry Karpeev   pc->ops->apply             = PCApply_GASM;
985*f746d493SDmitry Karpeev   pc->ops->applytranspose    = PCApplyTranspose_GASM;
986*f746d493SDmitry Karpeev   pc->ops->setup             = PCSetUp_GASM;
987*f746d493SDmitry Karpeev   pc->ops->destroy           = PCDestroy_GASM;
988*f746d493SDmitry Karpeev   pc->ops->setfromoptions    = PCSetFromOptions_GASM;
989*f746d493SDmitry Karpeev   pc->ops->setuponblocks     = PCSetUpOnBlocks_GASM;
990*f746d493SDmitry Karpeev   pc->ops->view              = PCView_GASM;
991b1a0a8a3SJed Brown   pc->ops->applyrichardson   = 0;
992b1a0a8a3SJed Brown 
993*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetLocalSubdomains_C","PCGASMSetLocalSubdomains_GASM",
994*f746d493SDmitry Karpeev                     PCGASMSetLocalSubdomains_GASM);CHKERRQ(ierr);
995*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetTotalSubdomains_C","PCGASMSetTotalSubdomains_GASM",
996*f746d493SDmitry Karpeev                     PCGASMSetTotalSubdomains_GASM);CHKERRQ(ierr);
997*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetOverlap_C","PCGASMSetOverlap_GASM",
998*f746d493SDmitry Karpeev                     PCGASMSetOverlap_GASM);CHKERRQ(ierr);
999*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetType_C","PCGASMSetType_GASM",
1000*f746d493SDmitry Karpeev                     PCGASMSetType_GASM);CHKERRQ(ierr);
1001*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetSortIndices_C","PCGASMSetSortIndices_GASM",
1002*f746d493SDmitry Karpeev                     PCGASMSetSortIndices_GASM);CHKERRQ(ierr);
1003*f746d493SDmitry Karpeev   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMGetSubKSP_C","PCGASMGetSubKSP_GASM",
1004*f746d493SDmitry Karpeev                     PCGASMGetSubKSP_GASM);CHKERRQ(ierr);
1005b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1006b1a0a8a3SJed Brown }
1007b1a0a8a3SJed Brown EXTERN_C_END
1008b1a0a8a3SJed Brown 
1009b1a0a8a3SJed Brown 
1010b1a0a8a3SJed Brown #undef __FUNCT__
1011*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains"
1012b1a0a8a3SJed Brown /*@C
1013*f746d493SDmitry Karpeev    PCGASMCreateSubdomains - Creates the index sets for the overlapping Schwarz
1014b1a0a8a3SJed Brown    preconditioner for a any problem on a general grid.
1015b1a0a8a3SJed Brown 
1016b1a0a8a3SJed Brown    Collective
1017b1a0a8a3SJed Brown 
1018b1a0a8a3SJed Brown    Input Parameters:
1019b1a0a8a3SJed Brown +  A - The global matrix operator
1020b1a0a8a3SJed Brown -  n - the number of local blocks
1021b1a0a8a3SJed Brown 
1022b1a0a8a3SJed Brown    Output Parameters:
1023b1a0a8a3SJed Brown .  outis - the array of index sets defining the subdomains
1024b1a0a8a3SJed Brown 
1025b1a0a8a3SJed Brown    Level: advanced
1026b1a0a8a3SJed Brown 
1027*f746d493SDmitry Karpeev    Note: this generates nonoverlapping subdomains; the PCGASM will generate the overlap
1028*f746d493SDmitry Karpeev     from these if you use PCGASMSetLocalSubdomains()
1029b1a0a8a3SJed Brown 
1030b1a0a8a3SJed Brown     In the Fortran version you must provide the array outis[] already allocated of length n.
1031b1a0a8a3SJed Brown 
1032*f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1033b1a0a8a3SJed Brown 
1034*f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMDestroySubdomains()
1035b1a0a8a3SJed Brown @*/
1036*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMCreateSubdomains(Mat A, PetscInt n, IS* outis[])
1037b1a0a8a3SJed Brown {
1038b1a0a8a3SJed Brown   MatPartitioning           mpart;
1039b1a0a8a3SJed Brown   const char                *prefix;
1040b1a0a8a3SJed Brown   PetscErrorCode            (*f)(Mat,PetscBool *,MatReuse,Mat*);
1041b1a0a8a3SJed Brown   PetscMPIInt               size;
1042b1a0a8a3SJed Brown   PetscInt                  i,j,rstart,rend,bs;
1043b1a0a8a3SJed Brown   PetscBool                 iscopy = PETSC_FALSE,isbaij = PETSC_FALSE,foundpart = PETSC_FALSE;
1044b1a0a8a3SJed Brown   Mat                       Ad = PETSC_NULL, adj;
1045b1a0a8a3SJed Brown   IS                        ispart,isnumb,*is;
1046b1a0a8a3SJed Brown   PetscErrorCode            ierr;
1047b1a0a8a3SJed Brown 
1048b1a0a8a3SJed Brown   PetscFunctionBegin;
1049b1a0a8a3SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1050b1a0a8a3SJed Brown   PetscValidPointer(outis,3);
1051b1a0a8a3SJed Brown   if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n);
1052b1a0a8a3SJed Brown 
1053b1a0a8a3SJed Brown   /* Get prefix, row distribution, and block size */
1054b1a0a8a3SJed Brown   ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr);
1055b1a0a8a3SJed Brown   ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);
1056b1a0a8a3SJed Brown   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1057b1a0a8a3SJed 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);
1058b1a0a8a3SJed Brown 
1059b1a0a8a3SJed Brown   /* Get diagonal block from matrix if possible */
1060b1a0a8a3SJed Brown   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
1061b1a0a8a3SJed Brown   ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**)(void))&f);CHKERRQ(ierr);
1062b1a0a8a3SJed Brown   if (f) {
1063b1a0a8a3SJed Brown     ierr = (*f)(A,&iscopy,MAT_INITIAL_MATRIX,&Ad);CHKERRQ(ierr);
1064b1a0a8a3SJed Brown   } else if (size == 1) {
1065b1a0a8a3SJed Brown     iscopy = PETSC_FALSE; Ad = A;
1066b1a0a8a3SJed Brown   } else {
1067b1a0a8a3SJed Brown     iscopy = PETSC_FALSE; Ad = PETSC_NULL;
1068b1a0a8a3SJed Brown   }
1069b1a0a8a3SJed Brown   if (Ad) {
1070b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr);
1071b1a0a8a3SJed Brown     if (!isbaij) {ierr = PetscTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);}
1072b1a0a8a3SJed Brown   }
1073b1a0a8a3SJed Brown   if (Ad && n > 1) {
1074b1a0a8a3SJed Brown     PetscBool  match,done;
1075b1a0a8a3SJed Brown     /* Try to setup a good matrix partitioning if available */
1076b1a0a8a3SJed Brown     ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr);
1077b1a0a8a3SJed Brown     ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr);
1078b1a0a8a3SJed Brown     ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr);
1079b1a0a8a3SJed Brown     ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr);
1080b1a0a8a3SJed Brown     if (!match) {
1081b1a0a8a3SJed Brown       ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr);
1082b1a0a8a3SJed Brown     }
1083b1a0a8a3SJed Brown     if (!match) { /* assume a "good" partitioner is available */
1084b1a0a8a3SJed Brown       PetscInt na,*ia,*ja;
1085b1a0a8a3SJed Brown       ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1086b1a0a8a3SJed Brown       if (done) {
1087b1a0a8a3SJed Brown 	/* Build adjacency matrix by hand. Unfortunately a call to
1088b1a0a8a3SJed Brown 	   MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will
1089b1a0a8a3SJed Brown 	   remove the block-aij structure and we cannot expect
1090b1a0a8a3SJed Brown 	   MatPartitioning to split vertices as we need */
1091b1a0a8a3SJed Brown 	PetscInt i,j,*row,len,nnz,cnt,*iia=0,*jja=0;
1092b1a0a8a3SJed Brown 	nnz = 0;
1093b1a0a8a3SJed Brown 	for (i=0; i<na; i++) { /* count number of nonzeros */
1094b1a0a8a3SJed Brown 	  len = ia[i+1] - ia[i];
1095b1a0a8a3SJed Brown 	  row = ja + ia[i];
1096b1a0a8a3SJed Brown 	  for (j=0; j<len; j++) {
1097b1a0a8a3SJed Brown 	    if (row[j] == i) { /* don't count diagonal */
1098b1a0a8a3SJed Brown 	      len--; break;
1099b1a0a8a3SJed Brown 	    }
1100b1a0a8a3SJed Brown 	  }
1101b1a0a8a3SJed Brown 	  nnz += len;
1102b1a0a8a3SJed Brown 	}
1103b1a0a8a3SJed Brown 	ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr);
1104b1a0a8a3SJed Brown 	ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr);
1105b1a0a8a3SJed Brown 	nnz    = 0;
1106b1a0a8a3SJed Brown 	iia[0] = 0;
1107b1a0a8a3SJed Brown 	for (i=0; i<na; i++) { /* fill adjacency */
1108b1a0a8a3SJed Brown 	  cnt = 0;
1109b1a0a8a3SJed Brown 	  len = ia[i+1] - ia[i];
1110b1a0a8a3SJed Brown 	  row = ja + ia[i];
1111b1a0a8a3SJed Brown 	  for (j=0; j<len; j++) {
1112b1a0a8a3SJed Brown 	    if (row[j] != i) { /* if not diagonal */
1113b1a0a8a3SJed Brown 	      jja[nnz+cnt++] = row[j];
1114b1a0a8a3SJed Brown 	    }
1115b1a0a8a3SJed Brown 	  }
1116b1a0a8a3SJed Brown 	  nnz += cnt;
1117b1a0a8a3SJed Brown 	  iia[i+1] = nnz;
1118b1a0a8a3SJed Brown 	}
1119b1a0a8a3SJed Brown 	/* Partitioning of the adjacency matrix */
1120b1a0a8a3SJed Brown 	ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,PETSC_NULL,&adj);CHKERRQ(ierr);
1121b1a0a8a3SJed Brown 	ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr);
1122b1a0a8a3SJed Brown 	ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr);
1123b1a0a8a3SJed Brown 	ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr);
1124b1a0a8a3SJed Brown 	ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr);
1125b1a0a8a3SJed Brown 	ierr = MatDestroy(adj);CHKERRQ(ierr);
1126b1a0a8a3SJed Brown 	foundpart = PETSC_TRUE;
1127b1a0a8a3SJed Brown       }
1128b1a0a8a3SJed Brown       ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr);
1129b1a0a8a3SJed Brown     }
1130b1a0a8a3SJed Brown     ierr = MatPartitioningDestroy(mpart);CHKERRQ(ierr);
1131b1a0a8a3SJed Brown   }
1132b1a0a8a3SJed Brown   if (iscopy) {ierr = MatDestroy(Ad);CHKERRQ(ierr);}
1133b1a0a8a3SJed Brown 
1134b1a0a8a3SJed Brown   ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr);
1135b1a0a8a3SJed Brown   *outis = is;
1136b1a0a8a3SJed Brown 
1137b1a0a8a3SJed Brown   if (!foundpart) {
1138b1a0a8a3SJed Brown 
1139b1a0a8a3SJed Brown     /* Partitioning by contiguous chunks of rows */
1140b1a0a8a3SJed Brown 
1141b1a0a8a3SJed Brown     PetscInt mbs   = (rend-rstart)/bs;
1142b1a0a8a3SJed Brown     PetscInt start = rstart;
1143b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1144b1a0a8a3SJed Brown       PetscInt count = (mbs/n + ((mbs % n) > i)) * bs;
1145b1a0a8a3SJed Brown       ierr   = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr);
1146b1a0a8a3SJed Brown       start += count;
1147b1a0a8a3SJed Brown     }
1148b1a0a8a3SJed Brown 
1149b1a0a8a3SJed Brown   } else {
1150b1a0a8a3SJed Brown 
1151b1a0a8a3SJed Brown     /* Partitioning by adjacency of diagonal block  */
1152b1a0a8a3SJed Brown 
1153b1a0a8a3SJed Brown     const PetscInt *numbering;
1154b1a0a8a3SJed Brown     PetscInt       *count,nidx,*indices,*newidx,start=0;
1155b1a0a8a3SJed Brown     /* Get node count in each partition */
1156b1a0a8a3SJed Brown     ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr);
1157b1a0a8a3SJed Brown     ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr);
1158b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1159b1a0a8a3SJed Brown       for (i=0; i<n; i++) count[i] *= bs;
1160b1a0a8a3SJed Brown     }
1161b1a0a8a3SJed Brown     /* Build indices from node numbering */
1162b1a0a8a3SJed Brown     ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr);
1163b1a0a8a3SJed Brown     ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1164b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */
1165b1a0a8a3SJed Brown     ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr);
1166b1a0a8a3SJed Brown     ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr);
1167b1a0a8a3SJed Brown     ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr);
1168b1a0a8a3SJed Brown     if (isbaij && bs > 1) { /* adjust for the block-aij case */
1169b1a0a8a3SJed Brown       ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr);
1170b1a0a8a3SJed Brown       for (i=0; i<nidx; i++)
1171b1a0a8a3SJed Brown 	for (j=0; j<bs; j++)
1172b1a0a8a3SJed Brown 	  newidx[i*bs+j] = indices[i]*bs + j;
1173b1a0a8a3SJed Brown       ierr = PetscFree(indices);CHKERRQ(ierr);
1174b1a0a8a3SJed Brown       nidx   *= bs;
1175b1a0a8a3SJed Brown       indices = newidx;
1176b1a0a8a3SJed Brown     }
1177b1a0a8a3SJed Brown     /* Shift to get global indices */
1178b1a0a8a3SJed Brown     for (i=0; i<nidx; i++) indices[i] += rstart;
1179b1a0a8a3SJed Brown 
1180b1a0a8a3SJed Brown     /* Build the index sets for each block */
1181b1a0a8a3SJed Brown     for (i=0; i<n; i++) {
1182b1a0a8a3SJed Brown       ierr   = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],PETSC_COPY_VALUES,&is[i]);CHKERRQ(ierr);
1183b1a0a8a3SJed Brown       ierr   = ISSort(is[i]);CHKERRQ(ierr);
1184b1a0a8a3SJed Brown       start += count[i];
1185b1a0a8a3SJed Brown     }
1186b1a0a8a3SJed Brown 
1187b1a0a8a3SJed Brown     ierr = PetscFree(count);
1188b1a0a8a3SJed Brown     ierr = PetscFree(indices);
1189b1a0a8a3SJed Brown     ierr = ISDestroy(isnumb);CHKERRQ(ierr);
1190b1a0a8a3SJed Brown     ierr = ISDestroy(ispart);CHKERRQ(ierr);
1191b1a0a8a3SJed Brown 
1192b1a0a8a3SJed Brown   }
1193b1a0a8a3SJed Brown 
1194b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1195b1a0a8a3SJed Brown }
1196b1a0a8a3SJed Brown 
1197b1a0a8a3SJed Brown #undef __FUNCT__
1198*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMDestroySubdomains"
1199b1a0a8a3SJed Brown /*@C
1200*f746d493SDmitry Karpeev    PCGASMDestroySubdomains - Destroys the index sets created with
1201*f746d493SDmitry Karpeev    PCGASMCreateSubdomains(). Should be called after setting subdomains
1202*f746d493SDmitry Karpeev    with PCGASMSetLocalSubdomains().
1203b1a0a8a3SJed Brown 
1204b1a0a8a3SJed Brown    Collective
1205b1a0a8a3SJed Brown 
1206b1a0a8a3SJed Brown    Input Parameters:
1207b1a0a8a3SJed Brown +  n - the number of index sets
1208b1a0a8a3SJed Brown .  is - the array of index sets
1209b1a0a8a3SJed Brown -  is_local - the array of local index sets, can be PETSC_NULL
1210b1a0a8a3SJed Brown 
1211b1a0a8a3SJed Brown    Level: advanced
1212b1a0a8a3SJed Brown 
1213*f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid
1214b1a0a8a3SJed Brown 
1215*f746d493SDmitry Karpeev .seealso: PCGASMCreateSubdomains(), PCGASMSetLocalSubdomains()
1216b1a0a8a3SJed Brown @*/
1217*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMDestroySubdomains(PetscInt n, IS is[], IS is_local[])
1218b1a0a8a3SJed Brown {
1219b1a0a8a3SJed Brown   PetscInt       i;
1220b1a0a8a3SJed Brown   PetscErrorCode ierr;
1221b1a0a8a3SJed Brown   PetscFunctionBegin;
1222b1a0a8a3SJed Brown   if (n <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n must be > 0: n = %D",n);
1223b1a0a8a3SJed Brown   PetscValidPointer(is,2);
1224b1a0a8a3SJed Brown   for (i=0; i<n; i++) { ierr = ISDestroy(is[i]);CHKERRQ(ierr); }
1225b1a0a8a3SJed Brown   ierr = PetscFree(is);CHKERRQ(ierr);
1226b1a0a8a3SJed Brown   if (is_local) {
1227b1a0a8a3SJed Brown     PetscValidPointer(is_local,3);
1228b1a0a8a3SJed Brown     for (i=0; i<n; i++) { ierr = ISDestroy(is_local[i]);CHKERRQ(ierr); }
1229b1a0a8a3SJed Brown     ierr = PetscFree(is_local);CHKERRQ(ierr);
1230b1a0a8a3SJed Brown   }
1231b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1232b1a0a8a3SJed Brown }
1233b1a0a8a3SJed Brown 
1234b1a0a8a3SJed Brown #undef __FUNCT__
1235*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains2D"
1236b1a0a8a3SJed Brown /*@
1237*f746d493SDmitry Karpeev    PCGASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz
1238b1a0a8a3SJed Brown    preconditioner for a two-dimensional problem on a regular grid.
1239b1a0a8a3SJed Brown 
1240b1a0a8a3SJed Brown    Not Collective
1241b1a0a8a3SJed Brown 
1242b1a0a8a3SJed Brown    Input Parameters:
1243b1a0a8a3SJed Brown +  m, n - the number of mesh points in the x and y directions
1244b1a0a8a3SJed Brown .  M, N - the number of subdomains in the x and y directions
1245b1a0a8a3SJed Brown .  dof - degrees of freedom per node
1246b1a0a8a3SJed Brown -  overlap - overlap in mesh lines
1247b1a0a8a3SJed Brown 
1248b1a0a8a3SJed Brown    Output Parameters:
1249b1a0a8a3SJed Brown +  Nsub - the number of subdomains created
1250b1a0a8a3SJed Brown .  is - array of index sets defining overlapping (if overlap > 0) subdomains
1251b1a0a8a3SJed Brown -  is_local - array of index sets defining non-overlapping subdomains
1252b1a0a8a3SJed Brown 
1253b1a0a8a3SJed Brown    Note:
1254b1a0a8a3SJed Brown    Presently PCAMSCreateSubdomains2d() is valid only for sequential
1255b1a0a8a3SJed Brown    preconditioners.  More general related routines are
1256*f746d493SDmitry Karpeev    PCGASMSetTotalSubdomains() and PCGASMSetLocalSubdomains().
1257b1a0a8a3SJed Brown 
1258b1a0a8a3SJed Brown    Level: advanced
1259b1a0a8a3SJed Brown 
1260*f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, 2D, regular grid
1261b1a0a8a3SJed Brown 
1262*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(),
1263*f746d493SDmitry Karpeev           PCGASMSetOverlap()
1264b1a0a8a3SJed Brown @*/
1265*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMCreateSubdomains2D(PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscInt dof,PetscInt overlap,PetscInt *Nsub,IS **is,IS **is_local)
1266b1a0a8a3SJed Brown {
1267b1a0a8a3SJed Brown   PetscInt       i,j,height,width,ystart,xstart,yleft,yright,xleft,xright,loc_outer;
1268b1a0a8a3SJed Brown   PetscErrorCode ierr;
1269b1a0a8a3SJed Brown   PetscInt       nidx,*idx,loc,ii,jj,count;
1270b1a0a8a3SJed Brown 
1271b1a0a8a3SJed Brown   PetscFunctionBegin;
1272b1a0a8a3SJed Brown   if (dof != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," ");
1273b1a0a8a3SJed Brown 
1274b1a0a8a3SJed Brown   *Nsub = N*M;
1275b1a0a8a3SJed Brown   ierr = PetscMalloc((*Nsub)*sizeof(IS*),is);CHKERRQ(ierr);
1276b1a0a8a3SJed Brown   ierr = PetscMalloc((*Nsub)*sizeof(IS*),is_local);CHKERRQ(ierr);
1277b1a0a8a3SJed Brown   ystart = 0;
1278b1a0a8a3SJed Brown   loc_outer = 0;
1279b1a0a8a3SJed Brown   for (i=0; i<N; i++) {
1280b1a0a8a3SJed Brown     height = n/N + ((n % N) > i); /* height of subdomain */
1281b1a0a8a3SJed Brown     if (height < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many N subdomains for mesh dimension n");
1282b1a0a8a3SJed Brown     yleft  = ystart - overlap; if (yleft < 0) yleft = 0;
1283b1a0a8a3SJed Brown     yright = ystart + height + overlap; if (yright > n) yright = n;
1284b1a0a8a3SJed Brown     xstart = 0;
1285b1a0a8a3SJed Brown     for (j=0; j<M; j++) {
1286b1a0a8a3SJed Brown       width = m/M + ((m % M) > j); /* width of subdomain */
1287b1a0a8a3SJed Brown       if (width < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many M subdomains for mesh dimension m");
1288b1a0a8a3SJed Brown       xleft  = xstart - overlap; if (xleft < 0) xleft = 0;
1289b1a0a8a3SJed Brown       xright = xstart + width + overlap; if (xright > m) xright = m;
1290b1a0a8a3SJed Brown       nidx   = (xright - xleft)*(yright - yleft);
1291b1a0a8a3SJed Brown       ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1292b1a0a8a3SJed Brown       loc    = 0;
1293b1a0a8a3SJed Brown       for (ii=yleft; ii<yright; ii++) {
1294b1a0a8a3SJed Brown         count = m*ii + xleft;
1295b1a0a8a3SJed Brown         for (jj=xleft; jj<xright; jj++) {
1296b1a0a8a3SJed Brown           idx[loc++] = count++;
1297b1a0a8a3SJed Brown         }
1298b1a0a8a3SJed Brown       }
1299b1a0a8a3SJed Brown       ierr = ISCreateGeneral(PETSC_COMM_SELF,nidx,idx,PETSC_COPY_VALUES,(*is)+loc_outer);CHKERRQ(ierr);
1300b1a0a8a3SJed Brown       if (overlap == 0) {
1301b1a0a8a3SJed Brown         ierr = PetscObjectReference((PetscObject)(*is)[loc_outer]);CHKERRQ(ierr);
1302b1a0a8a3SJed Brown         (*is_local)[loc_outer] = (*is)[loc_outer];
1303b1a0a8a3SJed Brown       } else {
1304b1a0a8a3SJed Brown         for (loc=0,ii=ystart; ii<ystart+height; ii++) {
1305b1a0a8a3SJed Brown           for (jj=xstart; jj<xstart+width; jj++) {
1306b1a0a8a3SJed Brown             idx[loc++] = m*ii + jj;
1307b1a0a8a3SJed Brown           }
1308b1a0a8a3SJed Brown         }
1309b1a0a8a3SJed Brown         ierr = ISCreateGeneral(PETSC_COMM_SELF,loc,idx,PETSC_COPY_VALUES,*is_local+loc_outer);CHKERRQ(ierr);
1310b1a0a8a3SJed Brown       }
1311b1a0a8a3SJed Brown       ierr = PetscFree(idx);CHKERRQ(ierr);
1312b1a0a8a3SJed Brown       xstart += width;
1313b1a0a8a3SJed Brown       loc_outer++;
1314b1a0a8a3SJed Brown     }
1315b1a0a8a3SJed Brown     ystart += height;
1316b1a0a8a3SJed Brown   }
1317b1a0a8a3SJed Brown   for (i=0; i<*Nsub; i++) { ierr = ISSort((*is)[i]);CHKERRQ(ierr); }
1318b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1319b1a0a8a3SJed Brown }
1320b1a0a8a3SJed Brown 
1321b1a0a8a3SJed Brown #undef __FUNCT__
1322*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubdomains"
1323b1a0a8a3SJed Brown /*@C
1324*f746d493SDmitry Karpeev     PCGASMGetLocalSubdomains - Gets the local subdomains (for this processor
1325b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1326b1a0a8a3SJed Brown 
1327b1a0a8a3SJed Brown     Not Collective
1328b1a0a8a3SJed Brown 
1329b1a0a8a3SJed Brown     Input Parameter:
1330b1a0a8a3SJed Brown .   pc - the preconditioner context
1331b1a0a8a3SJed Brown 
1332b1a0a8a3SJed Brown     Output Parameters:
1333b1a0a8a3SJed Brown +   n - the number of subdomains for this processor (default value = 1)
1334b1a0a8a3SJed Brown .   is - the index sets that define the subdomains for this processor
1335b1a0a8a3SJed Brown -   is_local - the index sets that define the local part of the subdomains for this processor (can be PETSC_NULL)
1336b1a0a8a3SJed Brown 
1337b1a0a8a3SJed Brown 
1338b1a0a8a3SJed Brown     Notes:
1339b1a0a8a3SJed Brown     The IS numbering is in the parallel, global numbering of the vector.
1340b1a0a8a3SJed Brown 
1341b1a0a8a3SJed Brown     Level: advanced
1342b1a0a8a3SJed Brown 
1343*f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz
1344b1a0a8a3SJed Brown 
1345*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1346*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubmatrices()
1347b1a0a8a3SJed Brown @*/
1348*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[])
1349b1a0a8a3SJed Brown {
1350*f746d493SDmitry Karpeev   PC_GASM         *osm;
1351b1a0a8a3SJed Brown   PetscErrorCode ierr;
1352b1a0a8a3SJed Brown   PetscBool      match;
1353b1a0a8a3SJed Brown 
1354b1a0a8a3SJed Brown   PetscFunctionBegin;
1355b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1356b1a0a8a3SJed Brown   PetscValidIntPointer(n,2);
1357b1a0a8a3SJed Brown   if (is) PetscValidPointer(is,3);
1358*f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1359b1a0a8a3SJed Brown   if (!match) {
1360b1a0a8a3SJed Brown     if (n)  *n  = 0;
1361b1a0a8a3SJed Brown     if (is) *is = PETSC_NULL;
1362b1a0a8a3SJed Brown   } else {
1363*f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1364b1a0a8a3SJed Brown     if (n)  *n  = osm->n_local_true;
1365b1a0a8a3SJed Brown     if (is) *is = osm->is;
1366b1a0a8a3SJed Brown     if (is_local) *is_local = osm->is_local;
1367b1a0a8a3SJed Brown   }
1368b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1369b1a0a8a3SJed Brown }
1370b1a0a8a3SJed Brown 
1371b1a0a8a3SJed Brown #undef __FUNCT__
1372*f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubmatrices"
1373b1a0a8a3SJed Brown /*@C
1374*f746d493SDmitry Karpeev     PCGASMGetLocalSubmatrices - Gets the local submatrices (for this processor
1375b1a0a8a3SJed Brown     only) for the additive Schwarz preconditioner.
1376b1a0a8a3SJed Brown 
1377b1a0a8a3SJed Brown     Not Collective
1378b1a0a8a3SJed Brown 
1379b1a0a8a3SJed Brown     Input Parameter:
1380b1a0a8a3SJed Brown .   pc - the preconditioner context
1381b1a0a8a3SJed Brown 
1382b1a0a8a3SJed Brown     Output Parameters:
1383b1a0a8a3SJed Brown +   n - the number of matrices for this processor (default value = 1)
1384b1a0a8a3SJed Brown -   mat - the matrices
1385b1a0a8a3SJed Brown 
1386b1a0a8a3SJed Brown 
1387b1a0a8a3SJed Brown     Level: advanced
1388b1a0a8a3SJed Brown 
1389*f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz, block Jacobi
1390b1a0a8a3SJed Brown 
1391*f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(),
1392*f746d493SDmitry Karpeev           PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubdomains()
1393b1a0a8a3SJed Brown @*/
1394*f746d493SDmitry Karpeev PetscErrorCode PETSCKSP_DLLEXPORT PCGASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[])
1395b1a0a8a3SJed Brown {
1396*f746d493SDmitry Karpeev   PC_GASM         *osm;
1397b1a0a8a3SJed Brown   PetscErrorCode ierr;
1398b1a0a8a3SJed Brown   PetscBool      match;
1399b1a0a8a3SJed Brown 
1400b1a0a8a3SJed Brown   PetscFunctionBegin;
1401b1a0a8a3SJed Brown   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1402b1a0a8a3SJed Brown   PetscValidIntPointer(n,2);
1403b1a0a8a3SJed Brown   if (mat) PetscValidPointer(mat,3);
1404b1a0a8a3SJed Brown   if (!pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp().");
1405*f746d493SDmitry Karpeev   ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr);
1406b1a0a8a3SJed Brown   if (!match) {
1407b1a0a8a3SJed Brown     if (n)   *n   = 0;
1408b1a0a8a3SJed Brown     if (mat) *mat = PETSC_NULL;
1409b1a0a8a3SJed Brown   } else {
1410*f746d493SDmitry Karpeev     osm = (PC_GASM*)pc->data;
1411b1a0a8a3SJed Brown     if (n)   *n   = osm->n_local_true;
1412b1a0a8a3SJed Brown     if (mat) *mat = osm->pmat;
1413b1a0a8a3SJed Brown   }
1414b1a0a8a3SJed Brown   PetscFunctionReturn(0);
1415b1a0a8a3SJed Brown }
1416