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