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