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