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