xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision 43371fb976311d310bba23bc5011761ad522b1da)
1 #include <../src/mat/impls/aij/seq/aij.h>
2 #include <../src/ksp/pc/impls/bddc/bddc.h>
3 #include <../src/ksp/pc/impls/bddc/bddcprivate.h>
4 #include <../src/mat/impls/dense/seq/dense.h>
5 #include <petscdmplex.h>
6 #include <petscblaslapack.h>
7 #include <petsc/private/sfimpl.h>
8 #include <petsc/private/dmpleximpl.h>
9 #include <petscdmda.h>
10 
11 static PetscErrorCode MatMPIAIJRestrict(Mat,MPI_Comm,Mat*);
12 
13 /* if range is true,  it returns B s.t. span{B} = range(A)
14    if range is false, it returns B s.t. range(B) _|_ range(A) */
15 PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B)
16 {
17 #if !defined(PETSC_USE_COMPLEX)
18   PetscScalar    *uwork,*data,*U, ds = 0.;
19   PetscReal      *sing;
20   PetscBLASInt   bM,bN,lwork,lierr,di = 1;
21   PetscInt       ulw,i,nr,nc,n;
22   PetscErrorCode ierr;
23 
24   PetscFunctionBegin;
25 #if defined(PETSC_MISSING_LAPACK_GESVD)
26   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"LAPACK _GESVD not available");
27 #else
28   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
29   if (!nr || !nc) PetscFunctionReturn(0);
30 
31   /* workspace */
32   if (!work) {
33     ulw  = PetscMax(PetscMax(1,5*PetscMin(nr,nc)),3*PetscMin(nr,nc)+PetscMax(nr,nc));
34     ierr = PetscMalloc1(ulw,&uwork);CHKERRQ(ierr);
35   } else {
36     ulw   = lw;
37     uwork = work;
38   }
39   n = PetscMin(nr,nc);
40   if (!rwork) {
41     ierr = PetscMalloc1(n,&sing);CHKERRQ(ierr);
42   } else {
43     sing = rwork;
44   }
45 
46   /* SVD */
47   ierr = PetscMalloc1(nr*nr,&U);CHKERRQ(ierr);
48   ierr = PetscBLASIntCast(nr,&bM);CHKERRQ(ierr);
49   ierr = PetscBLASIntCast(nc,&bN);CHKERRQ(ierr);
50   ierr = PetscBLASIntCast(ulw,&lwork);CHKERRQ(ierr);
51   ierr = MatDenseGetArray(A,&data);CHKERRQ(ierr);
52   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
53   PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("A","N",&bM,&bN,data,&bM,sing,U,&bM,&ds,&di,uwork,&lwork,&lierr));
54   ierr = PetscFPTrapPop();CHKERRQ(ierr);
55   if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in GESVD Lapack routine %d",(int)lierr);
56   ierr = MatDenseRestoreArray(A,&data);CHKERRQ(ierr);
57   for (i=0;i<n;i++) if (sing[i] < PETSC_SMALL) break;
58   if (!rwork) {
59     ierr = PetscFree(sing);CHKERRQ(ierr);
60   }
61   if (!work) {
62     ierr = PetscFree(uwork);CHKERRQ(ierr);
63   }
64   /* create B */
65   if (!range) {
66     ierr = MatCreateSeqDense(PETSC_COMM_SELF,nr,nr-i,NULL,B);CHKERRQ(ierr);
67     ierr = MatDenseGetArray(*B,&data);CHKERRQ(ierr);
68     ierr = PetscMemcpy(data,U+nr*i,(nr-i)*nr*sizeof(PetscScalar));CHKERRQ(ierr);
69   } else {
70     ierr = MatCreateSeqDense(PETSC_COMM_SELF,nr,i,NULL,B);CHKERRQ(ierr);
71     ierr = MatDenseGetArray(*B,&data);CHKERRQ(ierr);
72     ierr = PetscMemcpy(data,U,i*nr*sizeof(PetscScalar));CHKERRQ(ierr);
73   }
74   ierr = MatDenseRestoreArray(*B,&data);CHKERRQ(ierr);
75   ierr = PetscFree(U);CHKERRQ(ierr);
76 #endif
77 #else /* PETSC_USE_COMPLEX */
78   PetscFunctionBegin;
79   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for complexes");
80 #endif
81   PetscFunctionReturn(0);
82 }
83 
84 /* TODO REMOVE */
85 #if defined(PRINT_GDET)
86 static int inc = 0;
87 static int lev = 0;
88 #endif
89 
90 PetscErrorCode PCBDDCComputeNedelecChangeEdge(Mat lG, IS edge, IS extrow, IS extcol, IS corners, Mat* Gins, Mat* GKins, PetscScalar cvals[2], PetscScalar *work, PetscReal *rwork)
91 {
92   PetscErrorCode ierr;
93   Mat            GE,GEd;
94   PetscInt       rsize,csize,esize;
95   PetscScalar    *ptr;
96 
97   PetscFunctionBegin;
98   ierr = ISGetSize(edge,&esize);CHKERRQ(ierr);
99   if (!esize) PetscFunctionReturn(0);
100   ierr = ISGetSize(extrow,&rsize);CHKERRQ(ierr);
101   ierr = ISGetSize(extcol,&csize);CHKERRQ(ierr);
102 
103   /* gradients */
104   ptr  = work + 5*esize;
105   ierr = MatCreateSubMatrix(lG,extrow,extcol,MAT_INITIAL_MATRIX,&GE);CHKERRQ(ierr);
106   ierr = MatCreateSeqDense(PETSC_COMM_SELF,rsize,csize,ptr,Gins);CHKERRQ(ierr);
107   ierr = MatConvert(GE,MATSEQDENSE,MAT_REUSE_MATRIX,Gins);CHKERRQ(ierr);
108   ierr = MatDestroy(&GE);CHKERRQ(ierr);
109 
110   /* constants */
111   ptr += rsize*csize;
112   ierr = MatCreateSeqDense(PETSC_COMM_SELF,esize,csize,ptr,&GEd);CHKERRQ(ierr);
113   ierr = MatCreateSubMatrix(lG,edge,extcol,MAT_INITIAL_MATRIX,&GE);CHKERRQ(ierr);
114   ierr = MatConvert(GE,MATSEQDENSE,MAT_REUSE_MATRIX,&GEd);CHKERRQ(ierr);
115   ierr = MatDestroy(&GE);CHKERRQ(ierr);
116   ierr = MatDenseOrthogonalRangeOrComplement(GEd,PETSC_FALSE,5*esize,work,rwork,GKins);CHKERRQ(ierr);
117   ierr = MatDestroy(&GEd);CHKERRQ(ierr);
118 
119   if (corners) {
120     Mat            GEc;
121     PetscScalar    *vals,v;
122 
123     ierr = MatCreateSubMatrix(lG,edge,corners,MAT_INITIAL_MATRIX,&GEc);CHKERRQ(ierr);
124     ierr = MatTransposeMatMult(GEc,*GKins,MAT_INITIAL_MATRIX,1.0,&GEd);CHKERRQ(ierr);
125     ierr = MatDenseGetArray(GEd,&vals);CHKERRQ(ierr);
126     /* v    = PetscAbsScalar(vals[0]) */;
127     v    = 1.;
128     cvals[0] = vals[0]/v;
129     cvals[1] = vals[1]/v;
130     ierr = MatDenseRestoreArray(GEd,&vals);CHKERRQ(ierr);
131     ierr = MatScale(*GKins,1./v);CHKERRQ(ierr);
132 #if defined(PRINT_GDET)
133     {
134       PetscViewer viewer;
135       char filename[256];
136       sprintf(filename,"Gdet_l%d_r%d_cc%d.m",lev,PetscGlobalRank,inc++);
137       ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer);CHKERRQ(ierr);
138       ierr = PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr);
139       ierr = PetscObjectSetName((PetscObject)GEc,"GEc");CHKERRQ(ierr);
140       ierr = MatView(GEc,viewer);CHKERRQ(ierr);
141       ierr = PetscObjectSetName((PetscObject)(*GKins),"GK");CHKERRQ(ierr);
142       ierr = MatView(*GKins,viewer);CHKERRQ(ierr);
143       ierr = PetscObjectSetName((PetscObject)GEd,"Gproj");CHKERRQ(ierr);
144       ierr = MatView(GEd,viewer);CHKERRQ(ierr);
145       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
146     }
147 #endif
148     ierr = MatDestroy(&GEd);CHKERRQ(ierr);
149     ierr = MatDestroy(&GEc);CHKERRQ(ierr);
150   }
151 
152   PetscFunctionReturn(0);
153 }
154 
155 PetscErrorCode PCBDDCNedelecSupport(PC pc)
156 {
157   PC_BDDC                *pcbddc = (PC_BDDC*)pc->data;
158   Mat_IS                 *matis = (Mat_IS*)pc->pmat->data;
159   Mat                    G,T,conn,lG,lGt,lGis,lGall,lGe,lGinit;
160   Vec                    tvec;
161   PetscSF                sfv;
162   ISLocalToGlobalMapping el2g,vl2g,fl2g,al2g;
163   MPI_Comm               comm;
164   IS                     lned,primals,allprimals,nedfieldlocal;
165   IS                     *eedges,*extrows,*extcols,*alleedges;
166   PetscBT                btv,bte,btvc,btb,btbd,btvcand,btvi,btee,bter;
167   PetscScalar            *vals,*work;
168   PetscReal              *rwork;
169   const PetscInt         *idxs,*ii,*jj,*iit,*jjt;
170   PetscInt               ne,nv,Lv,order,n,field;
171   PetscInt               n_neigh,*neigh,*n_shared,**shared;
172   PetscInt               i,j,extmem,cum,maxsize,nee;
173   PetscInt               *extrow,*extrowcum,*marks,*vmarks,*gidxs;
174   PetscInt               *sfvleaves,*sfvroots;
175   PetscInt               *corners,*cedges;
176   PetscInt               *ecount,**eneighs,*vcount,**vneighs;
177 #if defined(PETSC_USE_DEBUG)
178   PetscInt               *emarks;
179 #endif
180   PetscBool              print,eerr,done,lrc[2],conforming,global,singular,setprimal;
181   PetscErrorCode         ierr;
182 
183   PetscFunctionBegin;
184   /* If the discrete gradient is defined for a subset of dofs and global is true,
185      it assumes G is given in global ordering for all the dofs.
186      Otherwise, the ordering is global for the Nedelec field */
187   order      = pcbddc->nedorder;
188   conforming = pcbddc->conforming;
189   field      = pcbddc->nedfield;
190   global     = pcbddc->nedglobal;
191   setprimal  = PETSC_FALSE;
192   print      = PETSC_FALSE;
193   singular   = PETSC_FALSE;
194 
195   /* Command line customization */
196   ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)pc),((PetscObject)pc)->prefix,"BDDC Nedelec options","PC");CHKERRQ(ierr);
197   ierr = PetscOptionsBool("-pc_bddc_nedelec_field_primal","All edge dofs set as primals: Toselli's algorithm C",NULL,setprimal,&setprimal,NULL);CHKERRQ(ierr);
198   ierr = PetscOptionsBool("-pc_bddc_nedelec_singular","Infer nullspace from discrete gradient",NULL,singular,&singular,NULL);CHKERRQ(ierr);
199   ierr = PetscOptionsInt("-pc_bddc_nedelec_order","Test variable order code (to be removed)",NULL,order,&order,NULL);CHKERRQ(ierr);
200   /* print debug info TODO: to be removed */
201   ierr = PetscOptionsBool("-pc_bddc_nedelec_print","Print debug info",NULL,print,&print,NULL);CHKERRQ(ierr);
202   ierr = PetscOptionsEnd();CHKERRQ(ierr);
203 
204   /* Return if there are no edges in the decomposition and the problem is not singular */
205   ierr = MatGetLocalToGlobalMapping(pc->pmat,&al2g,NULL);CHKERRQ(ierr);
206   ierr = ISLocalToGlobalMappingGetSize(al2g,&n);CHKERRQ(ierr);
207   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
208   if (!singular) {
209     ierr   = VecGetArrayRead(matis->counter,(const PetscScalar**)&vals);CHKERRQ(ierr);
210     lrc[0] = PETSC_FALSE;
211     for (i=0;i<n;i++) {
212       if (PetscRealPart(vals[i]) > 2.) {
213         lrc[0] = PETSC_TRUE;
214         break;
215       }
216     }
217     ierr = VecRestoreArrayRead(matis->counter,(const PetscScalar**)&vals);CHKERRQ(ierr);
218     ierr = MPIU_Allreduce(&lrc[0],&lrc[1],1,MPIU_BOOL,MPI_LOR,comm);CHKERRQ(ierr);
219     if (!lrc[1]) PetscFunctionReturn(0);
220   }
221 
222   /* Get Nedelec field */
223   ierr = MatISSetUpSF(pc->pmat);CHKERRQ(ierr);
224   if (pcbddc->n_ISForDofsLocal && field >= pcbddc->n_ISForDofsLocal) SETERRQ2(comm,PETSC_ERR_USER,"Invalid field for Nedelec %d: number of fields is %d",field,pcbddc->n_ISForDofsLocal);
225   if (pcbddc->n_ISForDofsLocal && field >= 0) {
226     ierr          = PetscObjectReference((PetscObject)pcbddc->ISForDofsLocal[field]);CHKERRQ(ierr);
227     nedfieldlocal = pcbddc->ISForDofsLocal[field];
228     ierr          = ISGetLocalSize(nedfieldlocal,&ne);CHKERRQ(ierr);
229   } else if (!pcbddc->n_ISForDofsLocal && field != PETSC_DECIDE) {
230     ne            = n;
231     nedfieldlocal = NULL;
232     global        = PETSC_TRUE;
233   } else if (field == PETSC_DECIDE) {
234     PetscInt rst,ren,*idx;
235 
236     ierr = PetscMemzero(matis->sf_leafdata,n*sizeof(PetscInt));CHKERRQ(ierr);
237     ierr = PetscMemzero(matis->sf_rootdata,pc->pmat->rmap->n*sizeof(PetscInt));CHKERRQ(ierr);
238     ierr = MatGetOwnershipRange(pcbddc->discretegradient,&rst,&ren);CHKERRQ(ierr);
239     for (i=rst;i<ren;i++) {
240       PetscInt nc;
241 
242       ierr = MatGetRow(pcbddc->discretegradient,i,&nc,NULL,NULL);CHKERRQ(ierr);
243       if (nc > 1) matis->sf_rootdata[i-rst] = 1;
244       ierr = MatRestoreRow(pcbddc->discretegradient,i,&nc,NULL,NULL);CHKERRQ(ierr);
245     }
246     ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
247     ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
248     ierr = PetscMalloc1(n,&idx);CHKERRQ(ierr);
249     for (i=0,ne=0;i<n;i++) if (matis->sf_leafdata[i]) idx[ne++] = i;
250     ierr = ISCreateGeneral(comm,ne,idx,PETSC_OWN_POINTER,&nedfieldlocal);CHKERRQ(ierr);
251   } else {
252     SETERRQ(comm,PETSC_ERR_USER,"When multiple fields are present, the Nedelec field has to be specified");
253   }
254 
255   /* Sanity checks */
256   if (!order && !conforming) SETERRQ(comm,PETSC_ERR_SUP,"Variable order and non-conforming spaces are not supported at the same time");
257   if (pcbddc->user_ChangeOfBasisMatrix) SETERRQ(comm,PETSC_ERR_SUP,"Cannot generate Nedelec support with user defined change of basis");
258   if (order && ne%order) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"The number of local edge dofs %d it's not a multiple of the order %d",ne,order);
259 
260   /* Just set primal dofs and return */
261   if (setprimal) {
262     IS       enedfieldlocal;
263     PetscInt *eidxs;
264 
265     ierr = PetscMalloc1(ne,&eidxs);CHKERRQ(ierr);
266     ierr = VecGetArrayRead(matis->counter,(const PetscScalar**)&vals);CHKERRQ(ierr);
267     if (nedfieldlocal) {
268       ierr = ISGetIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
269       for (i=0,cum=0;i<ne;i++) {
270         if (PetscRealPart(vals[idxs[i]]) > 2.) {
271           eidxs[cum++] = idxs[i];
272         }
273       }
274       ierr = ISRestoreIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
275     } else {
276       for (i=0,cum=0;i<ne;i++) {
277         if (PetscRealPart(vals[i]) > 2.) {
278           eidxs[cum++] = i;
279         }
280       }
281     }
282     ierr = VecRestoreArrayRead(matis->counter,(const PetscScalar**)&vals);CHKERRQ(ierr);
283     ierr = ISCreateGeneral(comm,cum,eidxs,PETSC_COPY_VALUES,&enedfieldlocal);CHKERRQ(ierr);
284     ierr = PCBDDCSetPrimalVerticesLocalIS(pc,enedfieldlocal);CHKERRQ(ierr);
285     ierr = PetscFree(eidxs);CHKERRQ(ierr);
286     ierr = ISDestroy(&nedfieldlocal);CHKERRQ(ierr);
287     ierr = ISDestroy(&enedfieldlocal);CHKERRQ(ierr);
288     PetscFunctionReturn(0);
289   }
290 
291   /* Compute some l2g maps */
292   if (nedfieldlocal) {
293     IS is;
294 
295     /* need to map from the local Nedelec field to local numbering */
296     ierr = ISLocalToGlobalMappingCreateIS(nedfieldlocal,&fl2g);CHKERRQ(ierr);
297     /* need to map from the local Nedelec field to global numbering for the whole dofs*/
298     ierr = ISLocalToGlobalMappingApplyIS(al2g,nedfieldlocal,&is);CHKERRQ(ierr);
299     ierr = ISLocalToGlobalMappingCreateIS(is,&al2g);CHKERRQ(ierr);
300     /* need to map from the local Nedelec field to global numbering (for Nedelec only) */
301     if (global) {
302       ierr = PetscObjectReference((PetscObject)al2g);CHKERRQ(ierr);
303       el2g = al2g;
304     } else {
305       IS gis;
306 
307       ierr = ISRenumber(is,NULL,NULL,&gis);CHKERRQ(ierr);
308       ierr = ISLocalToGlobalMappingCreateIS(gis,&el2g);CHKERRQ(ierr);
309       ierr = ISDestroy(&gis);CHKERRQ(ierr);
310     }
311     ierr = ISDestroy(&is);CHKERRQ(ierr);
312   } else {
313     /* restore default */
314     pcbddc->nedfield = -1;
315     /* one ref for the destruction of al2g, one for el2g */
316     ierr = PetscObjectReference((PetscObject)al2g);CHKERRQ(ierr);
317     ierr = PetscObjectReference((PetscObject)al2g);CHKERRQ(ierr);
318     el2g = al2g;
319     fl2g = NULL;
320   }
321 
322   /* Start communication to drop connections for interior edges (for cc analysis only) */
323   ierr = PetscMemzero(matis->sf_leafdata,n*sizeof(PetscInt));CHKERRQ(ierr);
324   ierr = PetscMemzero(matis->sf_rootdata,pc->pmat->rmap->n*sizeof(PetscInt));CHKERRQ(ierr);
325   if (nedfieldlocal) {
326     ierr = ISGetIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
327     for (i=0;i<ne;i++) matis->sf_leafdata[idxs[i]] = 1;
328     ierr = ISRestoreIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
329   } else {
330     for (i=0;i<ne;i++) matis->sf_leafdata[i] = 1;
331   }
332   ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_SUM);CHKERRQ(ierr);
333   ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_SUM);CHKERRQ(ierr);
334 
335   if (!singular) { /* drop connections with interior edges to avoid unneeded communications and memory movements */
336     ierr = MatDuplicate(pcbddc->discretegradient,MAT_COPY_VALUES,&G);CHKERRQ(ierr);
337     ierr = MatSetOption(G,MAT_KEEP_NONZERO_PATTERN,PETSC_FALSE);CHKERRQ(ierr);
338     if (global) {
339       PetscInt rst;
340 
341       ierr = MatGetOwnershipRange(G,&rst,NULL);CHKERRQ(ierr);
342       for (i=0,cum=0;i<pc->pmat->rmap->n;i++) {
343         if (matis->sf_rootdata[i] < 2) {
344           matis->sf_rootdata[cum++] = i + rst;
345         }
346       }
347       ierr = MatSetOption(G,MAT_NO_OFF_PROC_ZERO_ROWS,PETSC_TRUE);CHKERRQ(ierr);
348       ierr = MatZeroRows(G,cum,matis->sf_rootdata,0.,NULL,NULL);CHKERRQ(ierr);
349     } else {
350       PetscInt *tbz;
351 
352       ierr = PetscMalloc1(ne,&tbz);CHKERRQ(ierr);
353       ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
354       ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
355       ierr = ISGetIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
356       for (i=0,cum=0;i<ne;i++)
357         if (matis->sf_leafdata[idxs[i]] == 1)
358           tbz[cum++] = i;
359       ierr = ISRestoreIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
360       ierr = ISLocalToGlobalMappingApply(el2g,cum,tbz,tbz);CHKERRQ(ierr);
361       ierr = MatZeroRows(G,cum,tbz,0.,NULL,NULL);CHKERRQ(ierr);
362       ierr = PetscFree(tbz);CHKERRQ(ierr);
363     }
364   } else { /* we need the entire G to infer the nullspace */
365     ierr = PetscObjectReference((PetscObject)pcbddc->discretegradient);CHKERRQ(ierr);
366     G    = pcbddc->discretegradient;
367   }
368 
369   /* Extract subdomain relevant rows of G */
370   ierr = ISLocalToGlobalMappingGetIndices(el2g,&idxs);CHKERRQ(ierr);
371   ierr = ISCreateGeneral(comm,ne,idxs,PETSC_USE_POINTER,&lned);CHKERRQ(ierr);
372   ierr = MatCreateSubMatrix(G,lned,NULL,MAT_INITIAL_MATRIX,&lGall);CHKERRQ(ierr);
373   ierr = ISLocalToGlobalMappingRestoreIndices(el2g,&idxs);CHKERRQ(ierr);
374   ierr = ISDestroy(&lned);CHKERRQ(ierr);
375   ierr = MatConvert(lGall,MATIS,MAT_INITIAL_MATRIX,&lGis);CHKERRQ(ierr);
376   ierr = MatDestroy(&lGall);CHKERRQ(ierr);
377   ierr = MatISGetLocalMat(lGis,&lG);CHKERRQ(ierr);
378 
379   /* SF for nodal dofs communications */
380   ierr = MatGetLocalSize(G,NULL,&Lv);CHKERRQ(ierr);
381   ierr = MatGetLocalToGlobalMapping(lGis,NULL,&vl2g);CHKERRQ(ierr);
382   ierr = PetscObjectReference((PetscObject)vl2g);CHKERRQ(ierr);
383   ierr = ISLocalToGlobalMappingGetSize(vl2g,&nv);CHKERRQ(ierr);
384   ierr = PetscSFCreate(comm,&sfv);CHKERRQ(ierr);
385   ierr = ISLocalToGlobalMappingGetIndices(vl2g,&idxs);CHKERRQ(ierr);
386   ierr = PetscSFSetGraphLayout(sfv,lGis->cmap,nv,NULL,PETSC_OWN_POINTER,idxs);CHKERRQ(ierr);
387   ierr = ISLocalToGlobalMappingRestoreIndices(vl2g,&idxs);CHKERRQ(ierr);
388   i    = singular ? 2 : 1;
389   ierr = PetscMalloc2(i*nv,&sfvleaves,i*Lv,&sfvroots);CHKERRQ(ierr);
390 
391   /* Destroy temporary G created in MATIS format and modified G */
392   ierr = PetscObjectReference((PetscObject)lG);CHKERRQ(ierr);
393   ierr = MatDestroy(&lGis);CHKERRQ(ierr);
394   ierr = MatDestroy(&G);CHKERRQ(ierr);
395 
396   if (print) {
397     ierr = PetscObjectSetName((PetscObject)lG,"initial_lG");CHKERRQ(ierr);
398     ierr = MatView(lG,NULL);CHKERRQ(ierr);
399   }
400 
401   /* Save lG for values insertion in change of basis */
402   ierr = MatDuplicate(lG,MAT_COPY_VALUES,&lGinit);CHKERRQ(ierr);
403 
404   /* Analyze the edge-nodes connections (duplicate lG) */
405   ierr = MatDuplicate(lG,MAT_COPY_VALUES,&lGe);CHKERRQ(ierr);
406   ierr = MatSetOption(lGe,MAT_KEEP_NONZERO_PATTERN,PETSC_FALSE);CHKERRQ(ierr);
407   ierr = PetscBTCreate(nv,&btv);CHKERRQ(ierr);
408   ierr = PetscBTCreate(ne,&bte);CHKERRQ(ierr);
409   ierr = PetscBTCreate(ne,&btb);CHKERRQ(ierr);
410   ierr = PetscBTCreate(ne,&btbd);CHKERRQ(ierr);
411   ierr = PetscBTCreate(nv,&btvcand);CHKERRQ(ierr);
412   /* need to import the boundary specification to ensure the
413      proper detection of coarse edges' endpoints */
414   if (pcbddc->DirichletBoundariesLocal) {
415     IS is;
416 
417     if (fl2g) {
418       ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_MASK,pcbddc->DirichletBoundariesLocal,&is);CHKERRQ(ierr);
419     } else {
420       is = pcbddc->DirichletBoundariesLocal;
421     }
422     ierr = ISGetLocalSize(is,&cum);CHKERRQ(ierr);
423     ierr = ISGetIndices(is,&idxs);CHKERRQ(ierr);
424     for (i=0;i<cum;i++) {
425       if (idxs[i] >= 0) {
426         ierr = PetscBTSet(btb,idxs[i]);CHKERRQ(ierr);
427         ierr = PetscBTSet(btbd,idxs[i]);CHKERRQ(ierr);
428       }
429     }
430     ierr = ISRestoreIndices(is,&idxs);CHKERRQ(ierr);
431     if (fl2g) {
432       ierr = ISDestroy(&is);CHKERRQ(ierr);
433     }
434   }
435   if (pcbddc->NeumannBoundariesLocal) {
436     IS is;
437 
438     if (fl2g) {
439       ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_MASK,pcbddc->NeumannBoundariesLocal,&is);CHKERRQ(ierr);
440     } else {
441       is = pcbddc->NeumannBoundariesLocal;
442     }
443     ierr = ISGetLocalSize(is,&cum);CHKERRQ(ierr);
444     ierr = ISGetIndices(is,&idxs);CHKERRQ(ierr);
445     for (i=0;i<cum;i++) {
446       if (idxs[i] >= 0) {
447         ierr = PetscBTSet(btb,idxs[i]);CHKERRQ(ierr);
448       }
449     }
450     ierr = ISRestoreIndices(is,&idxs);CHKERRQ(ierr);
451     if (fl2g) {
452       ierr = ISDestroy(&is);CHKERRQ(ierr);
453     }
454   }
455 
456   /* Count neighs per dof */
457   ierr = ISLocalToGlobalMappingGetNodeInfo(el2g,NULL,&ecount,&eneighs);CHKERRQ(ierr);
458   ierr = ISLocalToGlobalMappingGetNodeInfo(vl2g,NULL,&vcount,&vneighs);CHKERRQ(ierr);
459 
460   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
461      for proper detection of coarse edges' endpoints */
462   ierr = PetscBTCreate(ne,&btee);CHKERRQ(ierr);
463   for (i=0;i<ne;i++) {
464     if ((ecount[i] > 2 && !PetscBTLookup(btbd,i)) || (ecount[i] == 2 && PetscBTLookup(btb,i))) {
465       ierr = PetscBTSet(btee,i);CHKERRQ(ierr);
466     }
467   }
468   ierr = PetscMalloc1(ne,&marks);CHKERRQ(ierr);
469   if (!conforming) {
470     ierr = MatTranspose(lGe,MAT_INITIAL_MATRIX,&lGt);CHKERRQ(ierr);
471     ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
472   }
473   ierr = MatGetRowIJ(lGe,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
474   ierr = MatSeqAIJGetArray(lGe,&vals);CHKERRQ(ierr);
475   cum  = 0;
476   for (i=0;i<ne;i++) {
477     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
478     if (!PetscBTLookup(btee,i)) {
479       marks[cum++] = i;
480       continue;
481     }
482     /* set badly connected edge dofs as primal */
483     if (!conforming) {
484       if (ii[i+1]-ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
485         marks[cum++] = i;
486         ierr = PetscBTSet(bte,i);CHKERRQ(ierr);
487         for (j=ii[i];j<ii[i+1];j++) {
488           ierr = PetscBTSet(btv,jj[j]);CHKERRQ(ierr);
489         }
490       } else {
491         /* every edge dofs should be connected trough a certain number of nodal dofs
492            to other edge dofs belonging to coarse edges
493            - at most 2 endpoints
494            - order-1 interior nodal dofs
495            - no undefined nodal dofs (nconn < order)
496         */
497         PetscInt ends = 0,ints = 0, undef = 0;
498         for (j=ii[i];j<ii[i+1];j++) {
499           PetscInt v = jj[j],k;
500           PetscInt nconn = iit[v+1]-iit[v];
501           for (k=iit[v];k<iit[v+1];k++) if (!PetscBTLookup(btee,jjt[k])) nconn--;
502           if (nconn > order) ends++;
503           else if (nconn == order) ints++;
504           else undef++;
505         }
506         if (undef || ends > 2 || ints != order -1) {
507           marks[cum++] = i;
508           ierr = PetscBTSet(bte,i);CHKERRQ(ierr);
509           for (j=ii[i];j<ii[i+1];j++) {
510             ierr = PetscBTSet(btv,jj[j]);CHKERRQ(ierr);
511           }
512         }
513       }
514     }
515     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
516     if (!order && ii[i+1] != ii[i]) {
517       PetscScalar val = 1./(ii[i+1]-ii[i]-1);
518       for (j=ii[i];j<ii[i+1];j++) vals[j] = val;
519     }
520   }
521   ierr = PetscBTDestroy(&btee);CHKERRQ(ierr);
522   ierr = MatSeqAIJRestoreArray(lGe,&vals);CHKERRQ(ierr);
523   ierr = MatRestoreRowIJ(lGe,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
524   if (!conforming) {
525     ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
526     ierr = MatDestroy(&lGt);CHKERRQ(ierr);
527   }
528   ierr = MatZeroRows(lGe,cum,marks,0.,NULL,NULL);CHKERRQ(ierr);
529 
530   /* identify splitpoints and corner candidates */
531   ierr = MatTranspose(lGe,MAT_INITIAL_MATRIX,&lGt);CHKERRQ(ierr);
532   if (print) {
533     ierr = PetscObjectSetName((PetscObject)lGe,"edgerestr_lG");CHKERRQ(ierr);
534     ierr = MatView(lGe,NULL);CHKERRQ(ierr);
535     ierr = PetscObjectSetName((PetscObject)lGt,"edgerestr_lGt");CHKERRQ(ierr);
536     ierr = MatView(lGt,NULL);CHKERRQ(ierr);
537   }
538   ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
539   ierr = MatSeqAIJGetArray(lGt,&vals);CHKERRQ(ierr);
540   for (i=0;i<nv;i++) {
541     PetscInt  ord = order, test = ii[i+1]-ii[i], vc = vcount[i];
542     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
543     if (!order) { /* variable order */
544       PetscReal vorder = 0.;
545 
546       for (j=ii[i];j<ii[i+1];j++) vorder += PetscRealPart(vals[j]);
547       test = PetscFloorReal(vorder+10.*PETSC_SQRT_MACHINE_EPSILON);
548       if (vorder-test > PETSC_SQRT_MACHINE_EPSILON) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected value for vorder: %g (%d)",vorder,test);
549       ord  = 1;
550     }
551 #if defined(PETSC_USE_DEBUG)
552     if (test%ord) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of edge dofs %d connected with nodal dof %d with order %d",test,i,ord);
553 #endif
554     for (j=ii[i];j<ii[i+1] && sneighs;j++) {
555       if (PetscBTLookup(btbd,jj[j])) {
556         bdir = PETSC_TRUE;
557         break;
558       }
559       if (vc != ecount[jj[j]]) {
560         sneighs = PETSC_FALSE;
561       } else {
562         PetscInt k,*vn = vneighs[i], *en = eneighs[jj[j]];
563         for (k=0;k<vc;k++) {
564           if (vn[k] != en[k]) {
565             sneighs = PETSC_FALSE;
566             break;
567           }
568         }
569       }
570     }
571     if (!sneighs || test >= 3*ord || bdir) { /* splitpoints */
572       if (print) PetscPrintf(PETSC_COMM_SELF,"SPLITPOINT %d (%d %d %d)\n",i,!sneighs,test >= 3*ord,bdir);
573       ierr = PetscBTSet(btv,i);CHKERRQ(ierr);
574     } else if (test == ord) {
575       if (order == 1 || (!order && ii[i+1]-ii[i] == 1)) {
576         if (print) PetscPrintf(PETSC_COMM_SELF,"ENDPOINT %d\n",i);
577         ierr = PetscBTSet(btv,i);CHKERRQ(ierr);
578       } else {
579         if (print) PetscPrintf(PETSC_COMM_SELF,"CORNER CANDIDATE %d\n",i);
580         ierr = PetscBTSet(btvcand,i);CHKERRQ(ierr);
581       }
582     }
583   }
584   ierr = ISLocalToGlobalMappingRestoreNodeInfo(el2g,NULL,&ecount,&eneighs);CHKERRQ(ierr);
585   ierr = ISLocalToGlobalMappingRestoreNodeInfo(vl2g,NULL,&vcount,&vneighs);CHKERRQ(ierr);
586   ierr = PetscBTDestroy(&btbd);CHKERRQ(ierr);
587 
588   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
589   if (order != 1) {
590     if (print) PetscPrintf(PETSC_COMM_SELF,"INSPECTING CANDIDATES\n");
591     ierr = MatGetRowIJ(lGe,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
592     for (i=0;i<nv;i++) {
593       if (PetscBTLookup(btvcand,i)) {
594         PetscBool found = PETSC_FALSE;
595         for (j=ii[i];j<ii[i+1] && !found;j++) {
596           PetscInt k,e = jj[j];
597           if (PetscBTLookup(bte,e)) continue;
598           for (k=iit[e];k<iit[e+1];k++) {
599             PetscInt v = jjt[k];
600             if (v != i && PetscBTLookup(btvcand,v)) {
601               found = PETSC_TRUE;
602               break;
603             }
604           }
605         }
606         if (!found) {
607           if (print) PetscPrintf(PETSC_COMM_SELF,"  CANDIDATE %d CLEARED\n",i);
608           ierr = PetscBTClear(btvcand,i);CHKERRQ(ierr);
609         } else {
610           if (print) PetscPrintf(PETSC_COMM_SELF,"  CANDIDATE %d ACCEPTED\n",i);
611         }
612       }
613     }
614     ierr = MatRestoreRowIJ(lGe,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
615   }
616   ierr = MatSeqAIJRestoreArray(lGt,&vals);CHKERRQ(ierr);
617   ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
618   ierr = MatDestroy(&lGe);CHKERRQ(ierr);
619 
620   /* Get the local G^T explicitly */
621   ierr = MatDestroy(&lGt);CHKERRQ(ierr);
622   ierr = MatTranspose(lG,MAT_INITIAL_MATRIX,&lGt);CHKERRQ(ierr);
623   ierr = MatSetOption(lGt,MAT_KEEP_NONZERO_PATTERN,PETSC_FALSE);CHKERRQ(ierr);
624 
625   /* Mark interior nodal dofs */
626   ierr = ISLocalToGlobalMappingGetInfo(vl2g,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
627   ierr = PetscBTCreate(nv,&btvi);CHKERRQ(ierr);
628   for (i=1;i<n_neigh;i++) {
629     for (j=0;j<n_shared[i];j++) {
630       ierr = PetscBTSet(btvi,shared[i][j]);CHKERRQ(ierr);
631     }
632   }
633   ierr = ISLocalToGlobalMappingRestoreInfo(vl2g,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
634 
635   /* communicate corners and splitpoints */
636   ierr = PetscMalloc1(nv,&vmarks);CHKERRQ(ierr);
637   ierr = PetscMemzero(sfvleaves,nv*sizeof(PetscInt));CHKERRQ(ierr);
638   ierr = PetscMemzero(sfvroots,Lv*sizeof(PetscInt));CHKERRQ(ierr);
639   for (i=0;i<nv;i++) if (PetscUnlikely(PetscBTLookup(btv,i))) sfvleaves[i] = 1;
640 
641   if (print) {
642     IS tbz;
643 
644     cum = 0;
645     for (i=0;i<nv;i++)
646       if (sfvleaves[i])
647         vmarks[cum++] = i;
648 
649     ierr = ISCreateGeneral(PETSC_COMM_SELF,cum,vmarks,PETSC_COPY_VALUES,&tbz);CHKERRQ(ierr);
650     ierr = PetscObjectSetName((PetscObject)tbz,"corners_to_be_zeroed_local");CHKERRQ(ierr);
651     ierr = ISView(tbz,NULL);CHKERRQ(ierr);
652     ierr = ISDestroy(&tbz);CHKERRQ(ierr);
653   }
654 
655   ierr = PetscSFReduceBegin(sfv,MPIU_INT,sfvleaves,sfvroots,MPI_SUM);CHKERRQ(ierr);
656   ierr = PetscSFReduceEnd(sfv,MPIU_INT,sfvleaves,sfvroots,MPI_SUM);CHKERRQ(ierr);
657   ierr = PetscSFBcastBegin(sfv,MPIU_INT,sfvroots,sfvleaves);CHKERRQ(ierr);
658   ierr = PetscSFBcastEnd(sfv,MPIU_INT,sfvroots,sfvleaves);CHKERRQ(ierr);
659 
660   /* Zero rows of lGt corresponding to identified corners
661      and interior nodal dofs */
662   cum = 0;
663   for (i=0;i<nv;i++) {
664     if (sfvleaves[i]) {
665       vmarks[cum++] = i;
666       ierr = PetscBTSet(btv,i);CHKERRQ(ierr);
667     }
668     if (!PetscBTLookup(btvi,i)) vmarks[cum++] = i;
669   }
670   ierr = PetscBTDestroy(&btvi);CHKERRQ(ierr);
671   if (print) {
672     IS tbz;
673 
674     ierr = ISCreateGeneral(PETSC_COMM_SELF,cum,vmarks,PETSC_COPY_VALUES,&tbz);CHKERRQ(ierr);
675     ierr = PetscObjectSetName((PetscObject)tbz,"corners_to_be_zeroed_with_interior");CHKERRQ(ierr);
676     ierr = ISView(tbz,NULL);CHKERRQ(ierr);
677     ierr = ISDestroy(&tbz);CHKERRQ(ierr);
678   }
679   ierr = MatZeroRows(lGt,cum,vmarks,0.,NULL,NULL);CHKERRQ(ierr);
680   ierr = PetscFree(vmarks);CHKERRQ(ierr);
681   ierr = PetscSFDestroy(&sfv);CHKERRQ(ierr);
682   ierr = PetscFree2(sfvleaves,sfvroots);CHKERRQ(ierr);
683 
684   /* Recompute G */
685   ierr = MatDestroy(&lG);CHKERRQ(ierr);
686   ierr = MatTranspose(lGt,MAT_INITIAL_MATRIX,&lG);CHKERRQ(ierr);
687   if (print) {
688     ierr = PetscObjectSetName((PetscObject)lG,"used_lG");CHKERRQ(ierr);
689     ierr = MatView(lG,NULL);CHKERRQ(ierr);
690     ierr = PetscObjectSetName((PetscObject)lGt,"used_lGt");CHKERRQ(ierr);
691     ierr = MatView(lGt,NULL);CHKERRQ(ierr);
692   }
693 
694   /* Get primal dofs (if any) */
695   cum = 0;
696   for (i=0;i<ne;i++) {
697     if (PetscUnlikely(PetscBTLookup(bte,i))) marks[cum++] = i;
698   }
699   if (fl2g) {
700     ierr = ISLocalToGlobalMappingApply(fl2g,cum,marks,marks);CHKERRQ(ierr);
701   }
702   ierr = ISCreateGeneral(comm,cum,marks,PETSC_COPY_VALUES,&primals);CHKERRQ(ierr);
703   if (print) {
704     ierr = PetscObjectSetName((PetscObject)primals,"prescribed_primal_dofs");CHKERRQ(ierr);
705     ierr = ISView(primals,NULL);CHKERRQ(ierr);
706   }
707   ierr = PetscBTDestroy(&bte);CHKERRQ(ierr);
708   /* TODO: what if the user passed in some of them ?  */
709   ierr = PCBDDCSetPrimalVerticesLocalIS(pc,primals);CHKERRQ(ierr);
710   ierr = ISDestroy(&primals);CHKERRQ(ierr);
711 
712   /* Compute edge connectivity */
713   ierr = PetscObjectSetOptionsPrefix((PetscObject)lG,"econn_");CHKERRQ(ierr);
714   ierr = MatMatMultSymbolic(lG,lGt,PETSC_DEFAULT,&conn);CHKERRQ(ierr);
715   ierr = MatGetRowIJ(conn,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
716   if (fl2g) {
717     PetscBT   btf;
718     PetscInt  *iia,*jja,*iiu,*jju;
719     PetscBool rest = PETSC_FALSE,free = PETSC_FALSE;
720 
721     /* create CSR for all local dofs */
722     ierr = PetscMalloc1(n+1,&iia);CHKERRQ(ierr);
723     if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
724       if (pcbddc->mat_graph->nvtxs_csr != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid size of CSR graph %d. Should be %d\n",pcbddc->mat_graph->nvtxs_csr,n);
725       iiu = pcbddc->mat_graph->xadj;
726       jju = pcbddc->mat_graph->adjncy;
727     } else if (pcbddc->use_local_adj) {
728       rest = PETSC_TRUE;
729       ierr = MatGetRowIJ(matis->A,0,PETSC_TRUE,PETSC_FALSE,&i,(const PetscInt**)&iiu,(const PetscInt**)&jju,&done);CHKERRQ(ierr);
730     } else {
731       free   = PETSC_TRUE;
732       ierr   = PetscMalloc2(n+1,&iiu,n,&jju);CHKERRQ(ierr);
733       iiu[0] = 0;
734       for (i=0;i<n;i++) {
735         iiu[i+1] = i+1;
736         jju[i]   = -1;
737       }
738     }
739 
740     /* import sizes of CSR */
741     iia[0] = 0;
742     for (i=0;i<n;i++) iia[i+1] = iiu[i+1]-iiu[i];
743 
744     /* overwrite entries corresponding to the Nedelec field */
745     ierr = PetscBTCreate(n,&btf);CHKERRQ(ierr);
746     ierr = ISGetIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
747     for (i=0;i<ne;i++) {
748       ierr = PetscBTSet(btf,idxs[i]);CHKERRQ(ierr);
749       iia[idxs[i]+1] = ii[i+1]-ii[i];
750     }
751 
752     /* iia in CSR */
753     for (i=0;i<n;i++) iia[i+1] += iia[i];
754 
755     /* jja in CSR */
756     ierr = PetscMalloc1(iia[n],&jja);CHKERRQ(ierr);
757     for (i=0;i<n;i++)
758       if (!PetscBTLookup(btf,i))
759         for (j=0;j<iiu[i+1]-iiu[i];j++)
760           jja[iia[i]+j] = jju[iiu[i]+j];
761 
762     /* map edge dofs connectivity */
763     if (jj) {
764       ierr = ISLocalToGlobalMappingApply(fl2g,ii[ne],jj,(PetscInt *)jj);CHKERRQ(ierr);
765       for (i=0;i<ne;i++) {
766         PetscInt e = idxs[i];
767         for (j=0;j<ii[i+1]-ii[i];j++) jja[iia[e]+j] = jj[ii[i]+j];
768       }
769     }
770     ierr = ISRestoreIndices(nedfieldlocal,&idxs);CHKERRQ(ierr);
771     ierr = PCBDDCSetLocalAdjacencyGraph(pc,n,iia,jja,PETSC_OWN_POINTER);CHKERRQ(ierr);
772     if (rest) {
773       ierr = MatRestoreRowIJ(matis->A,0,PETSC_TRUE,PETSC_FALSE,&i,(const PetscInt**)&iiu,(const PetscInt**)&jju,&done);CHKERRQ(ierr);
774     }
775     if (free) {
776       ierr = PetscFree2(iiu,jju);CHKERRQ(ierr);
777     }
778     ierr = PetscBTDestroy(&btf);CHKERRQ(ierr);
779   } else {
780     ierr = PCBDDCSetLocalAdjacencyGraph(pc,n,ii,jj,PETSC_USE_POINTER);CHKERRQ(ierr);
781   }
782 
783   /* Analyze interface for edge dofs */
784   ierr = PCBDDCAnalyzeInterface(pc);CHKERRQ(ierr);
785   pcbddc->mat_graph->twodim = PETSC_FALSE;
786 
787   /* Get coarse edges in the edge space */
788   ierr = PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,NULL,NULL,&nee,&alleedges,&allprimals);CHKERRQ(ierr);
789   ierr = MatRestoreRowIJ(conn,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
790 
791   if (fl2g) {
792     ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_DROP,allprimals,&primals);CHKERRQ(ierr);
793     ierr = PetscMalloc1(nee,&eedges);CHKERRQ(ierr);
794     for (i=0;i<nee;i++) {
795       ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_DROP,alleedges[i],&eedges[i]);CHKERRQ(ierr);
796     }
797   } else {
798     eedges  = alleedges;
799     primals = allprimals;
800   }
801 
802   /* Mark fine edge dofs with their coarse edge id */
803   ierr = PetscMemzero(marks,ne*sizeof(PetscInt));CHKERRQ(ierr);
804   ierr = ISGetLocalSize(primals,&cum);CHKERRQ(ierr);
805   ierr = ISGetIndices(primals,&idxs);CHKERRQ(ierr);
806   for (i=0;i<cum;i++) marks[idxs[i]] = nee+1;
807   ierr = ISRestoreIndices(primals,&idxs);CHKERRQ(ierr);
808   if (print) {
809     ierr = PetscObjectSetName((PetscObject)primals,"obtained_primal_dofs");CHKERRQ(ierr);
810     ierr = ISView(primals,NULL);CHKERRQ(ierr);
811   }
812 
813   maxsize = 0;
814   for (i=0;i<nee;i++) {
815     PetscInt size,mark = i+1;
816 
817     ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
818     ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
819     for (j=0;j<size;j++) marks[idxs[j]] = mark;
820     ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
821     maxsize = PetscMax(maxsize,size);
822   }
823 
824   /* Find coarse edge endpoints */
825   ierr = MatGetRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
826   ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
827   for (i=0;i<nee;i++) {
828     PetscInt mark = i+1,size;
829 
830     ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
831     if (!size && nedfieldlocal) continue;
832     if (!size) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected zero sized edge %d",i);
833     ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
834     if (print) {
835       PetscPrintf(PETSC_COMM_SELF,"ENDPOINTS ANALYSIS EDGE %d\n",i);
836       ISView(eedges[i],NULL);
837     }
838     for (j=0;j<size;j++) {
839       PetscInt k, ee = idxs[j];
840       if (print) PetscPrintf(PETSC_COMM_SELF,"  idx %d\n",ee);
841       for (k=ii[ee];k<ii[ee+1];k++) {
842         if (print) PetscPrintf(PETSC_COMM_SELF,"    inspect %d\n",jj[k]);
843         if (PetscBTLookup(btv,jj[k])) {
844           if (print) PetscPrintf(PETSC_COMM_SELF,"      corner found (already set) %d\n",jj[k]);
845         } else if (PetscBTLookup(btvcand,jj[k])) { /* is it ok? */
846           PetscInt  k2;
847           PetscBool corner = PETSC_FALSE;
848           for (k2 = iit[jj[k]];k2 < iit[jj[k]+1];k2++) {
849             if (print) PetscPrintf(PETSC_COMM_SELF,"        INSPECTING %d: mark %d (ref mark %d), boundary %d\n",jjt[k2],marks[jjt[k2]],mark,!!PetscBTLookup(btb,jjt[k2]));
850             /* it's a corner if either is connected with an edge dof belonging to a different cc or
851                if the edge dof lie on the natural part of the boundary */
852             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb,jjt[k2]))) {
853               corner = PETSC_TRUE;
854               break;
855             }
856           }
857           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
858             if (print) PetscPrintf(PETSC_COMM_SELF,"        corner found %d\n",jj[k]);
859             ierr = PetscBTSet(btv,jj[k]);CHKERRQ(ierr);
860           } else {
861             if (print) PetscPrintf(PETSC_COMM_SELF,"        no corners found\n");
862           }
863         }
864       }
865     }
866     ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
867   }
868   ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
869   ierr = MatRestoreRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
870   ierr = PetscBTDestroy(&btb);CHKERRQ(ierr);
871 
872   /* Reset marked primal dofs */
873   ierr = ISGetLocalSize(primals,&cum);CHKERRQ(ierr);
874   ierr = ISGetIndices(primals,&idxs);CHKERRQ(ierr);
875   for (i=0;i<cum;i++) marks[idxs[i]] = 0;
876   ierr = ISRestoreIndices(primals,&idxs);CHKERRQ(ierr);
877 
878   /* Now use the initial lG */
879   ierr = MatDestroy(&lG);CHKERRQ(ierr);
880   ierr = MatDestroy(&lGt);CHKERRQ(ierr);
881   lG   = lGinit;
882   ierr = MatTranspose(lG,MAT_INITIAL_MATRIX,&lGt);CHKERRQ(ierr);
883 
884   /* Compute extended cols indices */
885   ierr = PetscBTCreate(nv,&btvc);CHKERRQ(ierr);
886   ierr = PetscBTCreate(nee,&bter);CHKERRQ(ierr);
887   ierr = MatGetRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
888   ierr = MatSeqAIJGetMaxRowNonzeros(lG,&i);CHKERRQ(ierr);
889   i   *= maxsize;
890   ierr = PetscCalloc1(nee,&extcols);CHKERRQ(ierr);
891   ierr = PetscMalloc2(i,&extrow,i,&gidxs);CHKERRQ(ierr);
892   eerr = PETSC_FALSE;
893   for (i=0;i<nee;i++) {
894     PetscInt size,found = 0;
895 
896     cum  = 0;
897     ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
898     if (!size && nedfieldlocal) continue;
899     if (!size) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected zero sized edge %d",i);
900     ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
901     ierr = PetscBTMemzero(nv,btvc);CHKERRQ(ierr);
902     for (j=0;j<size;j++) {
903       PetscInt k,ee = idxs[j];
904       for (k=ii[ee];k<ii[ee+1];k++) {
905         PetscInt vv = jj[k];
906         if (!PetscBTLookup(btv,vv)) extrow[cum++] = vv;
907         else if (!PetscBTLookupSet(btvc,vv)) found++;
908       }
909     }
910     ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
911     ierr = PetscSortRemoveDupsInt(&cum,extrow);CHKERRQ(ierr);
912     ierr = ISLocalToGlobalMappingApply(vl2g,cum,extrow,gidxs);CHKERRQ(ierr);
913     ierr = PetscSortIntWithArray(cum,gidxs,extrow);CHKERRQ(ierr);
914     ierr = ISCreateGeneral(PETSC_COMM_SELF,cum,extrow,PETSC_COPY_VALUES,&extcols[i]);CHKERRQ(ierr);
915     /* it may happen that endpoints are not defined at this point
916        if it is the case, mark this edge for a second pass */
917     if (cum != size -1 || found != 2) {
918       ierr = PetscBTSet(bter,i);CHKERRQ(ierr);
919       if (print) {
920         ierr = PetscObjectSetName((PetscObject)eedges[i],"error_edge");CHKERRQ(ierr);
921         ierr = ISView(eedges[i],NULL);CHKERRQ(ierr);
922         ierr = PetscObjectSetName((PetscObject)extcols[i],"error_extcol");CHKERRQ(ierr);
923         ierr = ISView(extcols[i],NULL);CHKERRQ(ierr);
924       }
925       eerr = PETSC_TRUE;
926     }
927   }
928   /* if (eerr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
929   ierr = MPIU_Allreduce(&eerr,&done,1,MPIU_BOOL,MPI_LOR,comm);CHKERRQ(ierr);
930   if (done) {
931     PetscInt *newprimals;
932 
933     ierr = PetscMalloc1(ne,&newprimals);CHKERRQ(ierr);
934     ierr = ISGetLocalSize(primals,&cum);CHKERRQ(ierr);
935     ierr = ISGetIndices(primals,&idxs);CHKERRQ(ierr);
936     ierr = PetscMemcpy(newprimals,idxs,cum*sizeof(PetscInt));CHKERRQ(ierr);
937     ierr = ISRestoreIndices(primals,&idxs);CHKERRQ(ierr);
938     ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
939     if (print) PetscPrintf(PETSC_COMM_SELF,"DOING SECOND PASS (eerr %d)\n",eerr);
940     for (i=0;i<nee;i++) {
941       PetscBool has_candidates = PETSC_FALSE;
942       if (PetscBTLookup(bter,i)) {
943         PetscInt size,mark = i+1;
944 
945         ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
946         ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
947         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
948         for (j=0;j<size;j++) {
949           PetscInt k,ee = idxs[j];
950           if (print) PetscPrintf(PETSC_COMM_SELF,"Inspecting edge dof %d [%d %d)\n",ee,ii[ee],ii[ee+1]);
951           for (k=ii[ee];k<ii[ee+1];k++) {
952             /* set all candidates located on the edge as corners */
953             if (PetscBTLookup(btvcand,jj[k])) {
954               PetscInt k2,vv = jj[k];
955               has_candidates = PETSC_TRUE;
956               if (print) PetscPrintf(PETSC_COMM_SELF,"  Candidate set to vertex %d\n",vv);
957               ierr = PetscBTSet(btv,vv);CHKERRQ(ierr);
958               /* set all edge dofs connected to candidate as primals */
959               for (k2=iit[vv];k2<iit[vv+1];k2++) {
960                 if (marks[jjt[k2]] == mark) {
961                   PetscInt k3,ee2 = jjt[k2];
962                   if (print) PetscPrintf(PETSC_COMM_SELF,"    Connected edge dof set to primal %d\n",ee2);
963                   newprimals[cum++] = ee2;
964                   /* finally set the new corners */
965                   for (k3=ii[ee2];k3<ii[ee2+1];k3++) {
966                     if (print) PetscPrintf(PETSC_COMM_SELF,"      Connected nodal dof set to vertex %d\n",jj[k3]);
967                     ierr = PetscBTSet(btv,jj[k3]);CHKERRQ(ierr);
968                   }
969                 }
970               }
971             } else {
972               if (print) PetscPrintf(PETSC_COMM_SELF,"  Not a candidate vertex %d\n",jj[k]);
973             }
974           }
975         }
976         if (!has_candidates) { /* circular edge */
977           PetscInt k, ee = idxs[0],*tmarks;
978 
979           ierr = PetscCalloc1(ne,&tmarks);CHKERRQ(ierr);
980           if (print) PetscPrintf(PETSC_COMM_SELF,"  Circular edge %d\n",i);
981           for (k=ii[ee];k<ii[ee+1];k++) {
982             PetscInt k2;
983             if (print) PetscPrintf(PETSC_COMM_SELF,"    Set to corner %d\n",jj[k]);
984             ierr = PetscBTSet(btv,jj[k]);CHKERRQ(ierr);
985             for (k2=iit[jj[k]];k2<iit[jj[k]+1];k2++) tmarks[jjt[k2]]++;
986           }
987           for (j=0;j<size;j++) {
988             if (tmarks[idxs[j]] > 1) {
989               if (print) PetscPrintf(PETSC_COMM_SELF,"  Edge dof set to primal %d\n",idxs[j]);
990               newprimals[cum++] = idxs[j];
991             }
992           }
993           ierr = PetscFree(tmarks);CHKERRQ(ierr);
994         }
995         ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
996       }
997       ierr = ISDestroy(&extcols[i]);CHKERRQ(ierr);
998     }
999     ierr = PetscFree(extcols);CHKERRQ(ierr);
1000     ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&iit,&jjt,&done);CHKERRQ(ierr);
1001     ierr = PetscSortRemoveDupsInt(&cum,newprimals);CHKERRQ(ierr);
1002     if (fl2g) {
1003       ierr = ISLocalToGlobalMappingApply(fl2g,cum,newprimals,newprimals);CHKERRQ(ierr);
1004       ierr = ISDestroy(&primals);CHKERRQ(ierr);
1005       for (i=0;i<nee;i++) {
1006         ierr = ISDestroy(&eedges[i]);CHKERRQ(ierr);
1007       }
1008       ierr = PetscFree(eedges);CHKERRQ(ierr);
1009     }
1010     ierr = PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph,NULL,NULL,&nee,&alleedges,&allprimals);CHKERRQ(ierr);
1011     ierr = ISCreateGeneral(comm,cum,newprimals,PETSC_COPY_VALUES,&primals);CHKERRQ(ierr);
1012     ierr = PetscFree(newprimals);CHKERRQ(ierr);
1013     ierr = PCBDDCSetPrimalVerticesLocalIS(pc,primals);CHKERRQ(ierr);
1014     ierr = ISDestroy(&primals);CHKERRQ(ierr);
1015     ierr = PCBDDCAnalyzeInterface(pc);CHKERRQ(ierr);
1016     pcbddc->mat_graph->twodim = PETSC_FALSE;
1017     ierr = PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,NULL,NULL,&nee,&alleedges,&allprimals);CHKERRQ(ierr);
1018     if (fl2g) {
1019       ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_DROP,allprimals,&primals);CHKERRQ(ierr);
1020       ierr = PetscMalloc1(nee,&eedges);CHKERRQ(ierr);
1021       for (i=0;i<nee;i++) {
1022         ierr = ISGlobalToLocalMappingApplyIS(fl2g,IS_GTOLM_DROP,alleedges[i],&eedges[i]);CHKERRQ(ierr);
1023       }
1024     } else {
1025       eedges  = alleedges;
1026       primals = allprimals;
1027     }
1028     ierr = PetscCalloc1(nee,&extcols);CHKERRQ(ierr);
1029 
1030     /* Mark again */
1031     ierr = PetscMemzero(marks,ne*sizeof(PetscInt));CHKERRQ(ierr);
1032     for (i=0;i<nee;i++) {
1033       PetscInt size,mark = i+1;
1034 
1035       ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
1036       ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
1037       for (j=0;j<size;j++) marks[idxs[j]] = mark;
1038       ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
1039     }
1040     if (print) {
1041       ierr = PetscObjectSetName((PetscObject)primals,"obtained_primal_dofs_secondpass");CHKERRQ(ierr);
1042       ierr = ISView(primals,NULL);CHKERRQ(ierr);
1043     }
1044 
1045     /* Recompute extended cols */
1046     eerr = PETSC_FALSE;
1047     for (i=0;i<nee;i++) {
1048       PetscInt size;
1049 
1050       cum  = 0;
1051       ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
1052       if (!size && nedfieldlocal) continue;
1053       if (!size) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected zero sized edge %d",i);
1054       ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
1055       for (j=0;j<size;j++) {
1056         PetscInt k,ee = idxs[j];
1057         for (k=ii[ee];k<ii[ee+1];k++) if (!PetscBTLookup(btv,jj[k])) extrow[cum++] = jj[k];
1058       }
1059       ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
1060       ierr = PetscSortRemoveDupsInt(&cum,extrow);CHKERRQ(ierr);
1061       ierr = ISLocalToGlobalMappingApply(vl2g,cum,extrow,gidxs);CHKERRQ(ierr);
1062       ierr = PetscSortIntWithArray(cum,gidxs,extrow);CHKERRQ(ierr);
1063       ierr = ISCreateGeneral(PETSC_COMM_SELF,cum,extrow,PETSC_COPY_VALUES,&extcols[i]);CHKERRQ(ierr);
1064       if (cum != size -1) {
1065         if (print) {
1066           ierr = PetscObjectSetName((PetscObject)eedges[i],"error_edge_secondpass");CHKERRQ(ierr);
1067           ierr = ISView(eedges[i],NULL);CHKERRQ(ierr);
1068           ierr = PetscObjectSetName((PetscObject)extcols[i],"error_extcol_secondpass");CHKERRQ(ierr);
1069           ierr = ISView(extcols[i],NULL);CHKERRQ(ierr);
1070         }
1071         eerr = PETSC_TRUE;
1072       }
1073     }
1074   }
1075   ierr = MatRestoreRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1076   ierr = PetscFree2(extrow,gidxs);CHKERRQ(ierr);
1077   ierr = PetscBTDestroy(&bter);CHKERRQ(ierr);
1078   if (print) { ierr = PCBDDCGraphASCIIView(pcbddc->mat_graph,5,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); }
1079   /* an error should not occur at this point */
1080   if (eerr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1081 
1082   /* Check the number of endpoints */
1083   ierr = MatGetRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1084   ierr = PetscMalloc1(2*nee,&corners);CHKERRQ(ierr);
1085   ierr = PetscMalloc1(nee,&cedges);CHKERRQ(ierr);
1086   for (i=0;i<nee;i++) {
1087     PetscInt size, found = 0, gc[2];
1088 
1089     /* init with defaults */
1090     cedges[i] = corners[i*2] = corners[i*2+1] = -1;
1091     ierr = ISGetLocalSize(eedges[i],&size);CHKERRQ(ierr);
1092     if (!size && nedfieldlocal) continue;
1093     if (!size) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected zero sized edge %d",i);
1094     ierr = ISGetIndices(eedges[i],&idxs);CHKERRQ(ierr);
1095     ierr = PetscBTMemzero(nv,btvc);CHKERRQ(ierr);
1096     for (j=0;j<size;j++) {
1097       PetscInt k,ee = idxs[j];
1098       for (k=ii[ee];k<ii[ee+1];k++) {
1099         PetscInt vv = jj[k];
1100         if (PetscBTLookup(btv,vv) && !PetscBTLookupSet(btvc,vv)) {
1101           if (found == 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Found more then two corners for edge %d\n",i);
1102           corners[i*2+found++] = vv;
1103         }
1104       }
1105     }
1106     if (found != 2) {
1107       PetscInt e;
1108       if (fl2g) {
1109         ierr = ISLocalToGlobalMappingApply(fl2g,1,idxs,&e);CHKERRQ(ierr);
1110       } else {
1111         e = idxs[0];
1112       }
1113       SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Found %d corners for edge %d (astart %d, estart %d)\n",found,i,e,idxs[0]);
1114     }
1115 
1116     /* get primal dof index on this coarse edge */
1117     ierr = ISLocalToGlobalMappingApply(vl2g,2,corners+2*i,gc);CHKERRQ(ierr);
1118     if (gc[0] > gc[1]) {
1119       PetscInt swap  = corners[2*i];
1120       corners[2*i]   = corners[2*i+1];
1121       corners[2*i+1] = swap;
1122     }
1123     cedges[i] = idxs[size-1];
1124     ierr = ISRestoreIndices(eedges[i],&idxs);CHKERRQ(ierr);
1125     if (print) PetscPrintf(PETSC_COMM_SELF,"EDGE %d: ce %d, corners (%d,%d)\n",i,cedges[i],corners[2*i],corners[2*i+1]);
1126   }
1127   ierr = MatRestoreRowIJ(lG,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1128   ierr = PetscBTDestroy(&btvc);CHKERRQ(ierr);
1129 
1130 #if defined(PETSC_USE_DEBUG)
1131   /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1132      not interfere with neighbouring coarse edges */
1133   ierr = PetscMalloc1(nee+1,&emarks);CHKERRQ(ierr);
1134   ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1135   for (i=0;i<nv;i++) {
1136     PetscInt emax = 0,eemax = 0;
1137 
1138     if (ii[i+1]==ii[i] || PetscBTLookup(btv,i)) continue;
1139     ierr = PetscMemzero(emarks,(nee+1)*sizeof(PetscInt));CHKERRQ(ierr);
1140     for (j=ii[i];j<ii[i+1];j++) emarks[marks[jj[j]]]++;
1141     for (j=1;j<nee+1;j++) {
1142       if (emax < emarks[j]) {
1143         emax = emarks[j];
1144         eemax = j;
1145       }
1146     }
1147     /* not relevant for edges */
1148     if (!eemax) continue;
1149 
1150     for (j=ii[i];j<ii[i+1];j++) {
1151       if (marks[jj[j]] && marks[jj[j]] != eemax) {
1152         SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Found 2 coarse edges (id %d and %d) connected through the %d nodal dof at edge dof %d\n",marks[jj[j]]-1,eemax,i,jj[j]);
1153       }
1154     }
1155   }
1156   ierr = PetscFree(emarks);CHKERRQ(ierr);
1157   ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1158 #endif
1159 
1160   /* Compute extended rows indices for edge blocks of the change of basis */
1161   ierr = MatGetRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1162   ierr = MatSeqAIJGetMaxRowNonzeros(lGt,&extmem);CHKERRQ(ierr);
1163   extmem *= maxsize;
1164   ierr = PetscMalloc1(extmem*nee,&extrow);CHKERRQ(ierr);
1165   ierr = PetscMalloc1(nee,&extrows);CHKERRQ(ierr);
1166   ierr = PetscCalloc1(nee,&extrowcum);CHKERRQ(ierr);
1167   for (i=0;i<nv;i++) {
1168     PetscInt mark = 0,size,start;
1169 
1170     if (ii[i+1]==ii[i] || PetscBTLookup(btv,i)) continue;
1171     for (j=ii[i];j<ii[i+1];j++)
1172       if (marks[jj[j]] && !mark)
1173         mark = marks[jj[j]];
1174 
1175     /* not relevant */
1176     if (!mark) continue;
1177 
1178     /* import extended row */
1179     mark--;
1180     start = mark*extmem+extrowcum[mark];
1181     size = ii[i+1]-ii[i];
1182     if (extrowcum[mark] + size > extmem) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not enough memory allocated %d > %d",extrowcum[mark] + size,extmem);
1183     ierr = PetscMemcpy(extrow+start,jj+ii[i],size*sizeof(PetscInt));CHKERRQ(ierr);
1184     extrowcum[mark] += size;
1185   }
1186   ierr = MatRestoreRowIJ(lGt,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&done);CHKERRQ(ierr);
1187   ierr = MatDestroy(&lGt);CHKERRQ(ierr);
1188   ierr = PetscFree(marks);CHKERRQ(ierr);
1189 
1190   /* Compress extrows */
1191   cum  = 0;
1192   for (i=0;i<nee;i++) {
1193     PetscInt size = extrowcum[i],*start = extrow + i*extmem;
1194     ierr = PetscSortRemoveDupsInt(&size,start);CHKERRQ(ierr);
1195     ierr = ISCreateGeneral(PETSC_COMM_SELF,size,start,PETSC_USE_POINTER,&extrows[i]);CHKERRQ(ierr);
1196     cum  = PetscMax(cum,size);
1197   }
1198   ierr = PetscFree(extrowcum);CHKERRQ(ierr);
1199   ierr = PetscBTDestroy(&btv);CHKERRQ(ierr);
1200   ierr = PetscBTDestroy(&btvcand);CHKERRQ(ierr);
1201 
1202   /* Workspace for lapack inner calls and VecSetValues */
1203   ierr = PetscMalloc2((5+cum+maxsize)*maxsize,&work,maxsize,&rwork);CHKERRQ(ierr);
1204 
1205   /* Create change of basis matrix (preallocation can be improved) */
1206   ierr = MatCreate(comm,&T);CHKERRQ(ierr);
1207   ierr = MatSetSizes(T,pc->pmat->rmap->n,pc->pmat->rmap->n,
1208                        pc->pmat->rmap->N,pc->pmat->rmap->N);CHKERRQ(ierr);
1209   ierr = MatSetType(T,MATAIJ);CHKERRQ(ierr);
1210   ierr = MatSeqAIJSetPreallocation(T,10,NULL);CHKERRQ(ierr);
1211   ierr = MatMPIAIJSetPreallocation(T,10,NULL,10,NULL);CHKERRQ(ierr);
1212   ierr = MatSetLocalToGlobalMapping(T,al2g,al2g);CHKERRQ(ierr);
1213   ierr = MatSetOption(T,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
1214   ierr = MatSetOption(T,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
1215   ierr = ISLocalToGlobalMappingDestroy(&al2g);CHKERRQ(ierr);
1216 
1217   /* Defaults to identity */
1218   ierr = MatCreateVecs(pc->pmat,&tvec,NULL);CHKERRQ(ierr);
1219   ierr = VecSet(tvec,1.0);CHKERRQ(ierr);
1220   ierr = MatDiagonalSet(T,tvec,INSERT_VALUES);CHKERRQ(ierr);
1221   ierr = VecDestroy(&tvec);CHKERRQ(ierr);
1222 
1223   /* Create discrete gradient for the coarser level if needed */
1224   ierr = MatDestroy(&pcbddc->nedcG);CHKERRQ(ierr);
1225   ierr = ISDestroy(&pcbddc->nedclocal);CHKERRQ(ierr);
1226   if (pcbddc->current_level < pcbddc->max_levels) {
1227     ISLocalToGlobalMapping cel2g,cvl2g;
1228     IS                     wis,gwis;
1229     PetscInt               cnv,cne;
1230 
1231     ierr = ISCreateGeneral(comm,nee,cedges,PETSC_COPY_VALUES,&wis);CHKERRQ(ierr);
1232     if (fl2g) {
1233       ierr = ISLocalToGlobalMappingApplyIS(fl2g,wis,&pcbddc->nedclocal);CHKERRQ(ierr);
1234     } else {
1235       ierr = PetscObjectReference((PetscObject)wis);CHKERRQ(ierr);
1236       pcbddc->nedclocal = wis;
1237     }
1238     ierr = ISLocalToGlobalMappingApplyIS(el2g,wis,&gwis);CHKERRQ(ierr);
1239     ierr = ISDestroy(&wis);CHKERRQ(ierr);
1240     ierr = ISRenumber(gwis,NULL,&cne,&wis);CHKERRQ(ierr);
1241     ierr = ISLocalToGlobalMappingCreateIS(wis,&cel2g);CHKERRQ(ierr);
1242     ierr = ISDestroy(&wis);CHKERRQ(ierr);
1243     ierr = ISDestroy(&gwis);CHKERRQ(ierr);
1244 
1245     ierr = ISCreateGeneral(comm,2*nee,corners,PETSC_USE_POINTER,&wis);CHKERRQ(ierr);
1246     ierr = ISLocalToGlobalMappingApplyIS(vl2g,wis,&gwis);CHKERRQ(ierr);
1247     ierr = ISDestroy(&wis);CHKERRQ(ierr);
1248     ierr = ISRenumber(gwis,NULL,&cnv,&wis);CHKERRQ(ierr);
1249     ierr = ISLocalToGlobalMappingCreateIS(wis,&cvl2g);CHKERRQ(ierr);
1250     ierr = ISDestroy(&wis);CHKERRQ(ierr);
1251     ierr = ISDestroy(&gwis);CHKERRQ(ierr);
1252 
1253     ierr = MatCreate(comm,&pcbddc->nedcG);CHKERRQ(ierr);
1254     ierr = MatSetSizes(pcbddc->nedcG,PETSC_DECIDE,PETSC_DECIDE,cne,cnv);CHKERRQ(ierr);
1255     ierr = MatSetType(pcbddc->nedcG,MATAIJ);CHKERRQ(ierr);
1256     ierr = MatSeqAIJSetPreallocation(pcbddc->nedcG,2,NULL);CHKERRQ(ierr);
1257     ierr = MatMPIAIJSetPreallocation(pcbddc->nedcG,2,NULL,2,NULL);CHKERRQ(ierr);
1258     ierr = MatSetLocalToGlobalMapping(pcbddc->nedcG,cel2g,cvl2g);CHKERRQ(ierr);
1259     ierr = ISLocalToGlobalMappingDestroy(&cel2g);CHKERRQ(ierr);
1260     ierr = ISLocalToGlobalMappingDestroy(&cvl2g);CHKERRQ(ierr);
1261   }
1262   ierr = ISLocalToGlobalMappingDestroy(&vl2g);CHKERRQ(ierr);
1263 
1264 #if defined(PRINT_GDET)
1265   inc = 0;
1266   lev = pcbddc->current_level;
1267 #endif
1268 
1269   /* Insert values in the change of basis matrix */
1270   for (i=0;i<nee;i++) {
1271     Mat         Gins = NULL, GKins = NULL;
1272     IS          cornersis = NULL;
1273     PetscScalar cvals[2];
1274 
1275     if (pcbddc->nedcG) {
1276       ierr = ISCreateGeneral(PETSC_COMM_SELF,2,corners+2*i,PETSC_USE_POINTER,&cornersis);CHKERRQ(ierr);
1277     }
1278     ierr = PCBDDCComputeNedelecChangeEdge(lG,eedges[i],extrows[i],extcols[i],cornersis,&Gins,&GKins,cvals,work,rwork);CHKERRQ(ierr);
1279     if (Gins && GKins) {
1280       PetscScalar    *data;
1281       const PetscInt *rows,*cols;
1282       PetscInt       nrh,nch,nrc,ncc;
1283 
1284       ierr = ISGetIndices(eedges[i],&cols);CHKERRQ(ierr);
1285       /* H1 */
1286       ierr = ISGetIndices(extrows[i],&rows);CHKERRQ(ierr);
1287       ierr = MatGetSize(Gins,&nrh,&nch);CHKERRQ(ierr);
1288       ierr = MatDenseGetArray(Gins,&data);CHKERRQ(ierr);
1289       ierr = MatSetValuesLocal(T,nrh,rows,nch,cols,data,INSERT_VALUES);CHKERRQ(ierr);
1290       ierr = MatDenseRestoreArray(Gins,&data);CHKERRQ(ierr);
1291       ierr = ISRestoreIndices(extrows[i],&rows);CHKERRQ(ierr);
1292       /* complement */
1293       ierr = MatGetSize(GKins,&nrc,&ncc);CHKERRQ(ierr);
1294       if (!ncc) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Constant function has not been generated for coarse edge %d",i);
1295       if (ncc + nch != nrc) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_PLIB,"The sum of the number of columns of GKins %d and Gins %d does not match %d for coarse edge %d",ncc,nch,nrc,i);
1296       if (ncc != 1 && pcbddc->nedcG) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot generate the coarse discrete gradient for coarse edge %d with ncc %d",i,ncc);
1297       ierr = MatDenseGetArray(GKins,&data);CHKERRQ(ierr);
1298       ierr = MatSetValuesLocal(T,nrc,cols,ncc,cols+nch,data,INSERT_VALUES);CHKERRQ(ierr);
1299       ierr = MatDenseRestoreArray(GKins,&data);CHKERRQ(ierr);
1300 
1301       /* coarse discrete gradient */
1302       if (pcbddc->nedcG) {
1303         PetscInt cols[2];
1304 
1305         cols[0] = 2*i;
1306         cols[1] = 2*i+1;
1307         ierr = MatSetValuesLocal(pcbddc->nedcG,1,&i,2,cols,cvals,INSERT_VALUES);CHKERRQ(ierr);
1308       }
1309       ierr = ISRestoreIndices(eedges[i],&cols);CHKERRQ(ierr);
1310     }
1311     ierr = ISDestroy(&extrows[i]);CHKERRQ(ierr);
1312     ierr = ISDestroy(&extcols[i]);CHKERRQ(ierr);
1313     ierr = ISDestroy(&cornersis);CHKERRQ(ierr);
1314     ierr = MatDestroy(&Gins);CHKERRQ(ierr);
1315     ierr = MatDestroy(&GKins);CHKERRQ(ierr);
1316   }
1317   ierr = ISLocalToGlobalMappingDestroy(&el2g);CHKERRQ(ierr);
1318 
1319   /* Start assembling */
1320   ierr = MatAssemblyBegin(T,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1321   if (pcbddc->nedcG) {
1322     ierr = MatAssemblyBegin(pcbddc->nedcG,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1323   }
1324 
1325   /* Free */
1326   if (fl2g) {
1327     ierr = ISDestroy(&primals);CHKERRQ(ierr);
1328     for (i=0;i<nee;i++) {
1329       ierr = ISDestroy(&eedges[i]);CHKERRQ(ierr);
1330     }
1331     ierr = PetscFree(eedges);CHKERRQ(ierr);
1332   }
1333 
1334   /* hack mat_graph with primal dofs on the coarse edges */
1335   {
1336     PCBDDCGraph graph   = pcbddc->mat_graph;
1337     PetscInt    *oqueue = graph->queue;
1338     PetscInt    *ocptr  = graph->cptr;
1339     PetscInt    ncc,*idxs;
1340 
1341     /* find first primal edge */
1342     if (pcbddc->nedclocal) {
1343       ierr = ISGetIndices(pcbddc->nedclocal,(const PetscInt**)&idxs);CHKERRQ(ierr);
1344     } else {
1345       if (fl2g) {
1346         ierr = ISLocalToGlobalMappingApply(fl2g,nee,cedges,cedges);CHKERRQ(ierr);
1347       }
1348       idxs = cedges;
1349     }
1350     cum = 0;
1351     while (cum < nee && cedges[cum] < 0) cum++;
1352 
1353     /* adapt connected components */
1354     ierr = PetscMalloc2(graph->nvtxs+1,&graph->cptr,ocptr[graph->ncc],&graph->queue);CHKERRQ(ierr);
1355     graph->cptr[0] = 0;
1356     for (i=0,ncc=0;i<graph->ncc;i++) {
1357       PetscInt lc = ocptr[i+1]-ocptr[i];
1358       if (cum != nee && oqueue[ocptr[i+1]-1] == cedges[cum]) { /* this cc has a primal dof */
1359         graph->cptr[ncc+1] = graph->cptr[ncc]+1;
1360         graph->queue[graph->cptr[ncc]] = cedges[cum];
1361         ncc++;
1362         lc--;
1363         cum++;
1364         while (cum < nee && cedges[cum] < 0) cum++;
1365       }
1366       graph->cptr[ncc+1] = graph->cptr[ncc] + lc;
1367       for (j=0;j<lc;j++) graph->queue[graph->cptr[ncc]+j] = oqueue[ocptr[i]+j];
1368       ncc++;
1369     }
1370     graph->ncc = ncc;
1371     if (pcbddc->nedclocal) {
1372       ierr = ISRestoreIndices(pcbddc->nedclocal,(const PetscInt**)&idxs);CHKERRQ(ierr);
1373     }
1374     ierr = PetscFree2(ocptr,oqueue);CHKERRQ(ierr);
1375   }
1376   ierr = ISLocalToGlobalMappingDestroy(&fl2g);CHKERRQ(ierr);
1377   ierr = PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph,NULL,NULL,&nee,&alleedges,&allprimals);CHKERRQ(ierr);
1378   ierr = PCBDDCGraphResetCSR(pcbddc->mat_graph);CHKERRQ(ierr);
1379   ierr = MatDestroy(&conn);CHKERRQ(ierr);
1380 
1381   ierr = ISDestroy(&nedfieldlocal);CHKERRQ(ierr);
1382   ierr = PetscFree(extrow);CHKERRQ(ierr);
1383   ierr = PetscFree2(work,rwork);CHKERRQ(ierr);
1384   ierr = PetscFree(corners);CHKERRQ(ierr);
1385   ierr = PetscFree(cedges);CHKERRQ(ierr);
1386   ierr = PetscFree(extrows);CHKERRQ(ierr);
1387   ierr = PetscFree(extcols);CHKERRQ(ierr);
1388   ierr = MatDestroy(&lG);CHKERRQ(ierr);
1389 
1390   /* Complete assembling */
1391   ierr = MatAssemblyEnd(T,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1392   if (pcbddc->nedcG) {
1393     ierr = MatAssemblyEnd(pcbddc->nedcG,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1394 #if 0
1395     ierr = PetscObjectSetName((PetscObject)pcbddc->nedcG,"coarse_G");CHKERRQ(ierr);
1396     ierr = MatView(pcbddc->nedcG,NULL);CHKERRQ(ierr);
1397 #endif
1398   }
1399 
1400   /* set change of basis */
1401   ierr = PCBDDCSetChangeOfBasisMat(pc,T,singular);CHKERRQ(ierr);
1402   ierr = MatDestroy(&T);CHKERRQ(ierr);
1403 
1404   PetscFunctionReturn(0);
1405 }
1406 
1407 /* the near-null space of BDDC carries information on quadrature weights,
1408    and these can be collinear -> so cheat with MatNullSpaceCreate
1409    and create a suitable set of basis vectors first */
1410 PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1411 {
1412   PetscErrorCode ierr;
1413   PetscInt       i;
1414 
1415   PetscFunctionBegin;
1416   for (i=0;i<nvecs;i++) {
1417     PetscInt first,last;
1418 
1419     ierr = VecGetOwnershipRange(quad_vecs[i],&first,&last);CHKERRQ(ierr);
1420     if (last-first < 2*nvecs && has_const) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented");
1421     if (i>=first && i < last) {
1422       PetscScalar *data;
1423       ierr = VecGetArray(quad_vecs[i],&data);CHKERRQ(ierr);
1424       if (!has_const) {
1425         data[i-first] = 1.;
1426       } else {
1427         data[2*i-first] = 1./PetscSqrtReal(2.);
1428         data[2*i-first+1] = -1./PetscSqrtReal(2.);
1429       }
1430       ierr = VecRestoreArray(quad_vecs[i],&data);CHKERRQ(ierr);
1431     }
1432     ierr = PetscObjectStateIncrease((PetscObject)quad_vecs[i]);CHKERRQ(ierr);
1433   }
1434   ierr = MatNullSpaceCreate(comm,has_const,nvecs,quad_vecs,nnsp);CHKERRQ(ierr);
1435   for (i=0;i<nvecs;i++) { /* reset vectors */
1436     PetscInt first,last;
1437     ierr = VecLockPop(quad_vecs[i]);CHKERRQ(ierr);
1438     ierr = VecGetOwnershipRange(quad_vecs[i],&first,&last);CHKERRQ(ierr);
1439     if (i>=first && i < last) {
1440       PetscScalar *data;
1441       ierr = VecGetArray(quad_vecs[i],&data);CHKERRQ(ierr);
1442       if (!has_const) {
1443         data[i-first] = 0.;
1444       } else {
1445         data[2*i-first] = 0.;
1446         data[2*i-first+1] = 0.;
1447       }
1448       ierr = VecRestoreArray(quad_vecs[i],&data);CHKERRQ(ierr);
1449     }
1450     ierr = PetscObjectStateIncrease((PetscObject)quad_vecs[i]);CHKERRQ(ierr);
1451     ierr = VecLockPush(quad_vecs[i]);CHKERRQ(ierr);
1452   }
1453   PetscFunctionReturn(0);
1454 }
1455 
1456 PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1457 {
1458   Mat                    loc_divudotp;
1459   Vec                    p,v,vins,quad_vec,*quad_vecs;
1460   ISLocalToGlobalMapping map;
1461   PetscScalar            *vals;
1462   const PetscScalar      *array;
1463   PetscInt               i,maxneighs,maxsize;
1464   PetscInt               n_neigh,*neigh,*n_shared,**shared;
1465   PetscMPIInt            rank;
1466   PetscErrorCode         ierr;
1467 
1468   PetscFunctionBegin;
1469   ierr = ISLocalToGlobalMappingGetInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
1470   ierr = MPIU_Allreduce(&n_neigh,&maxneighs,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1471   if (!maxneighs) {
1472     ierr  = ISLocalToGlobalMappingRestoreInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
1473     *nnsp = NULL;
1474     PetscFunctionReturn(0);
1475   }
1476   maxsize = 0;
1477   for (i=0;i<n_neigh;i++) maxsize = PetscMax(n_shared[i],maxsize);
1478   ierr = PetscMalloc1(maxsize,&vals);CHKERRQ(ierr);
1479   /* create vectors to hold quadrature weights */
1480   ierr = MatCreateVecs(A,&quad_vec,NULL);CHKERRQ(ierr);
1481   if (!transpose) {
1482     ierr = MatGetLocalToGlobalMapping(A,&map,NULL);CHKERRQ(ierr);
1483   } else {
1484     ierr = MatGetLocalToGlobalMapping(A,NULL,&map);CHKERRQ(ierr);
1485   }
1486   ierr = VecDuplicateVecs(quad_vec,maxneighs,&quad_vecs);CHKERRQ(ierr);
1487   ierr = VecDestroy(&quad_vec);CHKERRQ(ierr);
1488   ierr = PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A),PETSC_FALSE,maxneighs,quad_vecs,nnsp);CHKERRQ(ierr);
1489   for (i=0;i<maxneighs;i++) {
1490     ierr = VecLockPop(quad_vecs[i]);CHKERRQ(ierr);
1491     ierr = VecSetLocalToGlobalMapping(quad_vecs[i],map);CHKERRQ(ierr);
1492   }
1493 
1494   /* compute local quad vec */
1495   ierr = MatISGetLocalMat(divudotp,&loc_divudotp);CHKERRQ(ierr);
1496   if (!transpose) {
1497     ierr = MatCreateVecs(loc_divudotp,&v,&p);CHKERRQ(ierr);
1498   } else {
1499     ierr = MatCreateVecs(loc_divudotp,&p,&v);CHKERRQ(ierr);
1500   }
1501   ierr = VecSet(p,1.);CHKERRQ(ierr);
1502   if (!transpose) {
1503     ierr = MatMultTranspose(loc_divudotp,p,v);CHKERRQ(ierr);
1504   } else {
1505     ierr = MatMult(loc_divudotp,p,v);CHKERRQ(ierr);
1506   }
1507   if (vl2l) {
1508     Mat        lA;
1509     VecScatter sc;
1510 
1511     ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
1512     ierr = MatCreateVecs(lA,&vins,NULL);CHKERRQ(ierr);
1513     ierr = VecScatterCreate(v,vl2l,vins,NULL,&sc);CHKERRQ(ierr);
1514     ierr = VecScatterBegin(sc,v,vins,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1515     ierr = VecScatterEnd(sc,v,vins,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1516     ierr = VecScatterDestroy(&sc);CHKERRQ(ierr);
1517   } else {
1518     vins = v;
1519   }
1520   ierr = VecGetArrayRead(vins,&array);CHKERRQ(ierr);
1521   ierr = VecDestroy(&p);CHKERRQ(ierr);
1522 
1523   /* insert in global quadrature vecs */
1524   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A),&rank);CHKERRQ(ierr);
1525   for (i=0;i<n_neigh;i++) {
1526     const PetscInt    *idxs;
1527     PetscInt          idx,nn,j;
1528 
1529     idxs = shared[i];
1530     nn   = n_shared[i];
1531     for (j=0;j<nn;j++) vals[j] = array[idxs[j]];
1532     ierr = PetscFindInt(rank,graph->count[idxs[0]],graph->neighbours_set[idxs[0]],&idx);CHKERRQ(ierr);
1533     idx  = -(idx+1);
1534     ierr = VecSetValuesLocal(quad_vecs[idx],nn,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
1535   }
1536   ierr = ISLocalToGlobalMappingRestoreInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
1537   ierr = VecRestoreArrayRead(vins,&array);CHKERRQ(ierr);
1538   if (vl2l) {
1539     ierr = VecDestroy(&vins);CHKERRQ(ierr);
1540   }
1541   ierr = VecDestroy(&v);CHKERRQ(ierr);
1542   ierr = PetscFree(vals);CHKERRQ(ierr);
1543 
1544   /* assemble near null space */
1545   for (i=0;i<maxneighs;i++) {
1546     ierr = VecAssemblyBegin(quad_vecs[i]);CHKERRQ(ierr);
1547   }
1548   for (i=0;i<maxneighs;i++) {
1549     ierr = VecAssemblyEnd(quad_vecs[i]);CHKERRQ(ierr);
1550     ierr = VecViewFromOptions(quad_vecs[i],NULL,"-pc_bddc_quad_vecs_view");CHKERRQ(ierr);
1551     ierr = VecLockPush(quad_vecs[i]);CHKERRQ(ierr);
1552   }
1553   ierr = VecDestroyVecs(maxneighs,&quad_vecs);CHKERRQ(ierr);
1554   PetscFunctionReturn(0);
1555 }
1556 
1557 PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1558 {
1559   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
1560   PetscErrorCode ierr;
1561 
1562   PetscFunctionBegin;
1563   if (primalv) {
1564     if (pcbddc->user_primal_vertices_local) {
1565       IS list[2], newp;
1566 
1567       list[0] = primalv;
1568       list[1] = pcbddc->user_primal_vertices_local;
1569       ierr = ISConcatenate(PetscObjectComm((PetscObject)pc),2,list,&newp);CHKERRQ(ierr);
1570       ierr = ISSortRemoveDups(newp);CHKERRQ(ierr);
1571       ierr = ISDestroy(&list[1]);CHKERRQ(ierr);
1572       pcbddc->user_primal_vertices_local = newp;
1573     } else {
1574       ierr = PCBDDCSetPrimalVerticesLocalIS(pc,primalv);CHKERRQ(ierr);
1575     }
1576   }
1577   PetscFunctionReturn(0);
1578 }
1579 
1580 static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1581 {
1582   PetscInt f, *comp  = (PetscInt *)ctx;
1583 
1584   PetscFunctionBegin;
1585   for (f=0;f<Nf;f++) out[f] = X[*comp];
1586   PetscFunctionReturn(0);
1587 }
1588 
1589 PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1590 {
1591   PetscErrorCode ierr;
1592   Vec            local,global;
1593   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
1594   Mat_IS         *matis = (Mat_IS*)pc->pmat->data;
1595   PetscBool      monolithic = PETSC_FALSE;
1596 
1597   PetscFunctionBegin;
1598   ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)pc),((PetscObject)pc)->prefix,"BDDC topology options","PC");CHKERRQ(ierr);
1599   ierr = PetscOptionsBool("-pc_bddc_monolithic","Discard any information on dofs splitting",NULL,monolithic,&monolithic,NULL);CHKERRQ(ierr);
1600   ierr = PetscOptionsEnd();CHKERRQ(ierr);
1601   /* need to convert from global to local topology information and remove references to information in global ordering */
1602   ierr = MatCreateVecs(pc->pmat,&global,NULL);CHKERRQ(ierr);
1603   ierr = MatCreateVecs(matis->A,&local,NULL);CHKERRQ(ierr);
1604   if (monolithic) { /* just get block size to properly compute vertices */
1605     if (pcbddc->vertex_size == 1) {
1606       ierr = MatGetBlockSize(pc->pmat,&pcbddc->vertex_size);CHKERRQ(ierr);
1607     }
1608     goto boundary;
1609   }
1610 
1611   if (pcbddc->user_provided_isfordofs) {
1612     if (pcbddc->n_ISForDofs) {
1613       PetscInt i;
1614       ierr = PetscMalloc1(pcbddc->n_ISForDofs,&pcbddc->ISForDofsLocal);CHKERRQ(ierr);
1615       for (i=0;i<pcbddc->n_ISForDofs;i++) {
1616         ierr = PCBDDCGlobalToLocal(matis->rctx,global,local,pcbddc->ISForDofs[i],&pcbddc->ISForDofsLocal[i]);CHKERRQ(ierr);
1617         ierr = ISDestroy(&pcbddc->ISForDofs[i]);CHKERRQ(ierr);
1618       }
1619       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
1620       pcbddc->n_ISForDofs = 0;
1621       ierr = PetscFree(pcbddc->ISForDofs);CHKERRQ(ierr);
1622     }
1623   } else {
1624     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
1625       DM dm;
1626 
1627       ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
1628       if (!dm) {
1629         ierr = MatGetDM(pc->pmat, &dm);CHKERRQ(ierr);
1630       }
1631       if (dm) {
1632         IS      *fields;
1633         PetscInt nf,i;
1634         ierr = DMCreateFieldDecomposition(dm,&nf,NULL,&fields,NULL);CHKERRQ(ierr);
1635         ierr = PetscMalloc1(nf,&pcbddc->ISForDofsLocal);CHKERRQ(ierr);
1636         for (i=0;i<nf;i++) {
1637           ierr = PCBDDCGlobalToLocal(matis->rctx,global,local,fields[i],&pcbddc->ISForDofsLocal[i]);CHKERRQ(ierr);
1638           ierr = ISDestroy(&fields[i]);CHKERRQ(ierr);
1639         }
1640         ierr = PetscFree(fields);CHKERRQ(ierr);
1641         pcbddc->n_ISForDofsLocal = nf;
1642       } else { /* See if MATIS has fields attached by the conversion from MatNest */
1643         PetscContainer   c;
1644 
1645         ierr = PetscObjectQuery((PetscObject)pc->pmat,"_convert_nest_lfields",(PetscObject*)&c);CHKERRQ(ierr);
1646         if (c) {
1647           MatISLocalFields lf;
1648           ierr = PetscContainerGetPointer(c,(void**)&lf);CHKERRQ(ierr);
1649           ierr = PCBDDCSetDofsSplittingLocal(pc,lf->nr,lf->rf);CHKERRQ(ierr);
1650         } else { /* fallback, create the default fields if bs > 1 */
1651           PetscInt i, n = matis->A->rmap->n;
1652           ierr = MatGetBlockSize(pc->pmat,&i);CHKERRQ(ierr);
1653           if (i > 1) {
1654             pcbddc->n_ISForDofsLocal = i;
1655             ierr = PetscMalloc1(pcbddc->n_ISForDofsLocal,&pcbddc->ISForDofsLocal);CHKERRQ(ierr);
1656             for (i=0;i<pcbddc->n_ISForDofsLocal;i++) {
1657               ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),n/pcbddc->n_ISForDofsLocal,i,pcbddc->n_ISForDofsLocal,&pcbddc->ISForDofsLocal[i]);CHKERRQ(ierr);
1658             }
1659           }
1660         }
1661       }
1662     } else {
1663       PetscInt i;
1664       for (i=0;i<pcbddc->n_ISForDofsLocal;i++) {
1665         ierr = PCBDDCConsistencyCheckIS(pc,MPI_LAND,&pcbddc->ISForDofsLocal[i]);CHKERRQ(ierr);
1666       }
1667     }
1668   }
1669 
1670 boundary:
1671   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
1672     ierr = PCBDDCGlobalToLocal(matis->rctx,global,local,pcbddc->DirichletBoundaries,&pcbddc->DirichletBoundariesLocal);CHKERRQ(ierr);
1673   } else if (pcbddc->DirichletBoundariesLocal) {
1674     ierr = PCBDDCConsistencyCheckIS(pc,MPI_LAND,&pcbddc->DirichletBoundariesLocal);CHKERRQ(ierr);
1675   }
1676   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
1677     ierr = PCBDDCGlobalToLocal(matis->rctx,global,local,pcbddc->NeumannBoundaries,&pcbddc->NeumannBoundariesLocal);CHKERRQ(ierr);
1678   } else if (pcbddc->NeumannBoundariesLocal) {
1679     ierr = PCBDDCConsistencyCheckIS(pc,MPI_LOR,&pcbddc->NeumannBoundariesLocal);CHKERRQ(ierr);
1680   }
1681   if (!pcbddc->user_primal_vertices_local && pcbddc->user_primal_vertices) {
1682     ierr = PCBDDCGlobalToLocal(matis->rctx,global,local,pcbddc->user_primal_vertices,&pcbddc->user_primal_vertices_local);CHKERRQ(ierr);
1683   }
1684   ierr = VecDestroy(&global);CHKERRQ(ierr);
1685   ierr = VecDestroy(&local);CHKERRQ(ierr);
1686   /* detect local disconnected subdomains if requested (use matis->A) */
1687   if (pcbddc->detect_disconnected) {
1688     IS        primalv = NULL;
1689     PetscInt  i;
1690     PetscBool filter = pcbddc->detect_disconnected_filter;
1691 
1692     for (i=0;i<pcbddc->n_local_subs;i++) {
1693       ierr = ISDestroy(&pcbddc->local_subs[i]);CHKERRQ(ierr);
1694     }
1695     ierr = PetscFree(pcbddc->local_subs);CHKERRQ(ierr);
1696     ierr = PCBDDCDetectDisconnectedComponents(pc,filter,&pcbddc->n_local_subs,&pcbddc->local_subs,&primalv);CHKERRQ(ierr);
1697     ierr = PCBDDCAddPrimalVerticesLocalIS(pc,primalv);CHKERRQ(ierr);
1698     ierr = ISDestroy(&primalv);CHKERRQ(ierr);
1699   }
1700   /* early stage corner detection */
1701   {
1702     DM dm;
1703 
1704     ierr = MatGetDM(pc->pmat,&dm);CHKERRQ(ierr);
1705     if (dm) {
1706       PetscBool isda;
1707 
1708       ierr = PetscObjectTypeCompare((PetscObject)dm,DMDA,&isda);CHKERRQ(ierr);
1709       if (isda) {
1710         ISLocalToGlobalMapping l2l;
1711         IS                     corners;
1712         Mat                    lA;
1713 
1714         ierr = DMDAGetSubdomainCornersIS(dm,&corners);CHKERRQ(ierr);
1715         ierr = MatISGetLocalMat(pc->pmat,&lA);CHKERRQ(ierr);
1716         ierr = MatGetLocalToGlobalMapping(lA,&l2l,NULL);CHKERRQ(ierr);
1717         ierr = MatISRestoreLocalMat(pc->pmat,&lA);CHKERRQ(ierr);
1718         if (l2l && corners) {
1719           const PetscInt *idx;
1720           PetscInt       dof,bs,*idxout,n;
1721 
1722           ierr = DMDAGetInfo(dm,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL);CHKERRQ(ierr);
1723           ierr = ISLocalToGlobalMappingGetBlockSize(l2l,&bs);CHKERRQ(ierr);
1724           ierr = ISGetLocalSize(corners,&n);CHKERRQ(ierr);
1725           ierr = ISGetIndices(corners,&idx);CHKERRQ(ierr);
1726           if (bs == dof) {
1727             ierr = PetscMalloc1(n,&idxout);CHKERRQ(ierr);
1728             ierr = ISLocalToGlobalMappingApplyBlock(l2l,n,idx,idxout);CHKERRQ(ierr);
1729           } else { /* the original DMDA local-to-local map have been modified */
1730             PetscInt i,d;
1731 
1732             ierr = PetscMalloc1(dof*n,&idxout);CHKERRQ(ierr);
1733             for (i=0;i<n;i++) for (d=0;d<dof;d++) idxout[dof*i+d] = dof*idx[i]+d;
1734             ierr = ISLocalToGlobalMappingApply(l2l,dof*n,idxout,idxout);CHKERRQ(ierr);
1735 
1736             bs = 1;
1737             n *= dof;
1738           }
1739           ierr = ISRestoreIndices(corners,&idx);CHKERRQ(ierr);
1740           ierr = DMDARestoreSubdomainCornersIS(dm,&corners);CHKERRQ(ierr);
1741           ierr = ISCreateBlock(PetscObjectComm((PetscObject)pc),bs,n,idxout,PETSC_OWN_POINTER,&corners);CHKERRQ(ierr);
1742           ierr = PCBDDCAddPrimalVerticesLocalIS(pc,corners);CHKERRQ(ierr);
1743           ierr = ISDestroy(&corners);CHKERRQ(ierr);
1744           pcbddc->corner_selected = PETSC_TRUE;
1745         } else if (corners) { /* not from DMDA */
1746           ierr = DMDARestoreSubdomainCornersIS(dm,&corners);CHKERRQ(ierr);
1747         }
1748       }
1749     }
1750   }
1751   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
1752     DM dm;
1753 
1754     ierr = PCGetDM(pc,&dm);CHKERRQ(ierr);
1755     if (!dm) {
1756       ierr = MatGetDM(pc->pmat,&dm);CHKERRQ(ierr);
1757     }
1758     if (dm) {
1759       Vec            vcoords;
1760       PetscSection   section;
1761       PetscReal      *coords;
1762       PetscInt       d,cdim,nl,nf,**ctxs;
1763       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
1764 
1765       ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
1766       ierr = DMGetSection(dm,&section);CHKERRQ(ierr);
1767       ierr = PetscSectionGetNumFields(section,&nf);CHKERRQ(ierr);
1768       ierr = DMCreateGlobalVector(dm,&vcoords);CHKERRQ(ierr);
1769       ierr = VecGetLocalSize(vcoords,&nl);CHKERRQ(ierr);
1770       ierr = PetscMalloc1(nl*cdim,&coords);CHKERRQ(ierr);
1771       ierr = PetscMalloc2(nf,&funcs,nf,&ctxs);CHKERRQ(ierr);
1772       ierr = PetscMalloc1(nf,&ctxs[0]);CHKERRQ(ierr);
1773       for (d=0;d<nf;d++) funcs[d] = func_coords_private;
1774       for (d=1;d<nf;d++) ctxs[d] = ctxs[d-1] + 1;
1775       for (d=0;d<cdim;d++) {
1776         PetscInt          i;
1777         const PetscScalar *v;
1778 
1779         for (i=0;i<nf;i++) ctxs[i][0] = d;
1780         ierr = DMProjectFunction(dm,0.0,funcs,(void**)ctxs,INSERT_VALUES,vcoords);CHKERRQ(ierr);
1781         ierr = VecGetArrayRead(vcoords,&v);CHKERRQ(ierr);
1782         for (i=0;i<nl;i++) coords[i*cdim+d] = PetscRealPart(v[i]);
1783         ierr = VecRestoreArrayRead(vcoords,&v);CHKERRQ(ierr);
1784       }
1785       ierr = VecDestroy(&vcoords);CHKERRQ(ierr);
1786       ierr = PCSetCoordinates(pc,cdim,nl,coords);CHKERRQ(ierr);
1787       ierr = PetscFree(coords);CHKERRQ(ierr);
1788       ierr = PetscFree(ctxs[0]);CHKERRQ(ierr);
1789       ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr);
1790     }
1791   }
1792   PetscFunctionReturn(0);
1793 }
1794 
1795 PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
1796 {
1797   Mat_IS          *matis = (Mat_IS*)(pc->pmat->data);
1798   PetscErrorCode  ierr;
1799   IS              nis;
1800   const PetscInt  *idxs;
1801   PetscInt        i,nd,n = matis->A->rmap->n,*nidxs,nnd;
1802   PetscBool       *ld;
1803 
1804   PetscFunctionBegin;
1805   if (mop != MPI_LAND && mop != MPI_LOR) SETERRQ(PetscObjectComm((PetscObject)(pc)),PETSC_ERR_SUP,"Supported are MPI_LAND and MPI_LOR");
1806   ierr = MatISSetUpSF(pc->pmat);CHKERRQ(ierr);
1807   if (mop == MPI_LAND) {
1808     /* init rootdata with true */
1809     ld   = (PetscBool*) matis->sf_rootdata;
1810     for (i=0;i<pc->pmat->rmap->n;i++) ld[i] = PETSC_TRUE;
1811   } else {
1812     ierr = PetscMemzero(matis->sf_rootdata,pc->pmat->rmap->n*sizeof(PetscBool));CHKERRQ(ierr);
1813   }
1814   ierr = PetscMemzero(matis->sf_leafdata,n*sizeof(PetscBool));CHKERRQ(ierr);
1815   ierr = ISGetLocalSize(*is,&nd);CHKERRQ(ierr);
1816   ierr = ISGetIndices(*is,&idxs);CHKERRQ(ierr);
1817   ld   = (PetscBool*) matis->sf_leafdata;
1818   for (i=0;i<nd;i++)
1819     if (-1 < idxs[i] && idxs[i] < n)
1820       ld[idxs[i]] = PETSC_TRUE;
1821   ierr = ISRestoreIndices(*is,&idxs);CHKERRQ(ierr);
1822   ierr = PetscSFReduceBegin(matis->sf,MPIU_BOOL,matis->sf_leafdata,matis->sf_rootdata,mop);CHKERRQ(ierr);
1823   ierr = PetscSFReduceEnd(matis->sf,MPIU_BOOL,matis->sf_leafdata,matis->sf_rootdata,mop);CHKERRQ(ierr);
1824   ierr = PetscSFBcastBegin(matis->sf,MPIU_BOOL,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1825   ierr = PetscSFBcastEnd(matis->sf,MPIU_BOOL,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1826   if (mop == MPI_LAND) {
1827     ierr = PetscMalloc1(nd,&nidxs);CHKERRQ(ierr);
1828   } else {
1829     ierr = PetscMalloc1(n,&nidxs);CHKERRQ(ierr);
1830   }
1831   for (i=0,nnd=0;i<n;i++)
1832     if (ld[i])
1833       nidxs[nnd++] = i;
1834   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)(*is)),nnd,nidxs,PETSC_OWN_POINTER,&nis);CHKERRQ(ierr);
1835   ierr = ISDestroy(is);CHKERRQ(ierr);
1836   *is  = nis;
1837   PetscFunctionReturn(0);
1838 }
1839 
1840 PetscErrorCode PCBDDCBenignRemoveInterior(PC pc,Vec r,Vec z)
1841 {
1842   PC_IS             *pcis = (PC_IS*)(pc->data);
1843   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
1844   PetscErrorCode    ierr;
1845 
1846   PetscFunctionBegin;
1847   if (!pcbddc->benign_have_null) {
1848     PetscFunctionReturn(0);
1849   }
1850   if (pcbddc->ChangeOfBasisMatrix) {
1851     Vec swap;
1852 
1853     ierr = MatMultTranspose(pcbddc->ChangeOfBasisMatrix,r,pcbddc->work_change);CHKERRQ(ierr);
1854     swap = pcbddc->work_change;
1855     pcbddc->work_change = r;
1856     r = swap;
1857   }
1858   ierr = VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1859   ierr = VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1860   ierr = KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
1861   ierr = VecSet(z,0.);CHKERRQ(ierr);
1862   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1863   ierr = VecScatterEnd(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1864   if (pcbddc->ChangeOfBasisMatrix) {
1865     pcbddc->work_change = r;
1866     ierr = VecCopy(z,pcbddc->work_change);CHKERRQ(ierr);
1867     ierr = MatMult(pcbddc->ChangeOfBasisMatrix,pcbddc->work_change,z);CHKERRQ(ierr);
1868   }
1869   PetscFunctionReturn(0);
1870 }
1871 
1872 PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
1873 {
1874   PCBDDCBenignMatMult_ctx ctx;
1875   PetscErrorCode          ierr;
1876   PetscBool               apply_right,apply_left,reset_x;
1877 
1878   PetscFunctionBegin;
1879   ierr = MatShellGetContext(A,&ctx);CHKERRQ(ierr);
1880   if (transpose) {
1881     apply_right = ctx->apply_left;
1882     apply_left = ctx->apply_right;
1883   } else {
1884     apply_right = ctx->apply_right;
1885     apply_left = ctx->apply_left;
1886   }
1887   reset_x = PETSC_FALSE;
1888   if (apply_right) {
1889     const PetscScalar *ax;
1890     PetscInt          nl,i;
1891 
1892     ierr = VecGetLocalSize(x,&nl);CHKERRQ(ierr);
1893     ierr = VecGetArrayRead(x,&ax);CHKERRQ(ierr);
1894     ierr = PetscMemcpy(ctx->work,ax,nl*sizeof(PetscScalar));CHKERRQ(ierr);
1895     ierr = VecRestoreArrayRead(x,&ax);CHKERRQ(ierr);
1896     for (i=0;i<ctx->benign_n;i++) {
1897       PetscScalar    sum,val;
1898       const PetscInt *idxs;
1899       PetscInt       nz,j;
1900       ierr = ISGetLocalSize(ctx->benign_zerodiag_subs[i],&nz);CHKERRQ(ierr);
1901       ierr = ISGetIndices(ctx->benign_zerodiag_subs[i],&idxs);CHKERRQ(ierr);
1902       sum = 0.;
1903       if (ctx->apply_p0) {
1904         val = ctx->work[idxs[nz-1]];
1905         for (j=0;j<nz-1;j++) {
1906           sum += ctx->work[idxs[j]];
1907           ctx->work[idxs[j]] += val;
1908         }
1909       } else {
1910         for (j=0;j<nz-1;j++) {
1911           sum += ctx->work[idxs[j]];
1912         }
1913       }
1914       ctx->work[idxs[nz-1]] -= sum;
1915       ierr = ISRestoreIndices(ctx->benign_zerodiag_subs[i],&idxs);CHKERRQ(ierr);
1916     }
1917     ierr = VecPlaceArray(x,ctx->work);CHKERRQ(ierr);
1918     reset_x = PETSC_TRUE;
1919   }
1920   if (transpose) {
1921     ierr = MatMultTranspose(ctx->A,x,y);CHKERRQ(ierr);
1922   } else {
1923     ierr = MatMult(ctx->A,x,y);CHKERRQ(ierr);
1924   }
1925   if (reset_x) {
1926     ierr = VecResetArray(x);CHKERRQ(ierr);
1927   }
1928   if (apply_left) {
1929     PetscScalar *ay;
1930     PetscInt    i;
1931 
1932     ierr = VecGetArray(y,&ay);CHKERRQ(ierr);
1933     for (i=0;i<ctx->benign_n;i++) {
1934       PetscScalar    sum,val;
1935       const PetscInt *idxs;
1936       PetscInt       nz,j;
1937       ierr = ISGetLocalSize(ctx->benign_zerodiag_subs[i],&nz);CHKERRQ(ierr);
1938       ierr = ISGetIndices(ctx->benign_zerodiag_subs[i],&idxs);CHKERRQ(ierr);
1939       val = -ay[idxs[nz-1]];
1940       if (ctx->apply_p0) {
1941         sum = 0.;
1942         for (j=0;j<nz-1;j++) {
1943           sum += ay[idxs[j]];
1944           ay[idxs[j]] += val;
1945         }
1946         ay[idxs[nz-1]] += sum;
1947       } else {
1948         for (j=0;j<nz-1;j++) {
1949           ay[idxs[j]] += val;
1950         }
1951         ay[idxs[nz-1]] = 0.;
1952       }
1953       ierr = ISRestoreIndices(ctx->benign_zerodiag_subs[i],&idxs);CHKERRQ(ierr);
1954     }
1955     ierr = VecRestoreArray(y,&ay);CHKERRQ(ierr);
1956   }
1957   PetscFunctionReturn(0);
1958 }
1959 
1960 PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
1961 {
1962   PetscErrorCode ierr;
1963 
1964   PetscFunctionBegin;
1965   ierr = PCBDDCBenignMatMult_Private_Private(A,x,y,PETSC_TRUE);CHKERRQ(ierr);
1966   PetscFunctionReturn(0);
1967 }
1968 
1969 PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
1970 {
1971   PetscErrorCode ierr;
1972 
1973   PetscFunctionBegin;
1974   ierr = PCBDDCBenignMatMult_Private_Private(A,x,y,PETSC_FALSE);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
1979 {
1980   PC_IS                   *pcis = (PC_IS*)pc->data;
1981   PC_BDDC                 *pcbddc = (PC_BDDC*)pc->data;
1982   PCBDDCBenignMatMult_ctx ctx;
1983   PetscErrorCode          ierr;
1984 
1985   PetscFunctionBegin;
1986   if (!restore) {
1987     Mat                A_IB,A_BI;
1988     PetscScalar        *work;
1989     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
1990 
1991     if (pcbddc->benign_original_mat) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Benign original mat has not been restored");
1992     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(0);
1993     ierr = PetscMalloc1(pcis->n,&work);CHKERRQ(ierr);
1994     ierr = MatCreate(PETSC_COMM_SELF,&A_IB);CHKERRQ(ierr);
1995     ierr = MatSetSizes(A_IB,pcis->n-pcis->n_B,pcis->n_B,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
1996     ierr = MatSetType(A_IB,MATSHELL);CHKERRQ(ierr);
1997     ierr = MatShellSetOperation(A_IB,MATOP_MULT,(void (*)(void))PCBDDCBenignMatMult_Private);CHKERRQ(ierr);
1998     ierr = MatShellSetOperation(A_IB,MATOP_MULT_TRANSPOSE,(void (*)(void))PCBDDCBenignMatMultTranspose_Private);CHKERRQ(ierr);
1999     ierr = PetscNew(&ctx);CHKERRQ(ierr);
2000     ierr = MatShellSetContext(A_IB,ctx);CHKERRQ(ierr);
2001     ctx->apply_left = PETSC_TRUE;
2002     ctx->apply_right = PETSC_FALSE;
2003     ctx->apply_p0 = PETSC_FALSE;
2004     ctx->benign_n = pcbddc->benign_n;
2005     if (reuse) {
2006       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
2007       ctx->free = PETSC_FALSE;
2008     } else { /* TODO: could be optimized for successive solves */
2009       ISLocalToGlobalMapping N_to_D;
2010       PetscInt               i;
2011 
2012       ierr = ISLocalToGlobalMappingCreateIS(pcis->is_I_local,&N_to_D);CHKERRQ(ierr);
2013       ierr = PetscMalloc1(pcbddc->benign_n,&ctx->benign_zerodiag_subs);CHKERRQ(ierr);
2014       for (i=0;i<pcbddc->benign_n;i++) {
2015         ierr = ISGlobalToLocalMappingApplyIS(N_to_D,IS_GTOLM_DROP,pcbddc->benign_zerodiag_subs[i],&ctx->benign_zerodiag_subs[i]);CHKERRQ(ierr);
2016       }
2017       ierr = ISLocalToGlobalMappingDestroy(&N_to_D);CHKERRQ(ierr);
2018       ctx->free = PETSC_TRUE;
2019     }
2020     ctx->A = pcis->A_IB;
2021     ctx->work = work;
2022     ierr = MatSetUp(A_IB);CHKERRQ(ierr);
2023     ierr = MatAssemblyBegin(A_IB,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2024     ierr = MatAssemblyEnd(A_IB,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2025     pcis->A_IB = A_IB;
2026 
2027     /* A_BI as A_IB^T */
2028     ierr = MatCreateTranspose(A_IB,&A_BI);CHKERRQ(ierr);
2029     pcbddc->benign_original_mat = pcis->A_BI;
2030     pcis->A_BI = A_BI;
2031   } else {
2032     if (!pcbddc->benign_original_mat) {
2033       PetscFunctionReturn(0);
2034     }
2035     ierr = MatShellGetContext(pcis->A_IB,&ctx);CHKERRQ(ierr);
2036     ierr = MatDestroy(&pcis->A_IB);CHKERRQ(ierr);
2037     pcis->A_IB = ctx->A;
2038     ctx->A = NULL;
2039     ierr = MatDestroy(&pcis->A_BI);CHKERRQ(ierr);
2040     pcis->A_BI = pcbddc->benign_original_mat;
2041     pcbddc->benign_original_mat = NULL;
2042     if (ctx->free) {
2043       PetscInt i;
2044       for (i=0;i<ctx->benign_n;i++) {
2045         ierr = ISDestroy(&ctx->benign_zerodiag_subs[i]);CHKERRQ(ierr);
2046       }
2047       ierr = PetscFree(ctx->benign_zerodiag_subs);CHKERRQ(ierr);
2048     }
2049     ierr = PetscFree(ctx->work);CHKERRQ(ierr);
2050     ierr = PetscFree(ctx);CHKERRQ(ierr);
2051   }
2052   PetscFunctionReturn(0);
2053 }
2054 
2055 /* used just in bddc debug mode */
2056 PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2057 {
2058   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
2059   Mat_IS         *matis = (Mat_IS*)pc->pmat->data;
2060   Mat            An;
2061   PetscErrorCode ierr;
2062 
2063   PetscFunctionBegin;
2064   ierr = MatPtAP(matis->A,pcbddc->benign_change,MAT_INITIAL_MATRIX,2.0,&An);CHKERRQ(ierr);
2065   ierr = MatZeroRowsColumns(An,pcbddc->benign_n,pcbddc->benign_p0_lidx,1.0,NULL,NULL);CHKERRQ(ierr);
2066   if (is1) {
2067     ierr = MatCreateSubMatrix(An,is1,is2,MAT_INITIAL_MATRIX,B);CHKERRQ(ierr);
2068     ierr = MatDestroy(&An);CHKERRQ(ierr);
2069   } else {
2070     *B = An;
2071   }
2072   PetscFunctionReturn(0);
2073 }
2074 
2075 /* TODO: add reuse flag */
2076 PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2077 {
2078   Mat            Bt;
2079   PetscScalar    *a,*bdata;
2080   const PetscInt *ii,*ij;
2081   PetscInt       m,n,i,nnz,*bii,*bij;
2082   PetscBool      flg_row;
2083   PetscErrorCode ierr;
2084 
2085   PetscFunctionBegin;
2086   ierr = MatGetSize(A,&n,&m);CHKERRQ(ierr);
2087   ierr = MatGetRowIJ(A,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,&ij,&flg_row);CHKERRQ(ierr);
2088   ierr = MatSeqAIJGetArray(A,&a);CHKERRQ(ierr);
2089   nnz = n;
2090   for (i=0;i<ii[n];i++) {
2091     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
2092   }
2093   ierr = PetscMalloc1(n+1,&bii);CHKERRQ(ierr);
2094   ierr = PetscMalloc1(nnz,&bij);CHKERRQ(ierr);
2095   ierr = PetscMalloc1(nnz,&bdata);CHKERRQ(ierr);
2096   nnz = 0;
2097   bii[0] = 0;
2098   for (i=0;i<n;i++) {
2099     PetscInt j;
2100     for (j=ii[i];j<ii[i+1];j++) {
2101       PetscScalar entry = a[j];
2102       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
2103         bij[nnz] = ij[j];
2104         bdata[nnz] = entry;
2105         nnz++;
2106       }
2107     }
2108     bii[i+1] = nnz;
2109   }
2110   ierr = MatSeqAIJRestoreArray(A,&a);CHKERRQ(ierr);
2111   ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),n,m,bii,bij,bdata,&Bt);CHKERRQ(ierr);
2112   ierr = MatRestoreRowIJ(A,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,&ij,&flg_row);CHKERRQ(ierr);
2113   {
2114     Mat_SeqAIJ *b = (Mat_SeqAIJ*)(Bt->data);
2115     b->free_a = PETSC_TRUE;
2116     b->free_ij = PETSC_TRUE;
2117   }
2118   if (*B == A) {
2119     ierr = MatDestroy(&A);CHKERRQ(ierr);
2120   }
2121   *B = Bt;
2122   PetscFunctionReturn(0);
2123 }
2124 
2125 PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS* cc[], IS* primalv)
2126 {
2127   Mat                    B = NULL;
2128   DM                     dm;
2129   IS                     is_dummy,*cc_n;
2130   ISLocalToGlobalMapping l2gmap_dummy;
2131   PCBDDCGraph            graph;
2132   PetscInt               *xadj_filtered = NULL,*adjncy_filtered = NULL;
2133   PetscInt               i,n;
2134   PetscInt               *xadj,*adjncy;
2135   PetscBool              isplex = PETSC_FALSE;
2136   PetscErrorCode         ierr;
2137 
2138   PetscFunctionBegin;
2139   if (ncc) *ncc = 0;
2140   if (cc) *cc = NULL;
2141   if (primalv) *primalv = NULL;
2142   ierr = PCBDDCGraphCreate(&graph);CHKERRQ(ierr);
2143   ierr = PCGetDM(pc,&dm);CHKERRQ(ierr);
2144   if (!dm) {
2145     ierr = MatGetDM(pc->pmat,&dm);CHKERRQ(ierr);
2146   }
2147   if (dm) {
2148     ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex);CHKERRQ(ierr);
2149   }
2150   if (filter) isplex = PETSC_FALSE;
2151 
2152   if (isplex) { /* this code has been modified from plexpartition.c */
2153     PetscInt       p, pStart, pEnd, a, adjSize, idx, size, nroots;
2154     PetscInt      *adj = NULL;
2155     IS             cellNumbering;
2156     const PetscInt *cellNum;
2157     PetscBool      useCone, useClosure;
2158     PetscSection   section;
2159     PetscSegBuffer adjBuffer;
2160     PetscSF        sfPoint;
2161     PetscErrorCode ierr;
2162 
2163     PetscFunctionBegin;
2164     ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
2165     ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
2166     ierr = PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
2167     /* Build adjacency graph via a section/segbuffer */
2168     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
2169     ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
2170     ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
2171     /* Always use FVM adjacency to create partitioner graph */
2172     ierr = DMPlexGetAdjacencyUseCone(dm, &useCone);CHKERRQ(ierr);
2173     ierr = DMPlexGetAdjacencyUseClosure(dm, &useClosure);CHKERRQ(ierr);
2174     ierr = DMPlexSetAdjacencyUseCone(dm, PETSC_TRUE);CHKERRQ(ierr);
2175     ierr = DMPlexSetAdjacencyUseClosure(dm, PETSC_FALSE);CHKERRQ(ierr);
2176     ierr = DMPlexGetCellNumbering(dm, &cellNumbering);CHKERRQ(ierr);
2177     ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
2178     for (n = 0, p = pStart; p < pEnd; p++) {
2179       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
2180       if (nroots > 0) {if (cellNum[p] < 0) continue;}
2181       adjSize = PETSC_DETERMINE;
2182       ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
2183       for (a = 0; a < adjSize; ++a) {
2184         const PetscInt point = adj[a];
2185         if (pStart <= point && point < pEnd) {
2186           PetscInt *PETSC_RESTRICT pBuf;
2187           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
2188           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
2189           *pBuf = point;
2190         }
2191       }
2192       n++;
2193     }
2194     ierr = DMPlexSetAdjacencyUseCone(dm, useCone);CHKERRQ(ierr);
2195     ierr = DMPlexSetAdjacencyUseClosure(dm, useClosure);CHKERRQ(ierr);
2196     /* Derive CSR graph from section/segbuffer */
2197     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
2198     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2199     ierr = PetscMalloc1(n+1, &xadj);CHKERRQ(ierr);
2200     for (idx = 0, p = pStart; p < pEnd; p++) {
2201       if (nroots > 0) {if (cellNum[p] < 0) continue;}
2202       ierr = PetscSectionGetOffset(section, p, &(xadj[idx++]));CHKERRQ(ierr);
2203     }
2204     xadj[n] = size;
2205     ierr = PetscSegBufferExtractAlloc(adjBuffer, &adjncy);CHKERRQ(ierr);
2206     /* Clean up */
2207     ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
2208     ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
2209     ierr = PetscFree(adj);CHKERRQ(ierr);
2210     graph->xadj = xadj;
2211     graph->adjncy = adjncy;
2212   } else {
2213     Mat       A;
2214     PetscBool isseqaij, flg_row;
2215 
2216     ierr = MatISGetLocalMat(pc->pmat,&A);CHKERRQ(ierr);
2217     if (!A->rmap->N || !A->cmap->N) {
2218       ierr = PCBDDCGraphDestroy(&graph);CHKERRQ(ierr);
2219       PetscFunctionReturn(0);
2220     }
2221     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
2222     if (!isseqaij && filter) {
2223       PetscBool isseqdense;
2224 
2225       ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQDENSE,&isseqdense);CHKERRQ(ierr);
2226       if (!isseqdense) {
2227         ierr = MatConvert(A,MATSEQAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
2228       } else { /* TODO: rectangular case and LDA */
2229         PetscScalar *array;
2230         PetscReal   chop=1.e-6;
2231 
2232         ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
2233         ierr = MatDenseGetArray(B,&array);CHKERRQ(ierr);
2234         ierr = MatGetSize(B,&n,NULL);CHKERRQ(ierr);
2235         for (i=0;i<n;i++) {
2236           PetscInt j;
2237           for (j=i+1;j<n;j++) {
2238             PetscReal thresh = chop*(PetscAbsScalar(array[i*(n+1)])+PetscAbsScalar(array[j*(n+1)]));
2239             if (PetscAbsScalar(array[i*n+j]) < thresh) array[i*n+j] = 0.;
2240             if (PetscAbsScalar(array[j*n+i]) < thresh) array[j*n+i] = 0.;
2241           }
2242         }
2243         ierr = MatDenseRestoreArray(B,&array);CHKERRQ(ierr);
2244         ierr = MatConvert(B,MATSEQAIJ,MAT_INPLACE_MATRIX,&B);CHKERRQ(ierr);
2245       }
2246     } else {
2247       ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
2248       B = A;
2249     }
2250     ierr = MatGetRowIJ(B,0,PETSC_TRUE,PETSC_FALSE,&n,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&flg_row);CHKERRQ(ierr);
2251 
2252     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
2253     if (filter) {
2254       PetscScalar *data;
2255       PetscInt    j,cum;
2256 
2257       ierr = PetscCalloc2(n+1,&xadj_filtered,xadj[n],&adjncy_filtered);CHKERRQ(ierr);
2258       ierr = MatSeqAIJGetArray(B,&data);CHKERRQ(ierr);
2259       cum = 0;
2260       for (i=0;i<n;i++) {
2261         PetscInt t;
2262 
2263         for (j=xadj[i];j<xadj[i+1];j++) {
2264           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) {
2265             continue;
2266           }
2267           adjncy_filtered[cum+xadj_filtered[i]++] = adjncy[j];
2268         }
2269         t = xadj_filtered[i];
2270         xadj_filtered[i] = cum;
2271         cum += t;
2272       }
2273       ierr = MatSeqAIJRestoreArray(B,&data);CHKERRQ(ierr);
2274       graph->xadj = xadj_filtered;
2275       graph->adjncy = adjncy_filtered;
2276     } else {
2277       graph->xadj = xadj;
2278       graph->adjncy = adjncy;
2279     }
2280   }
2281   /* compute local connected components using PCBDDCGraph */
2282   ierr = ISCreateStride(PETSC_COMM_SELF,n,0,1,&is_dummy);CHKERRQ(ierr);
2283   ierr = ISLocalToGlobalMappingCreateIS(is_dummy,&l2gmap_dummy);CHKERRQ(ierr);
2284   ierr = ISDestroy(&is_dummy);CHKERRQ(ierr);
2285   ierr = PCBDDCGraphInit(graph,l2gmap_dummy,n,PETSC_MAX_INT);CHKERRQ(ierr);
2286   ierr = ISLocalToGlobalMappingDestroy(&l2gmap_dummy);CHKERRQ(ierr);
2287   ierr = PCBDDCGraphSetUp(graph,1,NULL,NULL,0,NULL,NULL);CHKERRQ(ierr);
2288   ierr = PCBDDCGraphComputeConnectedComponents(graph);CHKERRQ(ierr);
2289 
2290   /* partial clean up */
2291   ierr = PetscFree2(xadj_filtered,adjncy_filtered);CHKERRQ(ierr);
2292   if (B) {
2293     PetscBool flg_row;
2294     ierr = MatRestoreRowIJ(B,0,PETSC_TRUE,PETSC_FALSE,&n,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&flg_row);CHKERRQ(ierr);
2295     ierr = MatDestroy(&B);CHKERRQ(ierr);
2296   }
2297   if (isplex) {
2298     ierr = PetscFree(xadj);CHKERRQ(ierr);
2299     ierr = PetscFree(adjncy);CHKERRQ(ierr);
2300   }
2301 
2302   /* get back data */
2303   if (isplex) {
2304     if (ncc) *ncc = graph->ncc;
2305     if (cc || primalv) {
2306       Mat          A;
2307       PetscBT      btv,btvt;
2308       PetscSection subSection;
2309       PetscInt     *ids,cum,cump,*cids,*pids;
2310 
2311       ierr = DMPlexGetSubdomainSection(dm,&subSection);CHKERRQ(ierr);
2312       ierr = MatISGetLocalMat(pc->pmat,&A);CHKERRQ(ierr);
2313       ierr = PetscMalloc3(A->rmap->n,&ids,graph->ncc+1,&cids,A->rmap->n,&pids);CHKERRQ(ierr);
2314       ierr = PetscBTCreate(A->rmap->n,&btv);CHKERRQ(ierr);
2315       ierr = PetscBTCreate(A->rmap->n,&btvt);CHKERRQ(ierr);
2316 
2317       cids[0] = 0;
2318       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2319         PetscInt j;
2320 
2321         ierr = PetscBTMemzero(A->rmap->n,btvt);CHKERRQ(ierr);
2322         for (j = graph->cptr[i]; j < graph->cptr[i+1]; j++) {
2323           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2324 
2325           ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&size,&closure);CHKERRQ(ierr);
2326           for (k = 0; k < 2*size; k += 2) {
2327             PetscInt s, p = closure[k], off, dof, cdof;
2328 
2329             ierr = PetscSectionGetConstraintDof(subSection, p, &cdof);CHKERRQ(ierr);
2330             ierr = PetscSectionGetOffset(subSection,p,&off);CHKERRQ(ierr);
2331             ierr = PetscSectionGetDof(subSection,p,&dof);CHKERRQ(ierr);
2332             for (s = 0; s < dof-cdof; s++) {
2333               if (PetscBTLookupSet(btvt,off+s)) continue;
2334               if (!PetscBTLookup(btv,off+s)) {
2335                 ids[cum++] = off+s;
2336               } else { /* cross-vertex */
2337                 pids[cump++] = off+s;
2338               }
2339             }
2340           }
2341           ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&size,&closure);CHKERRQ(ierr);
2342         }
2343         cids[i+1] = cum;
2344         /* mark dofs as already assigned */
2345         for (j = cids[i]; j < cids[i+1]; j++) {
2346           ierr = PetscBTSet(btv,ids[j]);CHKERRQ(ierr);
2347         }
2348       }
2349       if (cc) {
2350         ierr = PetscMalloc1(graph->ncc,&cc_n);CHKERRQ(ierr);
2351         for (i = 0; i < graph->ncc; i++) {
2352           ierr = ISCreateGeneral(PETSC_COMM_SELF,cids[i+1]-cids[i],ids+cids[i],PETSC_COPY_VALUES,&cc_n[i]);CHKERRQ(ierr);
2353         }
2354         *cc = cc_n;
2355       }
2356       if (primalv) {
2357         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),cump,pids,PETSC_COPY_VALUES,primalv);CHKERRQ(ierr);
2358       }
2359       ierr = PetscFree3(ids,cids,pids);CHKERRQ(ierr);
2360       ierr = PetscBTDestroy(&btv);CHKERRQ(ierr);
2361       ierr = PetscBTDestroy(&btvt);CHKERRQ(ierr);
2362     }
2363   } else {
2364     if (ncc) *ncc = graph->ncc;
2365     if (cc) {
2366       ierr = PetscMalloc1(graph->ncc,&cc_n);CHKERRQ(ierr);
2367       for (i=0;i<graph->ncc;i++) {
2368         ierr = ISCreateGeneral(PETSC_COMM_SELF,graph->cptr[i+1]-graph->cptr[i],graph->queue+graph->cptr[i],PETSC_COPY_VALUES,&cc_n[i]);CHKERRQ(ierr);
2369       }
2370       *cc = cc_n;
2371     }
2372   }
2373   /* clean up graph */
2374   graph->xadj = 0;
2375   graph->adjncy = 0;
2376   ierr = PCBDDCGraphDestroy(&graph);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2381 {
2382   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
2383   PC_IS*         pcis = (PC_IS*)(pc->data);
2384   IS             dirIS = NULL;
2385   PetscInt       i;
2386   PetscErrorCode ierr;
2387 
2388   PetscFunctionBegin;
2389   ierr = PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph,&dirIS);CHKERRQ(ierr);
2390   if (zerodiag) {
2391     Mat            A;
2392     Vec            vec3_N;
2393     PetscScalar    *vals;
2394     const PetscInt *idxs;
2395     PetscInt       nz,*count;
2396 
2397     /* p0 */
2398     ierr = VecSet(pcis->vec1_N,0.);CHKERRQ(ierr);
2399     ierr = PetscMalloc1(pcis->n,&vals);CHKERRQ(ierr);
2400     ierr = ISGetLocalSize(zerodiag,&nz);CHKERRQ(ierr);
2401     ierr = ISGetIndices(zerodiag,&idxs);CHKERRQ(ierr);
2402     for (i=0;i<nz;i++) vals[i] = 1.;
2403     ierr = VecSetValues(pcis->vec1_N,nz,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
2404     ierr = VecAssemblyBegin(pcis->vec1_N);CHKERRQ(ierr);
2405     ierr = VecAssemblyEnd(pcis->vec1_N);CHKERRQ(ierr);
2406     /* v_I */
2407     ierr = VecSetRandom(pcis->vec2_N,NULL);CHKERRQ(ierr);
2408     for (i=0;i<nz;i++) vals[i] = 0.;
2409     ierr = VecSetValues(pcis->vec2_N,nz,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
2410     ierr = ISRestoreIndices(zerodiag,&idxs);CHKERRQ(ierr);
2411     ierr = ISGetIndices(pcis->is_B_local,&idxs);CHKERRQ(ierr);
2412     for (i=0;i<pcis->n_B;i++) vals[i] = 0.;
2413     ierr = VecSetValues(pcis->vec2_N,pcis->n_B,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
2414     ierr = ISRestoreIndices(pcis->is_B_local,&idxs);CHKERRQ(ierr);
2415     if (dirIS) {
2416       PetscInt n;
2417 
2418       ierr = ISGetLocalSize(dirIS,&n);CHKERRQ(ierr);
2419       ierr = ISGetIndices(dirIS,&idxs);CHKERRQ(ierr);
2420       for (i=0;i<n;i++) vals[i] = 0.;
2421       ierr = VecSetValues(pcis->vec2_N,n,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
2422       ierr = ISRestoreIndices(dirIS,&idxs);CHKERRQ(ierr);
2423     }
2424     ierr = VecAssemblyBegin(pcis->vec2_N);CHKERRQ(ierr);
2425     ierr = VecAssemblyEnd(pcis->vec2_N);CHKERRQ(ierr);
2426     ierr = VecDuplicate(pcis->vec1_N,&vec3_N);CHKERRQ(ierr);
2427     ierr = VecSet(vec3_N,0.);CHKERRQ(ierr);
2428     ierr = MatISGetLocalMat(pc->pmat,&A);CHKERRQ(ierr);
2429     ierr = MatMult(A,pcis->vec1_N,vec3_N);CHKERRQ(ierr);
2430     ierr = VecDot(vec3_N,pcis->vec2_N,&vals[0]);CHKERRQ(ierr);
2431     if (PetscAbsScalar(vals[0]) > 1.e-1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Benign trick can not be applied! b(v_I,p_0) = %1.6e (should be numerically 0.)",PetscAbsScalar(vals[0]));
2432     ierr = PetscFree(vals);CHKERRQ(ierr);
2433     ierr = VecDestroy(&vec3_N);CHKERRQ(ierr);
2434 
2435     /* there should not be any pressure dofs lying on the interface */
2436     ierr = PetscCalloc1(pcis->n,&count);CHKERRQ(ierr);
2437     ierr = ISGetIndices(pcis->is_B_local,&idxs);CHKERRQ(ierr);
2438     for (i=0;i<pcis->n_B;i++) count[idxs[i]]++;
2439     ierr = ISRestoreIndices(pcis->is_B_local,&idxs);CHKERRQ(ierr);
2440     ierr = ISGetIndices(zerodiag,&idxs);CHKERRQ(ierr);
2441     for (i=0;i<nz;i++) if (count[idxs[i]]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Benign trick can not be applied! pressure dof %d is an interface dof",idxs[i]);
2442     ierr = ISRestoreIndices(zerodiag,&idxs);CHKERRQ(ierr);
2443     ierr = PetscFree(count);CHKERRQ(ierr);
2444   }
2445   ierr = ISDestroy(&dirIS);CHKERRQ(ierr);
2446 
2447   /* check PCBDDCBenignGetOrSetP0 */
2448   ierr = VecSetRandom(pcis->vec1_global,NULL);CHKERRQ(ierr);
2449   for (i=0;i<pcbddc->benign_n;i++) pcbddc->benign_p0[i] = -PetscGlobalRank-i;
2450   ierr = PCBDDCBenignGetOrSetP0(pc,pcis->vec1_global,PETSC_FALSE);CHKERRQ(ierr);
2451   for (i=0;i<pcbddc->benign_n;i++) pcbddc->benign_p0[i] = 1;
2452   ierr = PCBDDCBenignGetOrSetP0(pc,pcis->vec1_global,PETSC_TRUE);CHKERRQ(ierr);
2453   for (i=0;i<pcbddc->benign_n;i++) {
2454     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
2455     if (val != -PetscGlobalRank-i) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error testing PCBDDCBenignGetOrSetP0! Found %g at %d instead of %g\n",PetscRealPart(pcbddc->benign_p0[i]),i,-PetscGlobalRank-i);
2456   }
2457   PetscFunctionReturn(0);
2458 }
2459 
2460 PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, IS *zerodiaglocal)
2461 {
2462   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
2463   IS             pressures,zerodiag,zerodiag_save,*zerodiag_subs;
2464   PetscInt       nz,n;
2465   PetscInt       *interior_dofs,n_interior_dofs,nneu;
2466   PetscBool      sorted,have_null,has_null_pressures,recompute_zerodiag,checkb;
2467   PetscErrorCode ierr;
2468 
2469   PetscFunctionBegin;
2470   ierr = PetscSFDestroy(&pcbddc->benign_sf);CHKERRQ(ierr);
2471   ierr = MatDestroy(&pcbddc->benign_B0);CHKERRQ(ierr);
2472   for (n=0;n<pcbddc->benign_n;n++) {
2473     ierr = ISDestroy(&pcbddc->benign_zerodiag_subs[n]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(pcbddc->benign_zerodiag_subs);CHKERRQ(ierr);
2476   pcbddc->benign_n = 0;
2477 
2478   /* if a local info on dofs is present, uses the last field for "pressures" (or fid by command line)
2479      otherwise, it uses only zerodiagonal dofs (ok if the pressure block is all zero; it could fail if it is not)
2480      Checks if all the pressure dofs in each subdomain have a zero diagonal
2481      If not, a change of basis on pressures is not needed
2482      since the local Schur complements are already SPD
2483   */
2484   has_null_pressures = PETSC_TRUE;
2485   have_null = PETSC_TRUE;
2486   if (pcbddc->n_ISForDofsLocal) {
2487     IS       iP = NULL;
2488     PetscInt npl,*idxs,p = pcbddc->n_ISForDofsLocal-1;
2489 
2490     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)pc),((PetscObject)pc)->prefix,"BDDC benign options","PC");CHKERRQ(ierr);
2491     ierr = PetscOptionsInt("-pc_bddc_pressure_field","Field id for pressures",NULL,p,&p,NULL);CHKERRQ(ierr);
2492     ierr = PetscOptionsEnd();CHKERRQ(ierr);
2493     if (p < 0 || p > pcbddc->n_ISForDofsLocal-1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"Invalid field id for pressures %D",p);
2494     /* Dofs splitting for BDDC cannot have PETSC_COMM_SELF, so create a sequential IS */
2495     ierr = ISGetLocalSize(pcbddc->ISForDofsLocal[p],&npl);CHKERRQ(ierr);
2496     ierr = ISGetIndices(pcbddc->ISForDofsLocal[p],(const PetscInt**)&idxs);CHKERRQ(ierr);
2497     ierr = ISCreateGeneral(PETSC_COMM_SELF,npl,idxs,PETSC_COPY_VALUES,&pressures);CHKERRQ(ierr);
2498     ierr = ISRestoreIndices(pcbddc->ISForDofsLocal[p],(const PetscInt**)&idxs);CHKERRQ(ierr);
2499     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
2500     ierr = PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_lP",(PetscObject*)&iP);CHKERRQ(ierr);
2501     if (iP) {
2502       IS newpressures;
2503 
2504       ierr = ISDifference(pressures,iP,&newpressures);CHKERRQ(ierr);
2505       ierr = ISDestroy(&pressures);CHKERRQ(ierr);
2506       pressures = newpressures;
2507     }
2508     ierr = ISSorted(pressures,&sorted);CHKERRQ(ierr);
2509     if (!sorted) {
2510       ierr = ISSort(pressures);CHKERRQ(ierr);
2511     }
2512   } else {
2513     pressures = NULL;
2514   }
2515   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
2516   ierr = MatGetLocalSize(pcbddc->local_mat,&n,NULL);CHKERRQ(ierr);
2517   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
2518   ierr = MatFindZeroDiagonals(pcbddc->local_mat,&zerodiag);CHKERRQ(ierr);
2519   ierr = ISSorted(zerodiag,&sorted);CHKERRQ(ierr);
2520   if (!sorted) {
2521     ierr = ISSort(zerodiag);CHKERRQ(ierr);
2522   }
2523   ierr = PetscObjectReference((PetscObject)zerodiag);CHKERRQ(ierr);
2524   zerodiag_save = zerodiag;
2525   ierr = ISGetLocalSize(zerodiag,&nz);CHKERRQ(ierr);
2526   if (!nz) {
2527     if (n) have_null = PETSC_FALSE;
2528     has_null_pressures = PETSC_FALSE;
2529     ierr = ISDestroy(&zerodiag);CHKERRQ(ierr);
2530   }
2531   recompute_zerodiag = PETSC_FALSE;
2532   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
2533   zerodiag_subs    = NULL;
2534   pcbddc->benign_n = 0;
2535   n_interior_dofs  = 0;
2536   interior_dofs    = NULL;
2537   nneu             = 0;
2538   if (pcbddc->NeumannBoundariesLocal) {
2539     ierr = ISGetLocalSize(pcbddc->NeumannBoundariesLocal,&nneu);CHKERRQ(ierr);
2540   }
2541   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
2542   if (checkb) { /* need to compute interior nodes */
2543     PetscInt n,i,j;
2544     PetscInt n_neigh,*neigh,*n_shared,**shared;
2545     PetscInt *iwork;
2546 
2547     ierr = ISLocalToGlobalMappingGetSize(pc->pmat->rmap->mapping,&n);CHKERRQ(ierr);
2548     ierr = ISLocalToGlobalMappingGetInfo(pc->pmat->rmap->mapping,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
2549     ierr = PetscCalloc1(n,&iwork);CHKERRQ(ierr);
2550     ierr = PetscMalloc1(n,&interior_dofs);CHKERRQ(ierr);
2551     for (i=1;i<n_neigh;i++)
2552       for (j=0;j<n_shared[i];j++)
2553           iwork[shared[i][j]] += 1;
2554     for (i=0;i<n;i++)
2555       if (!iwork[i])
2556         interior_dofs[n_interior_dofs++] = i;
2557     ierr = PetscFree(iwork);CHKERRQ(ierr);
2558     ierr = ISLocalToGlobalMappingRestoreInfo(pc->pmat->rmap->mapping,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
2559   }
2560   if (has_null_pressures) {
2561     IS             *subs;
2562     PetscInt       nsubs,i,j,nl;
2563     const PetscInt *idxs;
2564     PetscScalar    *array;
2565     Vec            *work;
2566     Mat_IS*        matis = (Mat_IS*)(pc->pmat->data);
2567 
2568     subs  = pcbddc->local_subs;
2569     nsubs = pcbddc->n_local_subs;
2570     /* these vectors are needed to check if the constant on pressures is in the kernel of the local operator B (i.e. B(v_I,p0) should be zero) */
2571     if (checkb) {
2572       ierr = VecDuplicateVecs(matis->y,2,&work);CHKERRQ(ierr);
2573       ierr = ISGetLocalSize(zerodiag,&nl);CHKERRQ(ierr);
2574       ierr = ISGetIndices(zerodiag,&idxs);CHKERRQ(ierr);
2575       /* work[0] = 1_p */
2576       ierr = VecSet(work[0],0.);CHKERRQ(ierr);
2577       ierr = VecGetArray(work[0],&array);CHKERRQ(ierr);
2578       for (j=0;j<nl;j++) array[idxs[j]] = 1.;
2579       ierr = VecRestoreArray(work[0],&array);CHKERRQ(ierr);
2580       /* work[0] = 1_v */
2581       ierr = VecSet(work[1],1.);CHKERRQ(ierr);
2582       ierr = VecGetArray(work[1],&array);CHKERRQ(ierr);
2583       for (j=0;j<nl;j++) array[idxs[j]] = 0.;
2584       ierr = VecRestoreArray(work[1],&array);CHKERRQ(ierr);
2585       ierr = ISRestoreIndices(zerodiag,&idxs);CHKERRQ(ierr);
2586     }
2587     if (nsubs > 1) {
2588       ierr = PetscCalloc1(nsubs,&zerodiag_subs);CHKERRQ(ierr);
2589       for (i=0;i<nsubs;i++) {
2590         ISLocalToGlobalMapping l2g;
2591         IS                     t_zerodiag_subs;
2592         PetscInt               nl;
2593 
2594         ierr = ISLocalToGlobalMappingCreateIS(subs[i],&l2g);CHKERRQ(ierr);
2595         ierr = ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_DROP,zerodiag,&t_zerodiag_subs);CHKERRQ(ierr);
2596         ierr = ISGetLocalSize(t_zerodiag_subs,&nl);CHKERRQ(ierr);
2597         if (nl) {
2598           PetscBool valid = PETSC_TRUE;
2599 
2600           if (checkb) {
2601             ierr = VecSet(matis->x,0);CHKERRQ(ierr);
2602             ierr = ISGetLocalSize(subs[i],&nl);CHKERRQ(ierr);
2603             ierr = ISGetIndices(subs[i],&idxs);CHKERRQ(ierr);
2604             ierr = VecGetArray(matis->x,&array);CHKERRQ(ierr);
2605             for (j=0;j<nl;j++) array[idxs[j]] = 1.;
2606             ierr = VecRestoreArray(matis->x,&array);CHKERRQ(ierr);
2607             ierr = ISRestoreIndices(subs[i],&idxs);CHKERRQ(ierr);
2608             ierr = VecPointwiseMult(matis->x,work[0],matis->x);CHKERRQ(ierr);
2609             ierr = MatMult(matis->A,matis->x,matis->y);CHKERRQ(ierr);
2610             ierr = VecPointwiseMult(matis->y,work[1],matis->y);CHKERRQ(ierr);
2611             ierr = VecGetArray(matis->y,&array);CHKERRQ(ierr);
2612             for (j=0;j<n_interior_dofs;j++) {
2613               if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
2614                 valid = PETSC_FALSE;
2615                 break;
2616               }
2617             }
2618             ierr = VecRestoreArray(matis->y,&array);CHKERRQ(ierr);
2619           }
2620           if (valid && nneu) {
2621             const PetscInt *idxs;
2622             PetscInt       nzb;
2623 
2624             ierr = ISGetIndices(pcbddc->NeumannBoundariesLocal,&idxs);CHKERRQ(ierr);
2625             ierr = ISGlobalToLocalMappingApply(l2g,IS_GTOLM_DROP,nneu,idxs,&nzb,NULL);CHKERRQ(ierr);
2626             ierr = ISRestoreIndices(pcbddc->NeumannBoundariesLocal,&idxs);CHKERRQ(ierr);
2627             if (nzb) valid = PETSC_FALSE;
2628           }
2629           if (valid && pressures) {
2630             IS t_pressure_subs;
2631             ierr = ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_DROP,pressures,&t_pressure_subs);CHKERRQ(ierr);
2632             ierr = ISEqual(t_pressure_subs,t_zerodiag_subs,&valid);CHKERRQ(ierr);
2633             ierr = ISDestroy(&t_pressure_subs);CHKERRQ(ierr);
2634           }
2635           if (valid) {
2636             ierr = ISLocalToGlobalMappingApplyIS(l2g,t_zerodiag_subs,&zerodiag_subs[pcbddc->benign_n]);CHKERRQ(ierr);
2637             pcbddc->benign_n++;
2638           } else {
2639             recompute_zerodiag = PETSC_TRUE;
2640           }
2641         }
2642         ierr = ISDestroy(&t_zerodiag_subs);CHKERRQ(ierr);
2643         ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
2644       }
2645     } else { /* there's just one subdomain (or zero if they have not been detected */
2646       PetscBool valid = PETSC_TRUE;
2647 
2648       if (nneu) valid = PETSC_FALSE;
2649       if (valid && pressures) {
2650         ierr = ISEqual(pressures,zerodiag,&valid);CHKERRQ(ierr);
2651       }
2652       if (valid && checkb) {
2653         ierr = MatMult(matis->A,work[0],matis->x);CHKERRQ(ierr);
2654         ierr = VecPointwiseMult(matis->x,work[1],matis->x);CHKERRQ(ierr);
2655         ierr = VecGetArray(matis->x,&array);CHKERRQ(ierr);
2656         for (j=0;j<n_interior_dofs;j++) {
2657           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
2658             valid = PETSC_FALSE;
2659             break;
2660           }
2661         }
2662         ierr = VecRestoreArray(matis->x,&array);CHKERRQ(ierr);
2663       }
2664       if (valid) {
2665         pcbddc->benign_n = 1;
2666         ierr = PetscMalloc1(pcbddc->benign_n,&zerodiag_subs);CHKERRQ(ierr);
2667         ierr = PetscObjectReference((PetscObject)zerodiag);CHKERRQ(ierr);
2668         zerodiag_subs[0] = zerodiag;
2669       }
2670     }
2671     if (checkb) {
2672       ierr = VecDestroyVecs(2,&work);CHKERRQ(ierr);
2673     }
2674   }
2675   ierr = PetscFree(interior_dofs);CHKERRQ(ierr);
2676 
2677   if (!pcbddc->benign_n) {
2678     PetscInt n;
2679 
2680     ierr = ISDestroy(&zerodiag);CHKERRQ(ierr);
2681     recompute_zerodiag = PETSC_FALSE;
2682     ierr = MatGetLocalSize(pcbddc->local_mat,&n,NULL);CHKERRQ(ierr);
2683     if (n) {
2684       has_null_pressures = PETSC_FALSE;
2685       have_null = PETSC_FALSE;
2686     }
2687   }
2688 
2689   /* final check for null pressures */
2690   if (zerodiag && pressures) {
2691     PetscInt nz,np;
2692     ierr = ISGetLocalSize(zerodiag,&nz);CHKERRQ(ierr);
2693     ierr = ISGetLocalSize(pressures,&np);CHKERRQ(ierr);
2694     if (nz != np) have_null = PETSC_FALSE;
2695   }
2696 
2697   if (recompute_zerodiag) {
2698     ierr = ISDestroy(&zerodiag);CHKERRQ(ierr);
2699     if (pcbddc->benign_n == 1) {
2700       ierr = PetscObjectReference((PetscObject)zerodiag_subs[0]);CHKERRQ(ierr);
2701       zerodiag = zerodiag_subs[0];
2702     } else {
2703       PetscInt i,nzn,*new_idxs;
2704 
2705       nzn = 0;
2706       for (i=0;i<pcbddc->benign_n;i++) {
2707         PetscInt ns;
2708         ierr = ISGetLocalSize(zerodiag_subs[i],&ns);CHKERRQ(ierr);
2709         nzn += ns;
2710       }
2711       ierr = PetscMalloc1(nzn,&new_idxs);CHKERRQ(ierr);
2712       nzn = 0;
2713       for (i=0;i<pcbddc->benign_n;i++) {
2714         PetscInt ns,*idxs;
2715         ierr = ISGetLocalSize(zerodiag_subs[i],&ns);CHKERRQ(ierr);
2716         ierr = ISGetIndices(zerodiag_subs[i],(const PetscInt**)&idxs);CHKERRQ(ierr);
2717         ierr = PetscMemcpy(new_idxs+nzn,idxs,ns*sizeof(PetscInt));CHKERRQ(ierr);
2718         ierr = ISRestoreIndices(zerodiag_subs[i],(const PetscInt**)&idxs);CHKERRQ(ierr);
2719         nzn += ns;
2720       }
2721       ierr = PetscSortInt(nzn,new_idxs);CHKERRQ(ierr);
2722       ierr = ISCreateGeneral(PETSC_COMM_SELF,nzn,new_idxs,PETSC_OWN_POINTER,&zerodiag);CHKERRQ(ierr);
2723     }
2724     have_null = PETSC_FALSE;
2725   }
2726 
2727   /* Prepare matrix to compute no-net-flux */
2728   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2729     Mat                    A,loc_divudotp;
2730     ISLocalToGlobalMapping rl2g,cl2g,l2gmap;
2731     IS                     row,col,isused = NULL;
2732     PetscInt               M,N,n,st,n_isused;
2733 
2734     if (pressures) {
2735       isused = pressures;
2736     } else {
2737       isused = zerodiag_save;
2738     }
2739     ierr = MatGetLocalToGlobalMapping(pc->pmat,&l2gmap,NULL);CHKERRQ(ierr);
2740     ierr = MatISGetLocalMat(pc->pmat,&A);CHKERRQ(ierr);
2741     ierr = MatGetLocalSize(A,&n,NULL);CHKERRQ(ierr);
2742     if (!isused && n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Don't know how to extract div u dot p! Please provide the pressure field");
2743     n_isused = 0;
2744     if (isused) {
2745       ierr = ISGetLocalSize(isused,&n_isused);CHKERRQ(ierr);
2746     }
2747     ierr = MPI_Scan(&n_isused,&st,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
2748     st = st-n_isused;
2749     if (n) {
2750       const PetscInt *gidxs;
2751 
2752       ierr = MatCreateSubMatrix(A,isused,NULL,MAT_INITIAL_MATRIX,&loc_divudotp);CHKERRQ(ierr);
2753       ierr = ISLocalToGlobalMappingGetIndices(l2gmap,&gidxs);CHKERRQ(ierr);
2754       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
2755       ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),n_isused,st,1,&row);CHKERRQ(ierr);
2756       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),n,gidxs,PETSC_COPY_VALUES,&col);CHKERRQ(ierr);
2757       ierr = ISLocalToGlobalMappingRestoreIndices(l2gmap,&gidxs);CHKERRQ(ierr);
2758     } else {
2759       ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,0,0,1,NULL,&loc_divudotp);CHKERRQ(ierr);
2760       ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),n_isused,st,1,&row);CHKERRQ(ierr);
2761       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),0,NULL,PETSC_COPY_VALUES,&col);CHKERRQ(ierr);
2762     }
2763     ierr = MatGetSize(pc->pmat,NULL,&N);CHKERRQ(ierr);
2764     ierr = ISGetSize(row,&M);CHKERRQ(ierr);
2765     ierr = ISLocalToGlobalMappingCreateIS(row,&rl2g);CHKERRQ(ierr);
2766     ierr = ISLocalToGlobalMappingCreateIS(col,&cl2g);CHKERRQ(ierr);
2767     ierr = ISDestroy(&row);CHKERRQ(ierr);
2768     ierr = ISDestroy(&col);CHKERRQ(ierr);
2769     ierr = MatCreate(PetscObjectComm((PetscObject)pc),&pcbddc->divudotp);CHKERRQ(ierr);
2770     ierr = MatSetType(pcbddc->divudotp,MATIS);CHKERRQ(ierr);
2771     ierr = MatSetSizes(pcbddc->divudotp,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
2772     ierr = MatSetLocalToGlobalMapping(pcbddc->divudotp,rl2g,cl2g);CHKERRQ(ierr);
2773     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2774     ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2775     ierr = MatISSetLocalMat(pcbddc->divudotp,loc_divudotp);CHKERRQ(ierr);
2776     ierr = MatDestroy(&loc_divudotp);CHKERRQ(ierr);
2777     ierr = MatAssemblyBegin(pcbddc->divudotp,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2778     ierr = MatAssemblyEnd(pcbddc->divudotp,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2779   }
2780   ierr = ISDestroy(&zerodiag_save);CHKERRQ(ierr);
2781 
2782   /* change of basis and p0 dofs */
2783   if (has_null_pressures) {
2784     IS             zerodiagc;
2785     const PetscInt *idxs,*idxsc;
2786     PetscInt       i,s,*nnz;
2787 
2788     ierr = ISGetLocalSize(zerodiag,&nz);CHKERRQ(ierr);
2789     ierr = ISComplement(zerodiag,0,n,&zerodiagc);CHKERRQ(ierr);
2790     ierr = ISGetIndices(zerodiagc,&idxsc);CHKERRQ(ierr);
2791     /* local change of basis for pressures */
2792     ierr = MatDestroy(&pcbddc->benign_change);CHKERRQ(ierr);
2793     ierr = MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat),&pcbddc->benign_change);CHKERRQ(ierr);
2794     ierr = MatSetType(pcbddc->benign_change,MATAIJ);CHKERRQ(ierr);
2795     ierr = MatSetSizes(pcbddc->benign_change,n,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
2796     ierr = PetscMalloc1(n,&nnz);CHKERRQ(ierr);
2797     for (i=0;i<n-nz;i++) nnz[idxsc[i]] = 1; /* identity on velocities plus pressure dofs for non-singular subdomains */
2798     for (i=0;i<pcbddc->benign_n;i++) {
2799       PetscInt nzs,j;
2800 
2801       ierr = ISGetLocalSize(zerodiag_subs[i],&nzs);CHKERRQ(ierr);
2802       ierr = ISGetIndices(zerodiag_subs[i],&idxs);CHKERRQ(ierr);
2803       for (j=0;j<nzs-1;j++) nnz[idxs[j]] = 2; /* change on pressures */
2804       nnz[idxs[nzs-1]] = nzs; /* last local pressure dof in subdomain */
2805       ierr = ISRestoreIndices(zerodiag_subs[i],&idxs);CHKERRQ(ierr);
2806     }
2807     ierr = MatSeqAIJSetPreallocation(pcbddc->benign_change,0,nnz);CHKERRQ(ierr);
2808     ierr = PetscFree(nnz);CHKERRQ(ierr);
2809     /* set identity on velocities */
2810     for (i=0;i<n-nz;i++) {
2811       ierr = MatSetValue(pcbddc->benign_change,idxsc[i],idxsc[i],1.,INSERT_VALUES);CHKERRQ(ierr);
2812     }
2813     ierr = ISRestoreIndices(zerodiagc,&idxsc);CHKERRQ(ierr);
2814     ierr = ISDestroy(&zerodiagc);CHKERRQ(ierr);
2815     ierr = PetscFree3(pcbddc->benign_p0_lidx,pcbddc->benign_p0_gidx,pcbddc->benign_p0);CHKERRQ(ierr);
2816     ierr = PetscMalloc3(pcbddc->benign_n,&pcbddc->benign_p0_lidx,pcbddc->benign_n,&pcbddc->benign_p0_gidx,pcbddc->benign_n,&pcbddc->benign_p0);CHKERRQ(ierr);
2817     /* set change on pressures */
2818     for (s=0;s<pcbddc->benign_n;s++) {
2819       PetscScalar *array;
2820       PetscInt    nzs;
2821 
2822       ierr = ISGetLocalSize(zerodiag_subs[s],&nzs);CHKERRQ(ierr);
2823       ierr = ISGetIndices(zerodiag_subs[s],&idxs);CHKERRQ(ierr);
2824       for (i=0;i<nzs-1;i++) {
2825         PetscScalar vals[2];
2826         PetscInt    cols[2];
2827 
2828         cols[0] = idxs[i];
2829         cols[1] = idxs[nzs-1];
2830         vals[0] = 1.;
2831         vals[1] = 1.;
2832         ierr = MatSetValues(pcbddc->benign_change,1,cols,2,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
2833       }
2834       ierr = PetscMalloc1(nzs,&array);CHKERRQ(ierr);
2835       for (i=0;i<nzs-1;i++) array[i] = -1.;
2836       array[nzs-1] = 1.;
2837       ierr = MatSetValues(pcbddc->benign_change,1,idxs+nzs-1,nzs,idxs,array,INSERT_VALUES);CHKERRQ(ierr);
2838       /* store local idxs for p0 */
2839       pcbddc->benign_p0_lidx[s] = idxs[nzs-1];
2840       ierr = ISRestoreIndices(zerodiag_subs[s],&idxs);CHKERRQ(ierr);
2841       ierr = PetscFree(array);CHKERRQ(ierr);
2842     }
2843     ierr = MatAssemblyBegin(pcbddc->benign_change,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2844     ierr = MatAssemblyEnd(pcbddc->benign_change,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2845     /* project if needed */
2846     if (pcbddc->benign_change_explicit) {
2847       Mat M;
2848 
2849       ierr = MatPtAP(pcbddc->local_mat,pcbddc->benign_change,MAT_INITIAL_MATRIX,2.0,&M);CHKERRQ(ierr);
2850       ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
2851       ierr = MatSeqAIJCompress(M,&pcbddc->local_mat);CHKERRQ(ierr);
2852       ierr = MatDestroy(&M);CHKERRQ(ierr);
2853     }
2854     /* store global idxs for p0 */
2855     ierr = ISLocalToGlobalMappingApply(pc->pmat->rmap->mapping,pcbddc->benign_n,pcbddc->benign_p0_lidx,pcbddc->benign_p0_gidx);CHKERRQ(ierr);
2856   }
2857   pcbddc->benign_zerodiag_subs = zerodiag_subs;
2858   ierr = ISDestroy(&pressures);CHKERRQ(ierr);
2859 
2860   /* determines if the coarse solver will be singular or not */
2861   ierr = MPI_Allreduce(&have_null,&pcbddc->benign_null,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
2862   /* determines if the problem has subdomains with 0 pressure block */
2863   have_null = (PetscBool)(!!pcbddc->benign_n);
2864   ierr = MPI_Allreduce(&have_null,&pcbddc->benign_have_null,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
2865   *zerodiaglocal = zerodiag;
2866   PetscFunctionReturn(0);
2867 }
2868 
2869 PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
2870 {
2871   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
2872   PetscScalar    *array;
2873   PetscErrorCode ierr;
2874 
2875   PetscFunctionBegin;
2876   if (!pcbddc->benign_sf) {
2877     ierr = PetscSFCreate(PetscObjectComm((PetscObject)pc),&pcbddc->benign_sf);CHKERRQ(ierr);
2878     ierr = PetscSFSetGraphLayout(pcbddc->benign_sf,pc->pmat->rmap,pcbddc->benign_n,NULL,PETSC_OWN_POINTER,pcbddc->benign_p0_gidx);CHKERRQ(ierr);
2879   }
2880   if (get) {
2881     ierr = VecGetArrayRead(v,(const PetscScalar**)&array);CHKERRQ(ierr);
2882     ierr = PetscSFBcastBegin(pcbddc->benign_sf,MPIU_SCALAR,array,pcbddc->benign_p0);CHKERRQ(ierr);
2883     ierr = PetscSFBcastEnd(pcbddc->benign_sf,MPIU_SCALAR,array,pcbddc->benign_p0);CHKERRQ(ierr);
2884     ierr = VecRestoreArrayRead(v,(const PetscScalar**)&array);CHKERRQ(ierr);
2885   } else {
2886     ierr = VecGetArray(v,&array);CHKERRQ(ierr);
2887     ierr = PetscSFReduceBegin(pcbddc->benign_sf,MPIU_SCALAR,pcbddc->benign_p0,array,MPIU_REPLACE);CHKERRQ(ierr);
2888     ierr = PetscSFReduceEnd(pcbddc->benign_sf,MPIU_SCALAR,pcbddc->benign_p0,array,MPIU_REPLACE);CHKERRQ(ierr);
2889     ierr = VecRestoreArray(v,&array);CHKERRQ(ierr);
2890   }
2891   PetscFunctionReturn(0);
2892 }
2893 
2894 PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
2895 {
2896   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
2897   PetscErrorCode ierr;
2898 
2899   PetscFunctionBegin;
2900   /* TODO: add error checking
2901     - avoid nested pop (or push) calls.
2902     - cannot push before pop.
2903     - cannot call this if pcbddc->local_mat is NULL
2904   */
2905   if (!pcbddc->benign_n) {
2906     PetscFunctionReturn(0);
2907   }
2908   if (pop) {
2909     if (pcbddc->benign_change_explicit) {
2910       IS       is_p0;
2911       MatReuse reuse;
2912 
2913       /* extract B_0 */
2914       reuse = MAT_INITIAL_MATRIX;
2915       if (pcbddc->benign_B0) {
2916         reuse = MAT_REUSE_MATRIX;
2917       }
2918       ierr = ISCreateGeneral(PETSC_COMM_SELF,pcbddc->benign_n,pcbddc->benign_p0_lidx,PETSC_COPY_VALUES,&is_p0);CHKERRQ(ierr);
2919       ierr = MatCreateSubMatrix(pcbddc->local_mat,is_p0,NULL,reuse,&pcbddc->benign_B0);CHKERRQ(ierr);
2920       /* remove rows and cols from local problem */
2921       ierr = MatSetOption(pcbddc->local_mat,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE);CHKERRQ(ierr);
2922       ierr = MatSetOption(pcbddc->local_mat,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
2923       ierr = MatZeroRowsColumnsIS(pcbddc->local_mat,is_p0,1.0,NULL,NULL);CHKERRQ(ierr);
2924       ierr = ISDestroy(&is_p0);CHKERRQ(ierr);
2925     } else {
2926       Mat_IS      *matis = (Mat_IS*)pc->pmat->data;
2927       PetscScalar *vals;
2928       PetscInt    i,n,*idxs_ins;
2929 
2930       ierr = VecGetLocalSize(matis->y,&n);CHKERRQ(ierr);
2931       ierr = PetscMalloc2(n,&idxs_ins,n,&vals);CHKERRQ(ierr);
2932       if (!pcbddc->benign_B0) {
2933         PetscInt *nnz;
2934         ierr = MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat),&pcbddc->benign_B0);CHKERRQ(ierr);
2935         ierr = MatSetType(pcbddc->benign_B0,MATAIJ);CHKERRQ(ierr);
2936         ierr = MatSetSizes(pcbddc->benign_B0,pcbddc->benign_n,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
2937         ierr = PetscMalloc1(pcbddc->benign_n,&nnz);CHKERRQ(ierr);
2938         for (i=0;i<pcbddc->benign_n;i++) {
2939           ierr = ISGetLocalSize(pcbddc->benign_zerodiag_subs[i],&nnz[i]);CHKERRQ(ierr);
2940           nnz[i] = n - nnz[i];
2941         }
2942         ierr = MatSeqAIJSetPreallocation(pcbddc->benign_B0,0,nnz);CHKERRQ(ierr);
2943         ierr = PetscFree(nnz);CHKERRQ(ierr);
2944       }
2945 
2946       for (i=0;i<pcbddc->benign_n;i++) {
2947         PetscScalar *array;
2948         PetscInt    *idxs,j,nz,cum;
2949 
2950         ierr = VecSet(matis->x,0.);CHKERRQ(ierr);
2951         ierr = ISGetLocalSize(pcbddc->benign_zerodiag_subs[i],&nz);CHKERRQ(ierr);
2952         ierr = ISGetIndices(pcbddc->benign_zerodiag_subs[i],(const PetscInt**)&idxs);CHKERRQ(ierr);
2953         for (j=0;j<nz;j++) vals[j] = 1.;
2954         ierr = VecSetValues(matis->x,nz,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
2955         ierr = VecAssemblyBegin(matis->x);CHKERRQ(ierr);
2956         ierr = VecAssemblyEnd(matis->x);CHKERRQ(ierr);
2957         ierr = VecSet(matis->y,0.);CHKERRQ(ierr);
2958         ierr = MatMult(matis->A,matis->x,matis->y);CHKERRQ(ierr);
2959         ierr = VecGetArray(matis->y,&array);CHKERRQ(ierr);
2960         cum = 0;
2961         for (j=0;j<n;j++) {
2962           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
2963             vals[cum] = array[j];
2964             idxs_ins[cum] = j;
2965             cum++;
2966           }
2967         }
2968         ierr = MatSetValues(pcbddc->benign_B0,1,&i,cum,idxs_ins,vals,INSERT_VALUES);CHKERRQ(ierr);
2969         ierr = VecRestoreArray(matis->y,&array);CHKERRQ(ierr);
2970         ierr = ISRestoreIndices(pcbddc->benign_zerodiag_subs[i],(const PetscInt**)&idxs);CHKERRQ(ierr);
2971       }
2972       ierr = MatAssemblyBegin(pcbddc->benign_B0,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2973       ierr = MatAssemblyEnd(pcbddc->benign_B0,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2974       ierr = PetscFree2(idxs_ins,vals);CHKERRQ(ierr);
2975     }
2976   } else { /* push */
2977     if (pcbddc->benign_change_explicit) {
2978       PetscInt i;
2979 
2980       for (i=0;i<pcbddc->benign_n;i++) {
2981         PetscScalar *B0_vals;
2982         PetscInt    *B0_cols,B0_ncol;
2983 
2984         ierr = MatGetRow(pcbddc->benign_B0,i,&B0_ncol,(const PetscInt**)&B0_cols,(const PetscScalar**)&B0_vals);CHKERRQ(ierr);
2985         ierr = MatSetValues(pcbddc->local_mat,1,pcbddc->benign_p0_lidx+i,B0_ncol,B0_cols,B0_vals,INSERT_VALUES);CHKERRQ(ierr);
2986         ierr = MatSetValues(pcbddc->local_mat,B0_ncol,B0_cols,1,pcbddc->benign_p0_lidx+i,B0_vals,INSERT_VALUES);CHKERRQ(ierr);
2987         ierr = MatSetValue(pcbddc->local_mat,pcbddc->benign_p0_lidx[i],pcbddc->benign_p0_lidx[i],0.0,INSERT_VALUES);CHKERRQ(ierr);
2988         ierr = MatRestoreRow(pcbddc->benign_B0,i,&B0_ncol,(const PetscInt**)&B0_cols,(const PetscScalar**)&B0_vals);CHKERRQ(ierr);
2989       }
2990       ierr = MatAssemblyBegin(pcbddc->local_mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2991       ierr = MatAssemblyEnd(pcbddc->local_mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2992     } else {
2993       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cannot push B0!\n");
2994     }
2995   }
2996   PetscFunctionReturn(0);
2997 }
2998 
2999 PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
3000 {
3001   PC_BDDC*        pcbddc = (PC_BDDC*)pc->data;
3002   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
3003   PetscBLASInt    B_dummyint,B_neigs,B_ierr,B_lwork;
3004   PetscBLASInt    *B_iwork,*B_ifail;
3005   PetscScalar     *work,lwork;
3006   PetscScalar     *St,*S,*eigv;
3007   PetscScalar     *Sarray,*Starray;
3008   PetscReal       *eigs,thresh,lthresh,uthresh;
3009   PetscInt        i,nmax,nmin,nv,cum,mss,cum2,cumarray,maxneigs;
3010   PetscBool       allocated_S_St;
3011 #if defined(PETSC_USE_COMPLEX)
3012   PetscReal       *rwork;
3013 #endif
3014   PetscErrorCode  ierr;
3015 
3016   PetscFunctionBegin;
3017   if (!sub_schurs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Adaptive selection of constraints requires SubSchurs data");
3018   if (!sub_schurs->schur_explicit) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Adaptive selection of constraints requires MUMPS and/or MKL_CPARDISO");
3019   if (sub_schurs->n_subs && (!sub_schurs->is_symmetric)) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Adaptive selection not yet implemented for this matrix pencil (herm %d, symm %d, posdef %d)",sub_schurs->is_hermitian,sub_schurs->is_symmetric,sub_schurs->is_posdef);
3020   ierr = PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
3021 
3022   if (pcbddc->dbg_flag) {
3023     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
3024     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
3025     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Check adaptive selection of constraints\n");CHKERRQ(ierr);
3026     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
3027   }
3028 
3029   if (pcbddc->dbg_flag) {
3030     PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d cc %d (%d,%d).\n",PetscGlobalRank,sub_schurs->n_subs,sub_schurs->is_hermitian,sub_schurs->is_posdef);
3031   }
3032 
3033   /* max size of subsets */
3034   mss = 0;
3035   for (i=0;i<sub_schurs->n_subs;i++) {
3036     PetscInt subset_size;
3037 
3038     ierr = ISGetLocalSize(sub_schurs->is_subs[i],&subset_size);CHKERRQ(ierr);
3039     mss = PetscMax(mss,subset_size);
3040   }
3041 
3042   /* min/max and threshold */
3043   nmax = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3044   nmin = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
3045   nmax = PetscMax(nmin,nmax);
3046   allocated_S_St = PETSC_FALSE;
3047   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3048     allocated_S_St = PETSC_TRUE;
3049   }
3050 
3051   /* allocate lapack workspace */
3052   cum = cum2 = 0;
3053   maxneigs = 0;
3054   for (i=0;i<sub_schurs->n_subs;i++) {
3055     PetscInt n,subset_size;
3056 
3057     ierr = ISGetLocalSize(sub_schurs->is_subs[i],&subset_size);CHKERRQ(ierr);
3058     n = PetscMin(subset_size,nmax);
3059     cum += subset_size;
3060     cum2 += subset_size*n;
3061     maxneigs = PetscMax(maxneigs,n);
3062   }
3063   if (mss) {
3064     if (sub_schurs->is_symmetric) {
3065       PetscBLASInt B_itype = 1;
3066       PetscBLASInt B_N = mss;
3067       PetscReal    zero = 0.0;
3068       PetscReal    eps = 0.0; /* dlamch? */
3069 
3070       B_lwork = -1;
3071       S = NULL;
3072       St = NULL;
3073       eigs = NULL;
3074       eigv = NULL;
3075       B_iwork = NULL;
3076       B_ifail = NULL;
3077 #if defined(PETSC_USE_COMPLEX)
3078       rwork = NULL;
3079 #endif
3080       thresh = 1.0;
3081       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
3082 #if defined(PETSC_USE_COMPLEX)
3083       PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&zero,&thresh,&B_dummyint,&B_dummyint,&eps,&B_neigs,eigs,eigv,&B_N,&lwork,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3084 #else
3085       PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&zero,&thresh,&B_dummyint,&B_dummyint,&eps,&B_neigs,eigs,eigv,&B_N,&lwork,&B_lwork,B_iwork,B_ifail,&B_ierr));
3086 #endif
3087       if (B_ierr != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in query to SYGVX Lapack routine %d",(int)B_ierr);
3088       ierr = PetscFPTrapPop();CHKERRQ(ierr);
3089     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not yet implemented");
3090   } else {
3091     lwork = 0;
3092   }
3093 
3094   nv = 0;
3095   if (sub_schurs->is_vertices && pcbddc->use_vertices) { /* complement set of active subsets, each entry is a vertex (boundary made by active subsets, vertices and dirichlet dofs) */
3096     ierr = ISGetLocalSize(sub_schurs->is_vertices,&nv);CHKERRQ(ierr);
3097   }
3098   ierr = PetscBLASIntCast((PetscInt)PetscRealPart(lwork),&B_lwork);CHKERRQ(ierr);
3099   if (allocated_S_St) {
3100     ierr = PetscMalloc2(mss*mss,&S,mss*mss,&St);CHKERRQ(ierr);
3101   }
3102   ierr = PetscMalloc5(mss*mss,&eigv,mss,&eigs,B_lwork,&work,5*mss,&B_iwork,mss,&B_ifail);CHKERRQ(ierr);
3103 #if defined(PETSC_USE_COMPLEX)
3104   ierr = PetscMalloc1(7*mss,&rwork);CHKERRQ(ierr);
3105 #endif
3106   ierr = PetscMalloc5(nv+sub_schurs->n_subs,&pcbddc->adaptive_constraints_n,
3107                       nv+sub_schurs->n_subs+1,&pcbddc->adaptive_constraints_idxs_ptr,
3108                       nv+sub_schurs->n_subs+1,&pcbddc->adaptive_constraints_data_ptr,
3109                       nv+cum,&pcbddc->adaptive_constraints_idxs,
3110                       nv+cum2,&pcbddc->adaptive_constraints_data);CHKERRQ(ierr);
3111   ierr = PetscMemzero(pcbddc->adaptive_constraints_n,(nv+sub_schurs->n_subs)*sizeof(PetscInt));CHKERRQ(ierr);
3112 
3113   maxneigs = 0;
3114   cum = cumarray = 0;
3115   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
3116   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3117   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
3118     const PetscInt *idxs;
3119 
3120     ierr = ISGetIndices(sub_schurs->is_vertices,&idxs);CHKERRQ(ierr);
3121     for (cum=0;cum<nv;cum++) {
3122       pcbddc->adaptive_constraints_n[cum] = 1;
3123       pcbddc->adaptive_constraints_idxs[cum] = idxs[cum];
3124       pcbddc->adaptive_constraints_data[cum] = 1.0;
3125       pcbddc->adaptive_constraints_idxs_ptr[cum+1] = pcbddc->adaptive_constraints_idxs_ptr[cum]+1;
3126       pcbddc->adaptive_constraints_data_ptr[cum+1] = pcbddc->adaptive_constraints_data_ptr[cum]+1;
3127     }
3128     ierr = ISRestoreIndices(sub_schurs->is_vertices,&idxs);CHKERRQ(ierr);
3129   }
3130 
3131   if (mss) { /* multilevel */
3132     ierr = MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all,&Sarray);CHKERRQ(ierr);
3133     ierr = MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all,&Starray);CHKERRQ(ierr);
3134   }
3135 
3136   lthresh = pcbddc->adaptive_threshold[0];
3137   uthresh = pcbddc->adaptive_threshold[1];
3138   for (i=0;i<sub_schurs->n_subs;i++) {
3139     const PetscInt *idxs;
3140     PetscReal      upper,lower;
3141     PetscInt       j,subset_size,eigs_start = 0;
3142     PetscBLASInt   B_N;
3143     PetscBool      same_data = PETSC_FALSE;
3144     PetscBool      scal = PETSC_FALSE;
3145 
3146     if (pcbddc->use_deluxe_scaling) {
3147       upper = PETSC_MAX_REAL;
3148       lower = uthresh;
3149     } else {
3150       if (!sub_schurs->is_posdef) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not yet implemented without deluxe scaling");
3151       upper = 1./uthresh;
3152       lower = 0.;
3153     }
3154     ierr = ISGetLocalSize(sub_schurs->is_subs[i],&subset_size);CHKERRQ(ierr);
3155     ierr = ISGetIndices(sub_schurs->is_subs[i],&idxs);CHKERRQ(ierr);
3156     ierr = PetscBLASIntCast(subset_size,&B_N);CHKERRQ(ierr);
3157     /* this is experimental: we assume the dofs have been properly grouped to have
3158        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3159     if (!sub_schurs->is_posdef) {
3160       Mat T;
3161 
3162       for (j=0;j<subset_size;j++) {
3163         if (PetscRealPart(*(Sarray+cumarray+j*(subset_size+1))) < 0.0) {
3164           ierr = MatCreateSeqDense(PETSC_COMM_SELF,subset_size,subset_size,Sarray+cumarray,&T);CHKERRQ(ierr);
3165           ierr = MatScale(T,-1.0);CHKERRQ(ierr);
3166           ierr = MatDestroy(&T);CHKERRQ(ierr);
3167           ierr = MatCreateSeqDense(PETSC_COMM_SELF,subset_size,subset_size,Starray+cumarray,&T);CHKERRQ(ierr);
3168           ierr = MatScale(T,-1.0);CHKERRQ(ierr);
3169           ierr = MatDestroy(&T);CHKERRQ(ierr);
3170           if (sub_schurs->change_primal_sub) {
3171             PetscInt       nz,k;
3172             const PetscInt *idxs;
3173 
3174             ierr = ISGetLocalSize(sub_schurs->change_primal_sub[i],&nz);CHKERRQ(ierr);
3175             ierr = ISGetIndices(sub_schurs->change_primal_sub[i],&idxs);CHKERRQ(ierr);
3176             for (k=0;k<nz;k++) {
3177               *( Sarray + cumarray + idxs[k]*(subset_size+1)) *= -1.0;
3178               *(Starray + cumarray + idxs[k]*(subset_size+1))  = 0.0;
3179             }
3180             ierr = ISRestoreIndices(sub_schurs->change_primal_sub[i],&idxs);CHKERRQ(ierr);
3181           }
3182           scal = PETSC_TRUE;
3183           break;
3184         }
3185       }
3186     }
3187 
3188     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3189       if (sub_schurs->is_symmetric) {
3190         PetscInt j,k;
3191         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscMemcmp later */
3192           ierr = PetscMemzero(S,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3193           ierr = PetscMemzero(St,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3194         }
3195         for (j=0;j<subset_size;j++) {
3196           for (k=j;k<subset_size;k++) {
3197             S [j*subset_size+k] = Sarray [cumarray+j*subset_size+k];
3198             St[j*subset_size+k] = Starray[cumarray+j*subset_size+k];
3199           }
3200         }
3201       } else {
3202         ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3203         ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3204       }
3205     } else {
3206       S = Sarray + cumarray;
3207       St = Starray + cumarray;
3208     }
3209     /* see if we can save some work */
3210     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) {
3211       ierr = PetscMemcmp(S,St,subset_size*subset_size*sizeof(PetscScalar),&same_data);CHKERRQ(ierr);
3212     }
3213 
3214     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3215       B_neigs = 0;
3216     } else {
3217       if (sub_schurs->is_symmetric) {
3218         PetscBLASInt B_itype = 1;
3219         PetscBLASInt B_IL, B_IU;
3220         PetscReal    eps = -1.0; /* dlamch? */
3221         PetscInt     nmin_s;
3222         PetscBool    compute_range;
3223 
3224         B_neigs = 0;
3225         compute_range = (PetscBool)!same_data;
3226         if (nmin >= subset_size) compute_range = PETSC_FALSE;
3227 
3228         if (pcbddc->dbg_flag) {
3229           PetscInt nc = 0;
3230 
3231           if (sub_schurs->change_primal_sub) {
3232             ierr = ISGetLocalSize(sub_schurs->change_primal_sub[i],&nc);CHKERRQ(ierr);
3233           }
3234           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Computing for sub %d/%d size %d count %d fid %d (range %d) (change %d).\n",i,sub_schurs->n_subs,subset_size,pcbddc->mat_graph->count[idxs[0]]+1,pcbddc->mat_graph->which_dof[idxs[0]],compute_range,nc);CHKERRQ(ierr);
3235         }
3236 
3237         ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
3238         if (compute_range) {
3239 
3240           /* ask for eigenvalues larger than thresh */
3241           if (sub_schurs->is_posdef) {
3242 #if defined(PETSC_USE_COMPLEX)
3243             PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3244 #else
3245             PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3246 #endif
3247             ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3248           } else { /* no theory so far, but it works nicely */
3249             PetscInt  recipe = 0,recipe_m = 1;
3250             PetscReal bb[2];
3251 
3252             ierr = PetscOptionsGetInt(NULL,((PetscObject)pc)->prefix,"-pc_bddc_adaptive_recipe",&recipe,NULL);CHKERRQ(ierr);
3253             switch (recipe) {
3254             case 0:
3255               if (scal) { bb[0] = PETSC_MIN_REAL; bb[1] = lthresh; }
3256               else { bb[0] = uthresh; bb[1] = PETSC_MAX_REAL; }
3257 #if defined(PETSC_USE_COMPLEX)
3258               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3259 #else
3260               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3261 #endif
3262               ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3263               break;
3264             case 1:
3265               bb[0] = PETSC_MIN_REAL; bb[1] = lthresh*lthresh;
3266 #if defined(PETSC_USE_COMPLEX)
3267               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3268 #else
3269               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3270 #endif
3271               ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3272               if (!scal) {
3273                 PetscBLASInt B_neigs2 = 0;
3274 
3275                 bb[0] = PetscMax(lthresh*lthresh,uthresh); bb[1] = PETSC_MAX_REAL;
3276                 ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3277                 ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3278 #if defined(PETSC_USE_COMPLEX)
3279                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3280 #else
3281                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3282 #endif
3283                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3284                 B_neigs += B_neigs2;
3285               }
3286               break;
3287             case 2:
3288               if (scal) {
3289                 bb[0] = PETSC_MIN_REAL;
3290                 bb[1] = 0;
3291 #if defined(PETSC_USE_COMPLEX)
3292                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3293 #else
3294                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3295 #endif
3296                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3297               } else {
3298                 PetscBLASInt B_neigs2 = 0;
3299                 PetscBool    import = PETSC_FALSE;
3300 
3301                 lthresh = PetscMax(lthresh,0.0);
3302                 if (lthresh > 0.0) {
3303                   bb[0] = PETSC_MIN_REAL;
3304                   bb[1] = lthresh*lthresh;
3305 
3306                   import = PETSC_TRUE;
3307 #if defined(PETSC_USE_COMPLEX)
3308                   PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3309 #else
3310                   PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3311 #endif
3312                   ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3313                 }
3314                 bb[0] = PetscMax(lthresh*lthresh,uthresh);
3315                 bb[1] = PETSC_MAX_REAL;
3316                 if (import) {
3317                   ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3318                   ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3319                 }
3320 #if defined(PETSC_USE_COMPLEX)
3321                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3322 #else
3323                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3324 #endif
3325                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3326                 B_neigs += B_neigs2;
3327               }
3328               break;
3329             case 3:
3330               if (scal) {
3331                 ierr = PetscOptionsGetInt(NULL,((PetscObject)pc)->prefix,"-pc_bddc_adaptive_recipe3_min_scal",&recipe_m,NULL);CHKERRQ(ierr);
3332               } else {
3333                 ierr = PetscOptionsGetInt(NULL,((PetscObject)pc)->prefix,"-pc_bddc_adaptive_recipe3_min",&recipe_m,NULL);CHKERRQ(ierr);
3334               }
3335               if (!scal) {
3336                 bb[0] = uthresh;
3337                 bb[1] = PETSC_MAX_REAL;
3338 #if defined(PETSC_USE_COMPLEX)
3339                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3340 #else
3341                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3342 #endif
3343                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3344               }
3345               if (recipe_m > 0 && B_N - B_neigs > 0) {
3346                 PetscBLASInt B_neigs2 = 0;
3347 
3348                 B_IL = 1;
3349                 ierr = PetscBLASIntCast(PetscMin(recipe_m,B_N - B_neigs),&B_IU);CHKERRQ(ierr);
3350                 ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3351                 ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3352 #if defined(PETSC_USE_COMPLEX)
3353                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3354 #else
3355                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3356 #endif
3357                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3358                 B_neigs += B_neigs2;
3359               }
3360               break;
3361             case 4:
3362               bb[0] = PETSC_MIN_REAL; bb[1] = lthresh;
3363 #if defined(PETSC_USE_COMPLEX)
3364               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3365 #else
3366               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3367 #endif
3368               ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3369               {
3370                 PetscBLASInt B_neigs2 = 0;
3371 
3372                 bb[0] = PetscMax(lthresh+PETSC_SMALL,uthresh); bb[1] = PETSC_MAX_REAL;
3373                 ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3374                 ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3375 #if defined(PETSC_USE_COMPLEX)
3376                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3377 #else
3378                 PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","V","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*B_N,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3379 #endif
3380                 ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3381                 B_neigs += B_neigs2;
3382               }
3383               break;
3384             case 5: /* same as before: first compute all eigenvalues, then filter */
3385 #if defined(PETSC_USE_COMPLEX)
3386               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","A","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3387 #else
3388               PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","A","L",&B_N,St,&B_N,S,&B_N,&bb[0],&bb[1],&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3389 #endif
3390               ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3391               {
3392                 PetscInt e,k,ne;
3393                 for (e=0,ne=0;e<B_neigs;e++) {
3394                   if (eigs[e] < lthresh || eigs[e] > uthresh) {
3395                     for (k=0;k<B_N;k++) S[ne*B_N+k] = eigv[e*B_N+k];
3396                     eigs[ne] = eigs[e];
3397                     ne++;
3398                   }
3399                 }
3400                 ierr = PetscMemcpy(eigv,S,B_N*ne*sizeof(PetscScalar));CHKERRQ(ierr);
3401                 B_neigs = ne;
3402               }
3403               break;
3404             default:
3405               SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Unknown recipe %D",recipe);
3406               break;
3407             }
3408           }
3409         } else if (!same_data) { /* this is just to see all the eigenvalues */
3410           B_IU = PetscMax(1,PetscMin(B_N,nmax));
3411           B_IL = 1;
3412 #if defined(PETSC_USE_COMPLEX)
3413           PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3414 #else
3415           PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs,eigs,eigv,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3416 #endif
3417           ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3418         } else { /* same_data is true, so just get the adaptive functional requested by the user */
3419           PetscInt k;
3420           if (!sub_schurs->change_primal_sub) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"This should not happen");
3421           ierr = ISGetLocalSize(sub_schurs->change_primal_sub[i],&nmax);CHKERRQ(ierr);
3422           ierr = PetscBLASIntCast(nmax,&B_neigs);CHKERRQ(ierr);
3423           nmin = nmax;
3424           ierr = PetscMemzero(eigv,subset_size*nmax*sizeof(PetscScalar));CHKERRQ(ierr);
3425           for (k=0;k<nmax;k++) {
3426             eigs[k] = 1./PETSC_SMALL;
3427             eigv[k*(subset_size+1)] = 1.0;
3428           }
3429         }
3430         ierr = PetscFPTrapPop();CHKERRQ(ierr);
3431         if (B_ierr) {
3432           if (B_ierr < 0 ) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: illegal value for argument %d",-(int)B_ierr);
3433           else if (B_ierr <= B_N) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: %d eigenvalues failed to converge",(int)B_ierr);
3434           else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: leading minor of order %d is not positive definite",(int)B_ierr-B_N-1);
3435         }
3436 
3437         if (B_neigs > nmax) {
3438           if (pcbddc->dbg_flag) {
3439             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"   found %d eigs, more than maximum required %d.\n",B_neigs,nmax);CHKERRQ(ierr);
3440           }
3441           if (pcbddc->use_deluxe_scaling) eigs_start = scal ? 0 : B_neigs-nmax;
3442           B_neigs = nmax;
3443         }
3444 
3445         nmin_s = PetscMin(nmin,B_N);
3446         if (B_neigs < nmin_s) {
3447           PetscBLASInt B_neigs2 = 0;
3448 
3449           if (pcbddc->use_deluxe_scaling) {
3450             if (scal) {
3451               B_IU = nmin_s;
3452               B_IL = B_neigs + 1;
3453             } else {
3454               B_IL = B_N - nmin_s + 1;
3455               B_IU = B_N - B_neigs;
3456             }
3457           } else {
3458             B_IL = B_neigs + 1;
3459             B_IU = nmin_s;
3460           }
3461           if (pcbddc->dbg_flag) {
3462             PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"   found %d eigs, less than minimum required %d. Asking for %d to %d incl (fortran like)\n",B_neigs,nmin,B_IL,B_IU);
3463           }
3464           if (sub_schurs->is_symmetric) {
3465             PetscInt j,k;
3466             for (j=0;j<subset_size;j++) {
3467               for (k=j;k<subset_size;k++) {
3468                 S [j*subset_size+k] = Sarray [cumarray+j*subset_size+k];
3469                 St[j*subset_size+k] = Starray[cumarray+j*subset_size+k];
3470               }
3471             }
3472           } else {
3473             ierr = PetscMemcpy(S,Sarray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3474             ierr = PetscMemcpy(St,Starray+cumarray,subset_size*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3475           }
3476           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
3477 #if defined(PETSC_USE_COMPLEX)
3478           PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*subset_size,&B_N,work,&B_lwork,rwork,B_iwork,B_ifail,&B_ierr));
3479 #else
3480           PetscStackCallBLAS("LAPACKsygvx",LAPACKsygvx_(&B_itype,"V","I","L",&B_N,St,&B_N,S,&B_N,&lower,&upper,&B_IL,&B_IU,&eps,&B_neigs2,eigs+B_neigs,eigv+B_neigs*subset_size,&B_N,work,&B_lwork,B_iwork,B_ifail,&B_ierr));
3481 #endif
3482           ierr = PetscLogFlops((4.0*subset_size*subset_size*subset_size)/3.0);CHKERRQ(ierr);
3483           ierr = PetscFPTrapPop();CHKERRQ(ierr);
3484           B_neigs += B_neigs2;
3485         }
3486         if (B_ierr) {
3487           if (B_ierr < 0 ) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: illegal value for argument %d",-(int)B_ierr);
3488           else if (B_ierr <= B_N) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: %d eigenvalues failed to converge",(int)B_ierr);
3489           else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYGVX Lapack routine: leading minor of order %d is not positive definite",(int)B_ierr-B_N-1);
3490         }
3491         if (pcbddc->dbg_flag) {
3492           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"   -> Got %d eigs\n",B_neigs);CHKERRQ(ierr);
3493           for (j=0;j<B_neigs;j++) {
3494             if (eigs[j] == 0.0) {
3495               ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"     Inf\n");CHKERRQ(ierr);
3496             } else {
3497               if (pcbddc->use_deluxe_scaling) {
3498                 ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"     %1.6e\n",eigs[j+eigs_start]);CHKERRQ(ierr);
3499               } else {
3500                 ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"     %1.6e\n",1./eigs[j+eigs_start]);CHKERRQ(ierr);
3501               }
3502             }
3503           }
3504         }
3505       } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not yet implemented");
3506     }
3507     /* change the basis back to the original one */
3508     if (sub_schurs->change) {
3509       Mat change,phi,phit;
3510 
3511       if (pcbddc->dbg_flag > 2) {
3512         PetscInt ii;
3513         for (ii=0;ii<B_neigs;ii++) {
3514           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"   -> Eigenvector (old basis) %d/%d (%d)\n",ii,B_neigs,B_N);CHKERRQ(ierr);
3515           for (j=0;j<B_N;j++) {
3516 #if defined(PETSC_USE_COMPLEX)
3517             PetscReal r = PetscRealPart(eigv[(ii+eigs_start)*subset_size+j]);
3518             PetscReal c = PetscImaginaryPart(eigv[(ii+eigs_start)*subset_size+j]);
3519             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"       %1.4e + %1.4e i\n",r,c);CHKERRQ(ierr);
3520 #else
3521             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"       %1.4e\n",eigv[(ii+eigs_start)*subset_size+j]);CHKERRQ(ierr);
3522 #endif
3523           }
3524         }
3525       }
3526       ierr = KSPGetOperators(sub_schurs->change[i],&change,NULL);CHKERRQ(ierr);
3527       ierr = MatCreateSeqDense(PETSC_COMM_SELF,subset_size,B_neigs,eigv+eigs_start*subset_size,&phit);CHKERRQ(ierr);
3528       ierr = MatMatMult(change,phit,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&phi);CHKERRQ(ierr);
3529       ierr = MatCopy(phi,phit,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
3530       ierr = MatDestroy(&phit);CHKERRQ(ierr);
3531       ierr = MatDestroy(&phi);CHKERRQ(ierr);
3532     }
3533     maxneigs = PetscMax(B_neigs,maxneigs);
3534     pcbddc->adaptive_constraints_n[i+nv] = B_neigs;
3535     if (B_neigs) {
3536       ierr = PetscMemcpy(pcbddc->adaptive_constraints_data+pcbddc->adaptive_constraints_data_ptr[cum],eigv+eigs_start*subset_size,B_neigs*subset_size*sizeof(PetscScalar));CHKERRQ(ierr);
3537 
3538       if (pcbddc->dbg_flag > 1) {
3539         PetscInt ii;
3540         for (ii=0;ii<B_neigs;ii++) {
3541           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"   -> Eigenvector %d/%d (%d)\n",ii,B_neigs,B_N);CHKERRQ(ierr);
3542           for (j=0;j<B_N;j++) {
3543 #if defined(PETSC_USE_COMPLEX)
3544             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii*subset_size+j+pcbddc->adaptive_constraints_data_ptr[cum]]);
3545             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii*subset_size+j+pcbddc->adaptive_constraints_data_ptr[cum]]);
3546             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"       %1.4e + %1.4e i\n",r,c);CHKERRQ(ierr);
3547 #else
3548             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"       %1.4e\n",pcbddc->adaptive_constraints_data[ii*subset_size+j+pcbddc->adaptive_constraints_data_ptr[cum]]);CHKERRQ(ierr);
3549 #endif
3550           }
3551         }
3552       }
3553       ierr = PetscMemcpy(pcbddc->adaptive_constraints_idxs+pcbddc->adaptive_constraints_idxs_ptr[cum],idxs,subset_size*sizeof(PetscInt));CHKERRQ(ierr);
3554       pcbddc->adaptive_constraints_idxs_ptr[cum+1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
3555       pcbddc->adaptive_constraints_data_ptr[cum+1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size*B_neigs;
3556       cum++;
3557     }
3558     ierr = ISRestoreIndices(sub_schurs->is_subs[i],&idxs);CHKERRQ(ierr);
3559     /* shift for next computation */
3560     cumarray += subset_size*subset_size;
3561   }
3562   if (pcbddc->dbg_flag) {
3563     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
3564   }
3565 
3566   if (mss) {
3567     ierr = MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all,&Sarray);CHKERRQ(ierr);
3568     ierr = MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all,&Starray);CHKERRQ(ierr);
3569     /* destroy matrices (junk) */
3570     ierr = MatDestroy(&sub_schurs->sum_S_Ej_inv_all);CHKERRQ(ierr);
3571     ierr = MatDestroy(&sub_schurs->sum_S_Ej_tilda_all);CHKERRQ(ierr);
3572   }
3573   if (allocated_S_St) {
3574     ierr = PetscFree2(S,St);CHKERRQ(ierr);
3575   }
3576   ierr = PetscFree5(eigv,eigs,work,B_iwork,B_ifail);CHKERRQ(ierr);
3577 #if defined(PETSC_USE_COMPLEX)
3578   ierr = PetscFree(rwork);CHKERRQ(ierr);
3579 #endif
3580   if (pcbddc->dbg_flag) {
3581     PetscInt maxneigs_r;
3582     ierr = MPIU_Allreduce(&maxneigs,&maxneigs_r,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
3583     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Maximum number of constraints per cc %d\n",maxneigs_r);CHKERRQ(ierr);
3584   }
3585   ierr = PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
3586   PetscFunctionReturn(0);
3587 }
3588 
3589 PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3590 {
3591   PetscScalar    *coarse_submat_vals;
3592   PetscErrorCode ierr;
3593 
3594   PetscFunctionBegin;
3595   /* Setup local scatters R_to_B and (optionally) R_to_D */
3596   /* PCBDDCSetUpLocalWorkVectors should be called first! */
3597   ierr = PCBDDCSetUpLocalScatters(pc);CHKERRQ(ierr);
3598 
3599   /* Setup local neumann solver ksp_R */
3600   /* PCBDDCSetUpLocalScatters should be called first! */
3601   ierr = PCBDDCSetUpLocalSolvers(pc,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
3602 
3603   /*
3604      Setup local correction and local part of coarse basis.
3605      Gives back the dense local part of the coarse matrix in column major ordering
3606   */
3607   ierr = PCBDDCSetUpCorrection(pc,&coarse_submat_vals);CHKERRQ(ierr);
3608 
3609   /* Compute total number of coarse nodes and setup coarse solver */
3610   ierr = PCBDDCSetUpCoarseSolver(pc,coarse_submat_vals);CHKERRQ(ierr);
3611 
3612   /* free */
3613   ierr = PetscFree(coarse_submat_vals);CHKERRQ(ierr);
3614   PetscFunctionReturn(0);
3615 }
3616 
3617 PetscErrorCode PCBDDCResetCustomization(PC pc)
3618 {
3619   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
3620   PetscErrorCode ierr;
3621 
3622   PetscFunctionBegin;
3623   ierr = ISDestroy(&pcbddc->user_primal_vertices);CHKERRQ(ierr);
3624   ierr = ISDestroy(&pcbddc->user_primal_vertices_local);CHKERRQ(ierr);
3625   ierr = ISDestroy(&pcbddc->NeumannBoundaries);CHKERRQ(ierr);
3626   ierr = ISDestroy(&pcbddc->NeumannBoundariesLocal);CHKERRQ(ierr);
3627   ierr = ISDestroy(&pcbddc->DirichletBoundaries);CHKERRQ(ierr);
3628   ierr = MatNullSpaceDestroy(&pcbddc->onearnullspace);CHKERRQ(ierr);
3629   ierr = PetscFree(pcbddc->onearnullvecs_state);CHKERRQ(ierr);
3630   ierr = ISDestroy(&pcbddc->DirichletBoundariesLocal);CHKERRQ(ierr);
3631   ierr = PCBDDCSetDofsSplitting(pc,0,NULL);CHKERRQ(ierr);
3632   ierr = PCBDDCSetDofsSplittingLocal(pc,0,NULL);CHKERRQ(ierr);
3633   PetscFunctionReturn(0);
3634 }
3635 
3636 PetscErrorCode PCBDDCResetTopography(PC pc)
3637 {
3638   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
3639   PetscInt       i;
3640   PetscErrorCode ierr;
3641 
3642   PetscFunctionBegin;
3643   ierr = MatDestroy(&pcbddc->nedcG);CHKERRQ(ierr);
3644   ierr = ISDestroy(&pcbddc->nedclocal);CHKERRQ(ierr);
3645   ierr = MatDestroy(&pcbddc->discretegradient);CHKERRQ(ierr);
3646   ierr = MatDestroy(&pcbddc->user_ChangeOfBasisMatrix);CHKERRQ(ierr);
3647   ierr = MatDestroy(&pcbddc->ChangeOfBasisMatrix);CHKERRQ(ierr);
3648   ierr = MatDestroy(&pcbddc->switch_static_change);CHKERRQ(ierr);
3649   ierr = VecDestroy(&pcbddc->work_change);CHKERRQ(ierr);
3650   ierr = MatDestroy(&pcbddc->ConstraintMatrix);CHKERRQ(ierr);
3651   ierr = MatDestroy(&pcbddc->divudotp);CHKERRQ(ierr);
3652   ierr = ISDestroy(&pcbddc->divudotp_vl2l);CHKERRQ(ierr);
3653   ierr = PCBDDCGraphDestroy(&pcbddc->mat_graph);CHKERRQ(ierr);
3654   for (i=0;i<pcbddc->n_local_subs;i++) {
3655     ierr = ISDestroy(&pcbddc->local_subs[i]);CHKERRQ(ierr);
3656   }
3657   pcbddc->n_local_subs = 0;
3658   ierr = PetscFree(pcbddc->local_subs);CHKERRQ(ierr);
3659   ierr = PCBDDCSubSchursDestroy(&pcbddc->sub_schurs);CHKERRQ(ierr);
3660   pcbddc->graphanalyzed        = PETSC_FALSE;
3661   pcbddc->recompute_topography = PETSC_TRUE;
3662   pcbddc->corner_selected      = PETSC_FALSE;
3663   PetscFunctionReturn(0);
3664 }
3665 
3666 PetscErrorCode PCBDDCResetSolvers(PC pc)
3667 {
3668   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
3669   PetscErrorCode ierr;
3670 
3671   PetscFunctionBegin;
3672   ierr = VecDestroy(&pcbddc->coarse_vec);CHKERRQ(ierr);
3673   if (pcbddc->coarse_phi_B) {
3674     PetscScalar *array;
3675     ierr = MatDenseGetArray(pcbddc->coarse_phi_B,&array);CHKERRQ(ierr);
3676     ierr = PetscFree(array);CHKERRQ(ierr);
3677   }
3678   ierr = MatDestroy(&pcbddc->coarse_phi_B);CHKERRQ(ierr);
3679   ierr = MatDestroy(&pcbddc->coarse_phi_D);CHKERRQ(ierr);
3680   ierr = MatDestroy(&pcbddc->coarse_psi_B);CHKERRQ(ierr);
3681   ierr = MatDestroy(&pcbddc->coarse_psi_D);CHKERRQ(ierr);
3682   ierr = VecDestroy(&pcbddc->vec1_P);CHKERRQ(ierr);
3683   ierr = VecDestroy(&pcbddc->vec1_C);CHKERRQ(ierr);
3684   ierr = MatDestroy(&pcbddc->local_auxmat2);CHKERRQ(ierr);
3685   ierr = MatDestroy(&pcbddc->local_auxmat1);CHKERRQ(ierr);
3686   ierr = VecDestroy(&pcbddc->vec1_R);CHKERRQ(ierr);
3687   ierr = VecDestroy(&pcbddc->vec2_R);CHKERRQ(ierr);
3688   ierr = ISDestroy(&pcbddc->is_R_local);CHKERRQ(ierr);
3689   ierr = VecScatterDestroy(&pcbddc->R_to_B);CHKERRQ(ierr);
3690   ierr = VecScatterDestroy(&pcbddc->R_to_D);CHKERRQ(ierr);
3691   ierr = VecScatterDestroy(&pcbddc->coarse_loc_to_glob);CHKERRQ(ierr);
3692   ierr = KSPReset(pcbddc->ksp_D);CHKERRQ(ierr);
3693   ierr = KSPReset(pcbddc->ksp_R);CHKERRQ(ierr);
3694   ierr = KSPReset(pcbddc->coarse_ksp);CHKERRQ(ierr);
3695   ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
3696   ierr = PetscFree(pcbddc->primal_indices_local_idxs);CHKERRQ(ierr);
3697   ierr = PetscFree2(pcbddc->local_primal_ref_node,pcbddc->local_primal_ref_mult);CHKERRQ(ierr);
3698   ierr = PetscFree(pcbddc->global_primal_indices);CHKERRQ(ierr);
3699   ierr = ISDestroy(&pcbddc->coarse_subassembling);CHKERRQ(ierr);
3700   ierr = MatDestroy(&pcbddc->benign_change);CHKERRQ(ierr);
3701   ierr = VecDestroy(&pcbddc->benign_vec);CHKERRQ(ierr);
3702   ierr = PCBDDCBenignShellMat(pc,PETSC_TRUE);CHKERRQ(ierr);
3703   ierr = MatDestroy(&pcbddc->benign_B0);CHKERRQ(ierr);
3704   ierr = PetscSFDestroy(&pcbddc->benign_sf);CHKERRQ(ierr);
3705   if (pcbddc->benign_zerodiag_subs) {
3706     PetscInt i;
3707     for (i=0;i<pcbddc->benign_n;i++) {
3708       ierr = ISDestroy(&pcbddc->benign_zerodiag_subs[i]);CHKERRQ(ierr);
3709     }
3710     ierr = PetscFree(pcbddc->benign_zerodiag_subs);CHKERRQ(ierr);
3711   }
3712   ierr = PetscFree3(pcbddc->benign_p0_lidx,pcbddc->benign_p0_gidx,pcbddc->benign_p0);CHKERRQ(ierr);
3713   PetscFunctionReturn(0);
3714 }
3715 
3716 PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
3717 {
3718   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
3719   PC_IS          *pcis = (PC_IS*)pc->data;
3720   VecType        impVecType;
3721   PetscInt       n_constraints,n_R,old_size;
3722   PetscErrorCode ierr;
3723 
3724   PetscFunctionBegin;
3725   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3726   n_R = pcis->n - pcbddc->n_vertices;
3727   ierr = VecGetType(pcis->vec1_N,&impVecType);CHKERRQ(ierr);
3728   /* local work vectors (try to avoid unneeded work)*/
3729   /* R nodes */
3730   old_size = -1;
3731   if (pcbddc->vec1_R) {
3732     ierr = VecGetSize(pcbddc->vec1_R,&old_size);CHKERRQ(ierr);
3733   }
3734   if (n_R != old_size) {
3735     ierr = VecDestroy(&pcbddc->vec1_R);CHKERRQ(ierr);
3736     ierr = VecDestroy(&pcbddc->vec2_R);CHKERRQ(ierr);
3737     ierr = VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N),&pcbddc->vec1_R);CHKERRQ(ierr);
3738     ierr = VecSetSizes(pcbddc->vec1_R,PETSC_DECIDE,n_R);CHKERRQ(ierr);
3739     ierr = VecSetType(pcbddc->vec1_R,impVecType);CHKERRQ(ierr);
3740     ierr = VecDuplicate(pcbddc->vec1_R,&pcbddc->vec2_R);CHKERRQ(ierr);
3741   }
3742   /* local primal dofs */
3743   old_size = -1;
3744   if (pcbddc->vec1_P) {
3745     ierr = VecGetSize(pcbddc->vec1_P,&old_size);CHKERRQ(ierr);
3746   }
3747   if (pcbddc->local_primal_size != old_size) {
3748     ierr = VecDestroy(&pcbddc->vec1_P);CHKERRQ(ierr);
3749     ierr = VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N),&pcbddc->vec1_P);CHKERRQ(ierr);
3750     ierr = VecSetSizes(pcbddc->vec1_P,PETSC_DECIDE,pcbddc->local_primal_size);CHKERRQ(ierr);
3751     ierr = VecSetType(pcbddc->vec1_P,impVecType);CHKERRQ(ierr);
3752   }
3753   /* local explicit constraints */
3754   old_size = -1;
3755   if (pcbddc->vec1_C) {
3756     ierr = VecGetSize(pcbddc->vec1_C,&old_size);CHKERRQ(ierr);
3757   }
3758   if (n_constraints && n_constraints != old_size) {
3759     ierr = VecDestroy(&pcbddc->vec1_C);CHKERRQ(ierr);
3760     ierr = VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N),&pcbddc->vec1_C);CHKERRQ(ierr);
3761     ierr = VecSetSizes(pcbddc->vec1_C,PETSC_DECIDE,n_constraints);CHKERRQ(ierr);
3762     ierr = VecSetType(pcbddc->vec1_C,impVecType);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 PetscErrorCode PCBDDCSetUpCorrection(PC pc, PetscScalar **coarse_submat_vals_n)
3768 {
3769   PetscErrorCode  ierr;
3770   /* pointers to pcis and pcbddc */
3771   PC_IS*          pcis = (PC_IS*)pc->data;
3772   PC_BDDC*        pcbddc = (PC_BDDC*)pc->data;
3773   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
3774   /* submatrices of local problem */
3775   Mat             A_RV,A_VR,A_VV,local_auxmat2_R;
3776   /* submatrices of local coarse problem */
3777   Mat             S_VV,S_CV,S_VC,S_CC;
3778   /* working matrices */
3779   Mat             C_CR;
3780   /* additional working stuff */
3781   PC              pc_R;
3782   Mat             F,Brhs = NULL;
3783   Vec             dummy_vec;
3784   PetscBool       isLU,isCHOL,isILU,need_benign_correction,sparserhs;
3785   PetscScalar     *coarse_submat_vals; /* TODO: use a PETSc matrix */
3786   PetscScalar     *work;
3787   PetscInt        *idx_V_B;
3788   PetscInt        lda_rhs,n,n_vertices,n_constraints,*p0_lidx_I;
3789   PetscInt        i,n_R,n_D,n_B;
3790 
3791   /* some shortcuts to scalars */
3792   PetscScalar     one=1.0,m_one=-1.0;
3793 
3794   PetscFunctionBegin;
3795   if (!pcbddc->symmetric_primal && pcbddc->benign_n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Non-symmetric primal basis computation with benign trick not yet implemented");
3796   ierr = PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
3797 
3798   /* Set Non-overlapping dimensions */
3799   n_vertices = pcbddc->n_vertices;
3800   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
3801   n_B = pcis->n_B;
3802   n_D = pcis->n - n_B;
3803   n_R = pcis->n - n_vertices;
3804 
3805   /* vertices in boundary numbering */
3806   ierr = PetscMalloc1(n_vertices,&idx_V_B);CHKERRQ(ierr);
3807   ierr = ISGlobalToLocalMappingApply(pcis->BtoNmap,IS_GTOLM_DROP,n_vertices,pcbddc->local_primal_ref_node,&i,idx_V_B);CHKERRQ(ierr);
3808   if (i != n_vertices) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in boundary numbering for BDDC vertices! %D != %D\n",n_vertices,i);
3809 
3810   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
3811   ierr = PetscCalloc1(pcbddc->local_primal_size*pcbddc->local_primal_size,&coarse_submat_vals);CHKERRQ(ierr);
3812   ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_vertices,n_vertices,coarse_submat_vals,&S_VV);CHKERRQ(ierr);
3813   ierr = MatSeqDenseSetLDA(S_VV,pcbddc->local_primal_size);CHKERRQ(ierr);
3814   ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_constraints,n_vertices,coarse_submat_vals+n_vertices,&S_CV);CHKERRQ(ierr);
3815   ierr = MatSeqDenseSetLDA(S_CV,pcbddc->local_primal_size);CHKERRQ(ierr);
3816   ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_vertices,n_constraints,coarse_submat_vals+pcbddc->local_primal_size*n_vertices,&S_VC);CHKERRQ(ierr);
3817   ierr = MatSeqDenseSetLDA(S_VC,pcbddc->local_primal_size);CHKERRQ(ierr);
3818   ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_constraints,n_constraints,coarse_submat_vals+(pcbddc->local_primal_size+1)*n_vertices,&S_CC);CHKERRQ(ierr);
3819   ierr = MatSeqDenseSetLDA(S_CC,pcbddc->local_primal_size);CHKERRQ(ierr);
3820 
3821   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
3822   ierr = KSPGetPC(pcbddc->ksp_R,&pc_R);CHKERRQ(ierr);
3823   ierr = PCSetUp(pc_R);CHKERRQ(ierr);
3824   ierr = PetscObjectTypeCompare((PetscObject)pc_R,PCLU,&isLU);CHKERRQ(ierr);
3825   ierr = PetscObjectTypeCompare((PetscObject)pc_R,PCILU,&isILU);CHKERRQ(ierr);
3826   ierr = PetscObjectTypeCompare((PetscObject)pc_R,PCCHOLESKY,&isCHOL);CHKERRQ(ierr);
3827   lda_rhs = n_R;
3828   need_benign_correction = PETSC_FALSE;
3829   if (isLU || isILU || isCHOL) {
3830     ierr = PCFactorGetMatrix(pc_R,&F);CHKERRQ(ierr);
3831   } else if (sub_schurs && sub_schurs->reuse_solver) {
3832     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3833     MatFactorType      type;
3834 
3835     F = reuse_solver->F;
3836     ierr = MatGetFactorType(F,&type);CHKERRQ(ierr);
3837     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
3838     ierr = MatGetSize(F,&lda_rhs,NULL);CHKERRQ(ierr);
3839     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
3840   } else {
3841     F = NULL;
3842   }
3843 
3844   /* determine if we can use a sparse right-hand side */
3845   sparserhs = PETSC_FALSE;
3846   if (F) {
3847     MatSolverType solver;
3848 
3849     ierr = MatFactorGetSolverType(F,&solver);CHKERRQ(ierr);
3850     ierr = PetscStrcmp(solver,MATSOLVERMUMPS,&sparserhs);CHKERRQ(ierr);
3851   }
3852 
3853   /* allocate workspace */
3854   n = 0;
3855   if (n_constraints) {
3856     n += lda_rhs*n_constraints;
3857   }
3858   if (n_vertices) {
3859     n = PetscMax(2*lda_rhs*n_vertices,n);
3860     n = PetscMax((lda_rhs+n_B)*n_vertices,n);
3861   }
3862   if (!pcbddc->symmetric_primal) {
3863     n = PetscMax(2*lda_rhs*pcbddc->local_primal_size,n);
3864   }
3865   ierr = PetscMalloc1(n,&work);CHKERRQ(ierr);
3866 
3867   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
3868   dummy_vec = NULL;
3869   if (need_benign_correction && lda_rhs != n_R && F) {
3870     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,lda_rhs,work,&dummy_vec);CHKERRQ(ierr);
3871   }
3872 
3873   /* Precompute stuffs needed for preprocessing and application of BDDC*/
3874   if (n_constraints) {
3875     Mat         M3,C_B;
3876     IS          is_aux;
3877     PetscScalar *array,*array2;
3878 
3879     ierr = MatDestroy(&pcbddc->local_auxmat1);CHKERRQ(ierr);
3880     ierr = MatDestroy(&pcbddc->local_auxmat2);CHKERRQ(ierr);
3881 
3882     /* Extract constraints on R nodes: C_{CR}  */
3883     ierr = ISCreateStride(PETSC_COMM_SELF,n_constraints,n_vertices,1,&is_aux);CHKERRQ(ierr);
3884     ierr = MatCreateSubMatrix(pcbddc->ConstraintMatrix,is_aux,pcbddc->is_R_local,MAT_INITIAL_MATRIX,&C_CR);CHKERRQ(ierr);
3885     ierr = MatCreateSubMatrix(pcbddc->ConstraintMatrix,is_aux,pcis->is_B_local,MAT_INITIAL_MATRIX,&C_B);CHKERRQ(ierr);
3886 
3887     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
3888     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
3889     if (!sparserhs) {
3890       ierr = PetscMemzero(work,lda_rhs*n_constraints*sizeof(PetscScalar));CHKERRQ(ierr);
3891       for (i=0;i<n_constraints;i++) {
3892         const PetscScalar *row_cmat_values;
3893         const PetscInt    *row_cmat_indices;
3894         PetscInt          size_of_constraint,j;
3895 
3896         ierr = MatGetRow(C_CR,i,&size_of_constraint,&row_cmat_indices,&row_cmat_values);CHKERRQ(ierr);
3897         for (j=0;j<size_of_constraint;j++) {
3898           work[row_cmat_indices[j]+i*lda_rhs] = -row_cmat_values[j];
3899         }
3900         ierr = MatRestoreRow(C_CR,i,&size_of_constraint,&row_cmat_indices,&row_cmat_values);CHKERRQ(ierr);
3901       }
3902       ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_constraints,work,&Brhs);CHKERRQ(ierr);
3903     } else {
3904       Mat tC_CR;
3905 
3906       ierr = MatScale(C_CR,-1.0);CHKERRQ(ierr);
3907       if (lda_rhs != n_R) {
3908         PetscScalar *aa;
3909         PetscInt    r,*ii,*jj;
3910         PetscBool   done;
3911 
3912         ierr = MatGetRowIJ(C_CR,0,PETSC_FALSE,PETSC_FALSE,&r,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
3913         if (!done) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"GetRowIJ failed");
3914         ierr = MatSeqAIJGetArray(C_CR,&aa);CHKERRQ(ierr);
3915         ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,n_constraints,lda_rhs,ii,jj,aa,&tC_CR);CHKERRQ(ierr);
3916         ierr = MatRestoreRowIJ(C_CR,0,PETSC_FALSE,PETSC_FALSE,&r,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
3917         if (!done) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"RestoreRowIJ failed");
3918       } else {
3919         ierr  = PetscObjectReference((PetscObject)C_CR);CHKERRQ(ierr);
3920         tC_CR = C_CR;
3921       }
3922       ierr = MatCreateTranspose(tC_CR,&Brhs);CHKERRQ(ierr);
3923       ierr = MatDestroy(&tC_CR);CHKERRQ(ierr);
3924     }
3925     ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_constraints,NULL,&local_auxmat2_R);CHKERRQ(ierr);
3926     if (F) {
3927       if (need_benign_correction) {
3928         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3929 
3930         /* rhs is already zero on interior dofs, no need to change the rhs */
3931         ierr = PetscMemzero(reuse_solver->benign_save_vals,pcbddc->benign_n*sizeof(PetscScalar));CHKERRQ(ierr);
3932       }
3933       ierr = MatMatSolve(F,Brhs,local_auxmat2_R);CHKERRQ(ierr);
3934       if (need_benign_correction) {
3935         PetscScalar        *marr;
3936         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3937 
3938         ierr = MatDenseGetArray(local_auxmat2_R,&marr);CHKERRQ(ierr);
3939         if (lda_rhs != n_R) {
3940           for (i=0;i<n_constraints;i++) {
3941             ierr = VecPlaceArray(dummy_vec,marr+i*lda_rhs);CHKERRQ(ierr);
3942             ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,dummy_vec,NULL,PETSC_TRUE,PETSC_TRUE);CHKERRQ(ierr);
3943             ierr = VecResetArray(dummy_vec);CHKERRQ(ierr);
3944           }
3945         } else {
3946           for (i=0;i<n_constraints;i++) {
3947             ierr = VecPlaceArray(pcbddc->vec1_R,marr+i*lda_rhs);CHKERRQ(ierr);
3948             ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,pcbddc->vec1_R,NULL,PETSC_TRUE,PETSC_TRUE);CHKERRQ(ierr);
3949             ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
3950           }
3951         }
3952         ierr = MatDenseRestoreArray(local_auxmat2_R,&marr);CHKERRQ(ierr);
3953       }
3954     } else {
3955       PetscScalar *marr;
3956 
3957       ierr = MatDenseGetArray(local_auxmat2_R,&marr);CHKERRQ(ierr);
3958       for (i=0;i<n_constraints;i++) {
3959         ierr = VecPlaceArray(pcbddc->vec1_R,work+i*lda_rhs);CHKERRQ(ierr);
3960         ierr = VecPlaceArray(pcbddc->vec2_R,marr+i*lda_rhs);CHKERRQ(ierr);
3961         ierr = KSPSolve(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec2_R);CHKERRQ(ierr);
3962         ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
3963         ierr = VecResetArray(pcbddc->vec2_R);CHKERRQ(ierr);
3964       }
3965       ierr = MatDenseRestoreArray(local_auxmat2_R,&marr);CHKERRQ(ierr);
3966     }
3967     if (sparserhs) {
3968       ierr = MatScale(C_CR,-1.0);CHKERRQ(ierr);
3969     }
3970     ierr = MatDestroy(&Brhs);CHKERRQ(ierr);
3971     if (!pcbddc->switch_static) {
3972       ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_B,n_constraints,NULL,&pcbddc->local_auxmat2);CHKERRQ(ierr);
3973       ierr = MatDenseGetArray(pcbddc->local_auxmat2,&array);CHKERRQ(ierr);
3974       ierr = MatDenseGetArray(local_auxmat2_R,&array2);CHKERRQ(ierr);
3975       for (i=0;i<n_constraints;i++) {
3976         ierr = VecPlaceArray(pcbddc->vec1_R,array2+i*lda_rhs);CHKERRQ(ierr);
3977         ierr = VecPlaceArray(pcis->vec1_B,array+i*n_B);CHKERRQ(ierr);
3978         ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3979         ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3980         ierr = VecResetArray(pcis->vec1_B);CHKERRQ(ierr);
3981         ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
3982       }
3983       ierr = MatDenseRestoreArray(local_auxmat2_R,&array2);CHKERRQ(ierr);
3984       ierr = MatDenseRestoreArray(pcbddc->local_auxmat2,&array);CHKERRQ(ierr);
3985       ierr = MatMatMult(C_B,pcbddc->local_auxmat2,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&M3);CHKERRQ(ierr);
3986     } else {
3987       if (lda_rhs != n_R) {
3988         IS dummy;
3989 
3990         ierr = ISCreateStride(PETSC_COMM_SELF,n_R,0,1,&dummy);CHKERRQ(ierr);
3991         ierr = MatCreateSubMatrix(local_auxmat2_R,dummy,NULL,MAT_INITIAL_MATRIX,&pcbddc->local_auxmat2);CHKERRQ(ierr);
3992         ierr = ISDestroy(&dummy);CHKERRQ(ierr);
3993       } else {
3994         ierr = PetscObjectReference((PetscObject)local_auxmat2_R);CHKERRQ(ierr);
3995         pcbddc->local_auxmat2 = local_auxmat2_R;
3996       }
3997       ierr = MatMatMult(C_CR,pcbddc->local_auxmat2,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&M3);CHKERRQ(ierr);
3998     }
3999     ierr = ISDestroy(&is_aux);CHKERRQ(ierr);
4000     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR} )^{-1}  */
4001     ierr = MatScale(M3,m_one);CHKERRQ(ierr);
4002     if (isCHOL) {
4003       ierr = MatCholeskyFactor(M3,NULL,NULL);CHKERRQ(ierr);
4004     } else {
4005       ierr = MatLUFactor(M3,NULL,NULL,NULL);CHKERRQ(ierr);
4006     }
4007     ierr = MatSeqDenseInvertFactors_Private(M3);CHKERRQ(ierr);
4008     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
4009     ierr = MatMatMult(M3,C_B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&pcbddc->local_auxmat1);CHKERRQ(ierr);
4010     ierr = MatDestroy(&C_B);CHKERRQ(ierr);
4011     ierr = MatCopy(M3,S_CC,SAME_NONZERO_PATTERN);CHKERRQ(ierr); /* S_CC can have a different LDA, MatMatSolve doesn't support it */
4012     ierr = MatDestroy(&M3);CHKERRQ(ierr);
4013   }
4014 
4015   /* Get submatrices from subdomain matrix */
4016   if (n_vertices) {
4017     IS        is_aux;
4018     PetscBool isseqaij;
4019 
4020     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
4021       IS tis;
4022 
4023       ierr = ISDuplicate(pcbddc->is_R_local,&tis);CHKERRQ(ierr);
4024       ierr = ISSort(tis);CHKERRQ(ierr);
4025       ierr = ISComplement(tis,0,pcis->n,&is_aux);CHKERRQ(ierr);
4026       ierr = ISDestroy(&tis);CHKERRQ(ierr);
4027     } else {
4028       ierr = ISComplement(pcbddc->is_R_local,0,pcis->n,&is_aux);CHKERRQ(ierr);
4029     }
4030     ierr = MatCreateSubMatrix(pcbddc->local_mat,pcbddc->is_R_local,is_aux,MAT_INITIAL_MATRIX,&A_RV);CHKERRQ(ierr);
4031     ierr = MatCreateSubMatrix(pcbddc->local_mat,is_aux,pcbddc->is_R_local,MAT_INITIAL_MATRIX,&A_VR);CHKERRQ(ierr);
4032     ierr = PetscObjectTypeCompare((PetscObject)A_VR,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
4033     if (!isseqaij) { /* MatMatMult(A_VR,A_RRmA_RV) below will raise an error */
4034       ierr = MatConvert(A_VR,MATSEQAIJ,MAT_INPLACE_MATRIX,&A_VR);CHKERRQ(ierr);
4035     }
4036     ierr = MatCreateSubMatrix(pcbddc->local_mat,is_aux,is_aux,MAT_INITIAL_MATRIX,&A_VV);CHKERRQ(ierr);
4037     ierr = ISDestroy(&is_aux);CHKERRQ(ierr);
4038   }
4039 
4040   /* Matrix of coarse basis functions (local) */
4041   if (pcbddc->coarse_phi_B) {
4042     PetscInt on_B,on_primal,on_D=n_D;
4043     if (pcbddc->coarse_phi_D) {
4044       ierr = MatGetSize(pcbddc->coarse_phi_D,&on_D,NULL);CHKERRQ(ierr);
4045     }
4046     ierr = MatGetSize(pcbddc->coarse_phi_B,&on_B,&on_primal);CHKERRQ(ierr);
4047     if (on_B != n_B || on_primal != pcbddc->local_primal_size || on_D != n_D) {
4048       PetscScalar *marray;
4049 
4050       ierr = MatDenseGetArray(pcbddc->coarse_phi_B,&marray);CHKERRQ(ierr);
4051       ierr = PetscFree(marray);CHKERRQ(ierr);
4052       ierr = MatDestroy(&pcbddc->coarse_phi_B);CHKERRQ(ierr);
4053       ierr = MatDestroy(&pcbddc->coarse_psi_B);CHKERRQ(ierr);
4054       ierr = MatDestroy(&pcbddc->coarse_phi_D);CHKERRQ(ierr);
4055       ierr = MatDestroy(&pcbddc->coarse_psi_D);CHKERRQ(ierr);
4056     }
4057   }
4058 
4059   if (!pcbddc->coarse_phi_B) {
4060     PetscScalar *marr;
4061 
4062     /* memory size */
4063     n = n_B*pcbddc->local_primal_size;
4064     if (pcbddc->switch_static || pcbddc->dbg_flag) n += n_D*pcbddc->local_primal_size;
4065     if (!pcbddc->symmetric_primal) n *= 2;
4066     ierr  = PetscCalloc1(n,&marr);CHKERRQ(ierr);
4067     ierr  = MatCreateSeqDense(PETSC_COMM_SELF,n_B,pcbddc->local_primal_size,marr,&pcbddc->coarse_phi_B);CHKERRQ(ierr);
4068     marr += n_B*pcbddc->local_primal_size;
4069     if (pcbddc->switch_static || pcbddc->dbg_flag) {
4070       ierr  = MatCreateSeqDense(PETSC_COMM_SELF,n_D,pcbddc->local_primal_size,marr,&pcbddc->coarse_phi_D);CHKERRQ(ierr);
4071       marr += n_D*pcbddc->local_primal_size;
4072     }
4073     if (!pcbddc->symmetric_primal) {
4074       ierr  = MatCreateSeqDense(PETSC_COMM_SELF,n_B,pcbddc->local_primal_size,marr,&pcbddc->coarse_psi_B);CHKERRQ(ierr);
4075       marr += n_B*pcbddc->local_primal_size;
4076       if (pcbddc->switch_static || pcbddc->dbg_flag) {
4077         ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_D,pcbddc->local_primal_size,marr,&pcbddc->coarse_psi_D);CHKERRQ(ierr);
4078       }
4079     } else {
4080       ierr = PetscObjectReference((PetscObject)pcbddc->coarse_phi_B);CHKERRQ(ierr);
4081       pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
4082       if (pcbddc->switch_static || pcbddc->dbg_flag) {
4083         ierr = PetscObjectReference((PetscObject)pcbddc->coarse_phi_D);CHKERRQ(ierr);
4084         pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
4085       }
4086     }
4087   }
4088 
4089   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
4090   p0_lidx_I = NULL;
4091   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4092     const PetscInt *idxs;
4093 
4094     ierr = ISGetIndices(pcis->is_I_local,&idxs);CHKERRQ(ierr);
4095     ierr = PetscMalloc1(pcbddc->benign_n,&p0_lidx_I);CHKERRQ(ierr);
4096     for (i=0;i<pcbddc->benign_n;i++) {
4097       ierr = PetscFindInt(pcbddc->benign_p0_lidx[i],pcis->n-pcis->n_B,idxs,&p0_lidx_I[i]);CHKERRQ(ierr);
4098     }
4099     ierr = ISRestoreIndices(pcis->is_I_local,&idxs);CHKERRQ(ierr);
4100   }
4101 
4102   /* vertices */
4103   if (n_vertices) {
4104     PetscBool restoreavr = PETSC_FALSE;
4105 
4106     ierr = MatConvert(A_VV,MATDENSE,MAT_INPLACE_MATRIX,&A_VV);CHKERRQ(ierr);
4107 
4108     if (n_R) {
4109       Mat          A_RRmA_RV,A_RV_bcorr=NULL,S_VVt; /* S_VVt with LDA=N */
4110       PetscBLASInt B_N,B_one = 1;
4111       PetscScalar  *x,*y;
4112 
4113       ierr = MatScale(A_RV,m_one);CHKERRQ(ierr);
4114       if (need_benign_correction) {
4115         ISLocalToGlobalMapping RtoN;
4116         IS                     is_p0;
4117         PetscInt               *idxs_p0,n;
4118 
4119         ierr = PetscMalloc1(pcbddc->benign_n,&idxs_p0);CHKERRQ(ierr);
4120         ierr = ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local,&RtoN);CHKERRQ(ierr);
4121         ierr = ISGlobalToLocalMappingApply(RtoN,IS_GTOLM_DROP,pcbddc->benign_n,pcbddc->benign_p0_lidx,&n,idxs_p0);CHKERRQ(ierr);
4122         if (n != pcbddc->benign_n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in R numbering for benign p0! %d != %d\n",n,pcbddc->benign_n);
4123         ierr = ISLocalToGlobalMappingDestroy(&RtoN);CHKERRQ(ierr);
4124         ierr = ISCreateGeneral(PETSC_COMM_SELF,n,idxs_p0,PETSC_OWN_POINTER,&is_p0);CHKERRQ(ierr);
4125         ierr = MatCreateSubMatrix(A_RV,is_p0,NULL,MAT_INITIAL_MATRIX,&A_RV_bcorr);CHKERRQ(ierr);
4126         ierr = ISDestroy(&is_p0);CHKERRQ(ierr);
4127       }
4128 
4129       ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_vertices,work,&A_RRmA_RV);CHKERRQ(ierr);
4130       if (!sparserhs || need_benign_correction) {
4131         if (lda_rhs == n_R) {
4132           ierr = MatConvert(A_RV,MATDENSE,MAT_INPLACE_MATRIX,&A_RV);CHKERRQ(ierr);
4133         } else {
4134           PetscScalar    *av,*array;
4135           const PetscInt *xadj,*adjncy;
4136           PetscInt       n;
4137           PetscBool      flg_row;
4138 
4139           array = work+lda_rhs*n_vertices;
4140           ierr = PetscMemzero(array,lda_rhs*n_vertices*sizeof(PetscScalar));CHKERRQ(ierr);
4141           ierr = MatConvert(A_RV,MATSEQAIJ,MAT_INPLACE_MATRIX,&A_RV);CHKERRQ(ierr);
4142           ierr = MatGetRowIJ(A_RV,0,PETSC_FALSE,PETSC_FALSE,&n,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
4143           ierr = MatSeqAIJGetArray(A_RV,&av);CHKERRQ(ierr);
4144           for (i=0;i<n;i++) {
4145             PetscInt j;
4146             for (j=xadj[i];j<xadj[i+1];j++) array[lda_rhs*adjncy[j]+i] = av[j];
4147           }
4148           ierr = MatRestoreRowIJ(A_RV,0,PETSC_FALSE,PETSC_FALSE,&n,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
4149           ierr = MatDestroy(&A_RV);CHKERRQ(ierr);
4150           ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_vertices,array,&A_RV);CHKERRQ(ierr);
4151         }
4152         if (need_benign_correction) {
4153           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4154           PetscScalar        *marr;
4155 
4156           ierr = MatDenseGetArray(A_RV,&marr);CHKERRQ(ierr);
4157           /* need \Phi^T A_RV = (I+L)A_RV, L given by
4158 
4159                  | 0 0  0 | (V)
4160              L = | 0 0 -1 | (P-p0)
4161                  | 0 0 -1 | (p0)
4162 
4163           */
4164           for (i=0;i<reuse_solver->benign_n;i++) {
4165             const PetscScalar *vals;
4166             const PetscInt    *idxs,*idxs_zero;
4167             PetscInt          n,j,nz;
4168 
4169             ierr = ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i],&nz);CHKERRQ(ierr);
4170             ierr = ISGetIndices(reuse_solver->benign_zerodiag_subs[i],&idxs_zero);CHKERRQ(ierr);
4171             ierr = MatGetRow(A_RV_bcorr,i,&n,&idxs,&vals);CHKERRQ(ierr);
4172             for (j=0;j<n;j++) {
4173               PetscScalar val = vals[j];
4174               PetscInt    k,col = idxs[j];
4175               for (k=0;k<nz;k++) marr[idxs_zero[k]+lda_rhs*col] -= val;
4176             }
4177             ierr = MatRestoreRow(A_RV_bcorr,i,&n,&idxs,&vals);CHKERRQ(ierr);
4178             ierr = ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i],&idxs_zero);CHKERRQ(ierr);
4179           }
4180           ierr = MatDenseRestoreArray(A_RV,&marr);CHKERRQ(ierr);
4181         }
4182         ierr = PetscObjectReference((PetscObject)A_RV);CHKERRQ(ierr);
4183         Brhs = A_RV;
4184       } else {
4185         Mat tA_RVT,A_RVT;
4186 
4187         if (!pcbddc->symmetric_primal) {
4188           /* A_RV already scaled by -1 */
4189           ierr = MatTranspose(A_RV,MAT_INITIAL_MATRIX,&A_RVT);CHKERRQ(ierr);
4190         } else {
4191           restoreavr = PETSC_TRUE;
4192           ierr  = MatScale(A_VR,-1.0);CHKERRQ(ierr);
4193           ierr  = PetscObjectReference((PetscObject)A_VR);CHKERRQ(ierr);
4194           A_RVT = A_VR;
4195         }
4196         if (lda_rhs != n_R) {
4197           PetscScalar *aa;
4198           PetscInt    r,*ii,*jj;
4199           PetscBool   done;
4200 
4201           ierr = MatGetRowIJ(A_RVT,0,PETSC_FALSE,PETSC_FALSE,&r,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
4202           if (!done) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"GetRowIJ failed");
4203           ierr = MatSeqAIJGetArray(A_RVT,&aa);CHKERRQ(ierr);
4204           ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,n_vertices,lda_rhs,ii,jj,aa,&tA_RVT);CHKERRQ(ierr);
4205           ierr = MatRestoreRowIJ(A_RVT,0,PETSC_FALSE,PETSC_FALSE,&r,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
4206           if (!done) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"RestoreRowIJ failed");
4207         } else {
4208           ierr   = PetscObjectReference((PetscObject)A_RVT);CHKERRQ(ierr);
4209           tA_RVT = A_RVT;
4210         }
4211         ierr = MatCreateTranspose(tA_RVT,&Brhs);CHKERRQ(ierr);
4212         ierr = MatDestroy(&tA_RVT);CHKERRQ(ierr);
4213         ierr = MatDestroy(&A_RVT);CHKERRQ(ierr);
4214       }
4215       if (F) {
4216         /* need to correct the rhs */
4217         if (need_benign_correction) {
4218           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4219           PetscScalar        *marr;
4220 
4221           ierr = MatDenseGetArray(Brhs,&marr);CHKERRQ(ierr);
4222           if (lda_rhs != n_R) {
4223             for (i=0;i<n_vertices;i++) {
4224               ierr = VecPlaceArray(dummy_vec,marr+i*lda_rhs);CHKERRQ(ierr);
4225               ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,dummy_vec,NULL,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
4226               ierr = VecResetArray(dummy_vec);CHKERRQ(ierr);
4227             }
4228           } else {
4229             for (i=0;i<n_vertices;i++) {
4230               ierr = VecPlaceArray(pcbddc->vec1_R,marr+i*lda_rhs);CHKERRQ(ierr);
4231               ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,pcbddc->vec1_R,NULL,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
4232               ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4233             }
4234           }
4235           ierr = MatDenseRestoreArray(Brhs,&marr);CHKERRQ(ierr);
4236         }
4237         ierr = MatMatSolve(F,Brhs,A_RRmA_RV);CHKERRQ(ierr);
4238         if (restoreavr) {
4239           ierr = MatScale(A_VR,-1.0);CHKERRQ(ierr);
4240         }
4241         /* need to correct the solution */
4242         if (need_benign_correction) {
4243           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4244           PetscScalar        *marr;
4245 
4246           ierr = MatDenseGetArray(A_RRmA_RV,&marr);CHKERRQ(ierr);
4247           if (lda_rhs != n_R) {
4248             for (i=0;i<n_vertices;i++) {
4249               ierr = VecPlaceArray(dummy_vec,marr+i*lda_rhs);CHKERRQ(ierr);
4250               ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,dummy_vec,NULL,PETSC_TRUE,PETSC_TRUE);CHKERRQ(ierr);
4251               ierr = VecResetArray(dummy_vec);CHKERRQ(ierr);
4252             }
4253           } else {
4254             for (i=0;i<n_vertices;i++) {
4255               ierr = VecPlaceArray(pcbddc->vec1_R,marr+i*lda_rhs);CHKERRQ(ierr);
4256               ierr = PCBDDCReuseSolversBenignAdapt(reuse_solver,pcbddc->vec1_R,NULL,PETSC_TRUE,PETSC_TRUE);CHKERRQ(ierr);
4257               ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4258             }
4259           }
4260           ierr = MatDenseRestoreArray(A_RRmA_RV,&marr);CHKERRQ(ierr);
4261         }
4262       } else {
4263         ierr = MatDenseGetArray(Brhs,&y);CHKERRQ(ierr);
4264         for (i=0;i<n_vertices;i++) {
4265           ierr = VecPlaceArray(pcbddc->vec1_R,y+i*lda_rhs);CHKERRQ(ierr);
4266           ierr = VecPlaceArray(pcbddc->vec2_R,work+i*lda_rhs);CHKERRQ(ierr);
4267           ierr = KSPSolve(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec2_R);CHKERRQ(ierr);
4268           ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4269           ierr = VecResetArray(pcbddc->vec2_R);CHKERRQ(ierr);
4270         }
4271         ierr = MatDenseRestoreArray(Brhs,&y);CHKERRQ(ierr);
4272       }
4273       ierr = MatDestroy(&A_RV);CHKERRQ(ierr);
4274       ierr = MatDestroy(&Brhs);CHKERRQ(ierr);
4275       /* S_VV and S_CV */
4276       if (n_constraints) {
4277         Mat B;
4278 
4279         ierr = PetscMemzero(work+lda_rhs*n_vertices,n_B*n_vertices*sizeof(PetscScalar));CHKERRQ(ierr);
4280         for (i=0;i<n_vertices;i++) {
4281           ierr = VecPlaceArray(pcbddc->vec1_R,work+i*lda_rhs);CHKERRQ(ierr);
4282           ierr = VecPlaceArray(pcis->vec1_B,work+lda_rhs*n_vertices+i*n_B);CHKERRQ(ierr);
4283           ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4284           ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4285           ierr = VecResetArray(pcis->vec1_B);CHKERRQ(ierr);
4286           ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4287         }
4288         ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_B,n_vertices,work+lda_rhs*n_vertices,&B);CHKERRQ(ierr);
4289         ierr = MatMatMult(pcbddc->local_auxmat1,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&S_CV);CHKERRQ(ierr);
4290         ierr = MatDestroy(&B);CHKERRQ(ierr);
4291         ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_vertices,work+lda_rhs*n_vertices,&B);CHKERRQ(ierr);
4292         ierr = MatMatMult(local_auxmat2_R,S_CV,MAT_REUSE_MATRIX,PETSC_DEFAULT,&B);CHKERRQ(ierr);
4293         ierr = MatScale(S_CV,m_one);CHKERRQ(ierr);
4294         ierr = PetscBLASIntCast(lda_rhs*n_vertices,&B_N);CHKERRQ(ierr);
4295         PetscStackCallBLAS("BLASaxpy",BLASaxpy_(&B_N,&one,work+lda_rhs*n_vertices,&B_one,work,&B_one));
4296         ierr = MatDestroy(&B);CHKERRQ(ierr);
4297       }
4298       if (lda_rhs != n_R) {
4299         ierr = MatDestroy(&A_RRmA_RV);CHKERRQ(ierr);
4300         ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_R,n_vertices,work,&A_RRmA_RV);CHKERRQ(ierr);
4301         ierr = MatSeqDenseSetLDA(A_RRmA_RV,lda_rhs);CHKERRQ(ierr);
4302       }
4303       ierr = MatMatMult(A_VR,A_RRmA_RV,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&S_VVt);CHKERRQ(ierr);
4304       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
4305       if (need_benign_correction) {
4306         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4307         PetscScalar      *marr,*sums;
4308 
4309         ierr = PetscMalloc1(n_vertices,&sums);CHKERRQ(ierr);
4310         ierr = MatDenseGetArray(S_VVt,&marr);CHKERRQ(ierr);
4311         for (i=0;i<reuse_solver->benign_n;i++) {
4312           const PetscScalar *vals;
4313           const PetscInt    *idxs,*idxs_zero;
4314           PetscInt          n,j,nz;
4315 
4316           ierr = ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i],&nz);CHKERRQ(ierr);
4317           ierr = ISGetIndices(reuse_solver->benign_zerodiag_subs[i],&idxs_zero);CHKERRQ(ierr);
4318           for (j=0;j<n_vertices;j++) {
4319             PetscInt k;
4320             sums[j] = 0.;
4321             for (k=0;k<nz;k++) sums[j] += work[idxs_zero[k]+j*lda_rhs];
4322           }
4323           ierr = MatGetRow(A_RV_bcorr,i,&n,&idxs,&vals);CHKERRQ(ierr);
4324           for (j=0;j<n;j++) {
4325             PetscScalar val = vals[j];
4326             PetscInt k;
4327             for (k=0;k<n_vertices;k++) {
4328               marr[idxs[j]+k*n_vertices] += val*sums[k];
4329             }
4330           }
4331           ierr = MatRestoreRow(A_RV_bcorr,i,&n,&idxs,&vals);CHKERRQ(ierr);
4332           ierr = ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i],&idxs_zero);CHKERRQ(ierr);
4333         }
4334         ierr = PetscFree(sums);CHKERRQ(ierr);
4335         ierr = MatDenseRestoreArray(S_VVt,&marr);CHKERRQ(ierr);
4336         ierr = MatDestroy(&A_RV_bcorr);CHKERRQ(ierr);
4337       }
4338       ierr = MatDestroy(&A_RRmA_RV);CHKERRQ(ierr);
4339       ierr = PetscBLASIntCast(n_vertices*n_vertices,&B_N);CHKERRQ(ierr);
4340       ierr = MatDenseGetArray(A_VV,&x);CHKERRQ(ierr);
4341       ierr = MatDenseGetArray(S_VVt,&y);CHKERRQ(ierr);
4342       PetscStackCallBLAS("BLASaxpy",BLASaxpy_(&B_N,&one,x,&B_one,y,&B_one));
4343       ierr = MatDenseRestoreArray(A_VV,&x);CHKERRQ(ierr);
4344       ierr = MatDenseRestoreArray(S_VVt,&y);CHKERRQ(ierr);
4345       ierr = MatCopy(S_VVt,S_VV,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
4346       ierr = MatDestroy(&S_VVt);CHKERRQ(ierr);
4347     } else {
4348       ierr = MatCopy(A_VV,S_VV,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
4349     }
4350     ierr = MatDestroy(&A_VV);CHKERRQ(ierr);
4351 
4352     /* coarse basis functions */
4353     for (i=0;i<n_vertices;i++) {
4354       PetscScalar *y;
4355 
4356       ierr = VecPlaceArray(pcbddc->vec1_R,work+lda_rhs*i);CHKERRQ(ierr);
4357       ierr = MatDenseGetArray(pcbddc->coarse_phi_B,&y);CHKERRQ(ierr);
4358       ierr = VecPlaceArray(pcis->vec1_B,y+n_B*i);CHKERRQ(ierr);
4359       ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4360       ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4361       y[n_B*i+idx_V_B[i]] = 1.0;
4362       ierr = MatDenseRestoreArray(pcbddc->coarse_phi_B,&y);CHKERRQ(ierr);
4363       ierr = VecResetArray(pcis->vec1_B);CHKERRQ(ierr);
4364 
4365       if (pcbddc->switch_static || pcbddc->dbg_flag) {
4366         PetscInt j;
4367 
4368         ierr = MatDenseGetArray(pcbddc->coarse_phi_D,&y);CHKERRQ(ierr);
4369         ierr = VecPlaceArray(pcis->vec1_D,y+n_D*i);CHKERRQ(ierr);
4370         ierr = VecScatterBegin(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4371         ierr = VecScatterEnd(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4372         ierr = VecResetArray(pcis->vec1_D);CHKERRQ(ierr);
4373         for (j=0;j<pcbddc->benign_n;j++) y[n_D*i+p0_lidx_I[j]] = 0.0;
4374         ierr = MatDenseRestoreArray(pcbddc->coarse_phi_D,&y);CHKERRQ(ierr);
4375       }
4376       ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4377     }
4378     /* if n_R == 0 the object is not destroyed */
4379     ierr = MatDestroy(&A_RV);CHKERRQ(ierr);
4380   }
4381   ierr = VecDestroy(&dummy_vec);CHKERRQ(ierr);
4382 
4383   if (n_constraints) {
4384     Mat B;
4385 
4386     ierr = MatCreateSeqDense(PETSC_COMM_SELF,lda_rhs,n_constraints,work,&B);CHKERRQ(ierr);
4387     ierr = MatScale(S_CC,m_one);CHKERRQ(ierr);
4388     ierr = MatMatMult(local_auxmat2_R,S_CC,MAT_REUSE_MATRIX,PETSC_DEFAULT,&B);CHKERRQ(ierr);
4389     ierr = MatScale(S_CC,m_one);CHKERRQ(ierr);
4390     if (n_vertices) {
4391       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
4392         ierr = MatTranspose(S_CV,MAT_REUSE_MATRIX,&S_VC);CHKERRQ(ierr);
4393       } else {
4394         Mat S_VCt;
4395 
4396         if (lda_rhs != n_R) {
4397           ierr = MatDestroy(&B);CHKERRQ(ierr);
4398           ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_R,n_constraints,work,&B);CHKERRQ(ierr);
4399           ierr = MatSeqDenseSetLDA(B,lda_rhs);CHKERRQ(ierr);
4400         }
4401         ierr = MatMatMult(A_VR,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&S_VCt);CHKERRQ(ierr);
4402         ierr = MatCopy(S_VCt,S_VC,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
4403         ierr = MatDestroy(&S_VCt);CHKERRQ(ierr);
4404       }
4405     }
4406     ierr = MatDestroy(&B);CHKERRQ(ierr);
4407     /* coarse basis functions */
4408     for (i=0;i<n_constraints;i++) {
4409       PetscScalar *y;
4410 
4411       ierr = VecPlaceArray(pcbddc->vec1_R,work+lda_rhs*i);CHKERRQ(ierr);
4412       ierr = MatDenseGetArray(pcbddc->coarse_phi_B,&y);CHKERRQ(ierr);
4413       ierr = VecPlaceArray(pcis->vec1_B,y+n_B*(i+n_vertices));CHKERRQ(ierr);
4414       ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4415       ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4416       ierr = MatDenseRestoreArray(pcbddc->coarse_phi_B,&y);CHKERRQ(ierr);
4417       ierr = VecResetArray(pcis->vec1_B);CHKERRQ(ierr);
4418       if (pcbddc->switch_static || pcbddc->dbg_flag) {
4419         PetscInt j;
4420 
4421         ierr = MatDenseGetArray(pcbddc->coarse_phi_D,&y);CHKERRQ(ierr);
4422         ierr = VecPlaceArray(pcis->vec1_D,y+n_D*(i+n_vertices));CHKERRQ(ierr);
4423         ierr = VecScatterBegin(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4424         ierr = VecScatterEnd(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4425         ierr = VecResetArray(pcis->vec1_D);CHKERRQ(ierr);
4426         for (j=0;j<pcbddc->benign_n;j++) y[n_D*i+p0_lidx_I[j]] = 0.0;
4427         ierr = MatDenseRestoreArray(pcbddc->coarse_phi_D,&y);CHKERRQ(ierr);
4428       }
4429       ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4430     }
4431   }
4432   if (n_constraints) {
4433     ierr = MatDestroy(&local_auxmat2_R);CHKERRQ(ierr);
4434   }
4435   ierr = PetscFree(p0_lidx_I);CHKERRQ(ierr);
4436 
4437   /* coarse matrix entries relative to B_0 */
4438   if (pcbddc->benign_n) {
4439     Mat         B0_B,B0_BPHI;
4440     IS          is_dummy;
4441     PetscScalar *data;
4442     PetscInt    j;
4443 
4444     ierr = ISCreateStride(PETSC_COMM_SELF,pcbddc->benign_n,0,1,&is_dummy);CHKERRQ(ierr);
4445     ierr = MatCreateSubMatrix(pcbddc->benign_B0,is_dummy,pcis->is_B_local,MAT_INITIAL_MATRIX,&B0_B);CHKERRQ(ierr);
4446     ierr = ISDestroy(&is_dummy);CHKERRQ(ierr);
4447     ierr = MatMatMult(B0_B,pcbddc->coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&B0_BPHI);CHKERRQ(ierr);
4448     ierr = MatConvert(B0_BPHI,MATSEQDENSE,MAT_INPLACE_MATRIX,&B0_BPHI);CHKERRQ(ierr);
4449     ierr = MatDenseGetArray(B0_BPHI,&data);CHKERRQ(ierr);
4450     for (j=0;j<pcbddc->benign_n;j++) {
4451       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
4452       for (i=0;i<pcbddc->local_primal_size;i++) {
4453         coarse_submat_vals[primal_idx*pcbddc->local_primal_size+i] = data[i*pcbddc->benign_n+j];
4454         coarse_submat_vals[i*pcbddc->local_primal_size+primal_idx] = data[i*pcbddc->benign_n+j];
4455       }
4456     }
4457     ierr = MatDenseRestoreArray(B0_BPHI,&data);CHKERRQ(ierr);
4458     ierr = MatDestroy(&B0_B);CHKERRQ(ierr);
4459     ierr = MatDestroy(&B0_BPHI);CHKERRQ(ierr);
4460   }
4461 
4462   /* compute other basis functions for non-symmetric problems */
4463   if (!pcbddc->symmetric_primal) {
4464     Mat         B_V=NULL,B_C=NULL;
4465     PetscScalar *marray;
4466 
4467     if (n_constraints) {
4468       Mat S_CCT,C_CRT;
4469 
4470       ierr = MatTranspose(C_CR,MAT_INITIAL_MATRIX,&C_CRT);CHKERRQ(ierr);
4471       ierr = MatTranspose(S_CC,MAT_INITIAL_MATRIX,&S_CCT);CHKERRQ(ierr);
4472       ierr = MatMatMult(C_CRT,S_CCT,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B_C);CHKERRQ(ierr);
4473       ierr = MatDestroy(&S_CCT);CHKERRQ(ierr);
4474       if (n_vertices) {
4475         Mat S_VCT;
4476 
4477         ierr = MatTranspose(S_VC,MAT_INITIAL_MATRIX,&S_VCT);CHKERRQ(ierr);
4478         ierr = MatMatMult(C_CRT,S_VCT,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B_V);CHKERRQ(ierr);
4479         ierr = MatDestroy(&S_VCT);CHKERRQ(ierr);
4480       }
4481       ierr = MatDestroy(&C_CRT);CHKERRQ(ierr);
4482     } else {
4483       ierr = MatCreateSeqDense(PETSC_COMM_SELF,n_R,n_vertices,NULL,&B_V);CHKERRQ(ierr);
4484     }
4485     if (n_vertices && n_R) {
4486       PetscScalar    *av,*marray;
4487       const PetscInt *xadj,*adjncy;
4488       PetscInt       n;
4489       PetscBool      flg_row;
4490 
4491       /* B_V = B_V - A_VR^T */
4492       ierr = MatConvert(A_VR,MATSEQAIJ,MAT_INPLACE_MATRIX,&A_VR);CHKERRQ(ierr);
4493       ierr = MatGetRowIJ(A_VR,0,PETSC_FALSE,PETSC_FALSE,&n,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
4494       ierr = MatSeqAIJGetArray(A_VR,&av);CHKERRQ(ierr);
4495       ierr = MatDenseGetArray(B_V,&marray);CHKERRQ(ierr);
4496       for (i=0;i<n;i++) {
4497         PetscInt j;
4498         for (j=xadj[i];j<xadj[i+1];j++) marray[i*n_R + adjncy[j]] -= av[j];
4499       }
4500       ierr = MatDenseRestoreArray(B_V,&marray);CHKERRQ(ierr);
4501       ierr = MatRestoreRowIJ(A_VR,0,PETSC_FALSE,PETSC_FALSE,&n,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
4502       ierr = MatDestroy(&A_VR);CHKERRQ(ierr);
4503     }
4504 
4505     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
4506     if (n_vertices) {
4507       ierr = MatDenseGetArray(B_V,&marray);CHKERRQ(ierr);
4508       for (i=0;i<n_vertices;i++) {
4509         ierr = VecPlaceArray(pcbddc->vec1_R,marray+i*n_R);CHKERRQ(ierr);
4510         ierr = VecPlaceArray(pcbddc->vec2_R,work+i*n_R);CHKERRQ(ierr);
4511         ierr = KSPSolveTranspose(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec2_R);CHKERRQ(ierr);
4512         ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4513         ierr = VecResetArray(pcbddc->vec2_R);CHKERRQ(ierr);
4514       }
4515       ierr = MatDenseRestoreArray(B_V,&marray);CHKERRQ(ierr);
4516     }
4517     if (B_C) {
4518       ierr = MatDenseGetArray(B_C,&marray);CHKERRQ(ierr);
4519       for (i=n_vertices;i<n_constraints+n_vertices;i++) {
4520         ierr = VecPlaceArray(pcbddc->vec1_R,marray+(i-n_vertices)*n_R);CHKERRQ(ierr);
4521         ierr = VecPlaceArray(pcbddc->vec2_R,work+i*n_R);CHKERRQ(ierr);
4522         ierr = KSPSolveTranspose(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec2_R);CHKERRQ(ierr);
4523         ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4524         ierr = VecResetArray(pcbddc->vec2_R);CHKERRQ(ierr);
4525       }
4526       ierr = MatDenseRestoreArray(B_C,&marray);CHKERRQ(ierr);
4527     }
4528     /* coarse basis functions */
4529     for (i=0;i<pcbddc->local_primal_size;i++) {
4530       PetscScalar *y;
4531 
4532       ierr = VecPlaceArray(pcbddc->vec1_R,work+i*n_R);CHKERRQ(ierr);
4533       ierr = MatDenseGetArray(pcbddc->coarse_psi_B,&y);CHKERRQ(ierr);
4534       ierr = VecPlaceArray(pcis->vec1_B,y+n_B*i);CHKERRQ(ierr);
4535       ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4536       ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4537       if (i<n_vertices) {
4538         y[n_B*i+idx_V_B[i]] = 1.0;
4539       }
4540       ierr = MatDenseRestoreArray(pcbddc->coarse_psi_B,&y);CHKERRQ(ierr);
4541       ierr = VecResetArray(pcis->vec1_B);CHKERRQ(ierr);
4542 
4543       if (pcbddc->switch_static || pcbddc->dbg_flag) {
4544         ierr = MatDenseGetArray(pcbddc->coarse_psi_D,&y);CHKERRQ(ierr);
4545         ierr = VecPlaceArray(pcis->vec1_D,y+n_D*i);CHKERRQ(ierr);
4546         ierr = VecScatterBegin(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4547         ierr = VecScatterEnd(pcbddc->R_to_D,pcbddc->vec1_R,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4548         ierr = VecResetArray(pcis->vec1_D);CHKERRQ(ierr);
4549         ierr = MatDenseRestoreArray(pcbddc->coarse_psi_D,&y);CHKERRQ(ierr);
4550       }
4551       ierr = VecResetArray(pcbddc->vec1_R);CHKERRQ(ierr);
4552     }
4553     ierr = MatDestroy(&B_V);CHKERRQ(ierr);
4554     ierr = MatDestroy(&B_C);CHKERRQ(ierr);
4555   }
4556 
4557   /* free memory */
4558   ierr = PetscFree(idx_V_B);CHKERRQ(ierr);
4559   ierr = MatDestroy(&S_VV);CHKERRQ(ierr);
4560   ierr = MatDestroy(&S_CV);CHKERRQ(ierr);
4561   ierr = MatDestroy(&S_VC);CHKERRQ(ierr);
4562   ierr = MatDestroy(&S_CC);CHKERRQ(ierr);
4563   ierr = PetscFree(work);CHKERRQ(ierr);
4564   if (n_vertices) {
4565     ierr = MatDestroy(&A_VR);CHKERRQ(ierr);
4566   }
4567   if (n_constraints) {
4568     ierr = MatDestroy(&C_CR);CHKERRQ(ierr);
4569   }
4570   /* Checking coarse_sub_mat and coarse basis functios */
4571   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
4572   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
4573   if (pcbddc->dbg_flag) {
4574     Mat         coarse_sub_mat;
4575     Mat         AUXMAT,TM1,TM2,TM3,TM4;
4576     Mat         coarse_phi_D,coarse_phi_B;
4577     Mat         coarse_psi_D,coarse_psi_B;
4578     Mat         A_II,A_BB,A_IB,A_BI;
4579     Mat         C_B,CPHI;
4580     IS          is_dummy;
4581     Vec         mones;
4582     MatType     checkmattype=MATSEQAIJ;
4583     PetscReal   real_value;
4584 
4585     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
4586       Mat A;
4587       ierr = PCBDDCBenignProject(pc,NULL,NULL,&A);CHKERRQ(ierr);
4588       ierr = MatCreateSubMatrix(A,pcis->is_I_local,pcis->is_I_local,MAT_INITIAL_MATRIX,&A_II);CHKERRQ(ierr);
4589       ierr = MatCreateSubMatrix(A,pcis->is_I_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&A_IB);CHKERRQ(ierr);
4590       ierr = MatCreateSubMatrix(A,pcis->is_B_local,pcis->is_I_local,MAT_INITIAL_MATRIX,&A_BI);CHKERRQ(ierr);
4591       ierr = MatCreateSubMatrix(A,pcis->is_B_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&A_BB);CHKERRQ(ierr);
4592       ierr = MatDestroy(&A);CHKERRQ(ierr);
4593     } else {
4594       ierr = MatConvert(pcis->A_II,checkmattype,MAT_INITIAL_MATRIX,&A_II);CHKERRQ(ierr);
4595       ierr = MatConvert(pcis->A_IB,checkmattype,MAT_INITIAL_MATRIX,&A_IB);CHKERRQ(ierr);
4596       ierr = MatConvert(pcis->A_BI,checkmattype,MAT_INITIAL_MATRIX,&A_BI);CHKERRQ(ierr);
4597       ierr = MatConvert(pcis->A_BB,checkmattype,MAT_INITIAL_MATRIX,&A_BB);CHKERRQ(ierr);
4598     }
4599     ierr = MatConvert(pcbddc->coarse_phi_D,checkmattype,MAT_INITIAL_MATRIX,&coarse_phi_D);CHKERRQ(ierr);
4600     ierr = MatConvert(pcbddc->coarse_phi_B,checkmattype,MAT_INITIAL_MATRIX,&coarse_phi_B);CHKERRQ(ierr);
4601     if (!pcbddc->symmetric_primal) {
4602       ierr = MatConvert(pcbddc->coarse_psi_D,checkmattype,MAT_INITIAL_MATRIX,&coarse_psi_D);CHKERRQ(ierr);
4603       ierr = MatConvert(pcbddc->coarse_psi_B,checkmattype,MAT_INITIAL_MATRIX,&coarse_psi_B);CHKERRQ(ierr);
4604     }
4605     ierr = MatCreateSeqDense(PETSC_COMM_SELF,pcbddc->local_primal_size,pcbddc->local_primal_size,coarse_submat_vals,&coarse_sub_mat);CHKERRQ(ierr);
4606 
4607     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
4608     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Check coarse sub mat computation (symmetric %d)\n",pcbddc->symmetric_primal);CHKERRQ(ierr);
4609     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
4610     if (!pcbddc->symmetric_primal) {
4611       ierr = MatMatMult(A_II,coarse_phi_D,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4612       ierr = MatTransposeMatMult(coarse_psi_D,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM1);CHKERRQ(ierr);
4613       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4614       ierr = MatMatMult(A_BB,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4615       ierr = MatTransposeMatMult(coarse_psi_B,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM2);CHKERRQ(ierr);
4616       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4617       ierr = MatMatMult(A_IB,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4618       ierr = MatTransposeMatMult(coarse_psi_D,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM3);CHKERRQ(ierr);
4619       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4620       ierr = MatMatMult(A_BI,coarse_phi_D,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4621       ierr = MatTransposeMatMult(coarse_psi_B,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM4);CHKERRQ(ierr);
4622       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4623     } else {
4624       ierr = MatPtAP(A_II,coarse_phi_D,MAT_INITIAL_MATRIX,1.0,&TM1);CHKERRQ(ierr);
4625       ierr = MatPtAP(A_BB,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&TM2);CHKERRQ(ierr);
4626       ierr = MatMatMult(A_IB,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4627       ierr = MatTransposeMatMult(coarse_phi_D,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM3);CHKERRQ(ierr);
4628       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4629       ierr = MatMatMult(A_BI,coarse_phi_D,MAT_INITIAL_MATRIX,1.0,&AUXMAT);CHKERRQ(ierr);
4630       ierr = MatTransposeMatMult(coarse_phi_B,AUXMAT,MAT_INITIAL_MATRIX,1.0,&TM4);CHKERRQ(ierr);
4631       ierr = MatDestroy(&AUXMAT);CHKERRQ(ierr);
4632     }
4633     ierr = MatAXPY(TM1,one,TM2,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
4634     ierr = MatAXPY(TM1,one,TM3,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
4635     ierr = MatAXPY(TM1,one,TM4,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
4636     ierr = MatConvert(TM1,MATSEQDENSE,MAT_INPLACE_MATRIX,&TM1);CHKERRQ(ierr);
4637     if (pcbddc->benign_n) {
4638       Mat         B0_B,B0_BPHI;
4639       PetscScalar *data,*data2;
4640       PetscInt    j;
4641 
4642       ierr = ISCreateStride(PETSC_COMM_SELF,pcbddc->benign_n,0,1,&is_dummy);CHKERRQ(ierr);
4643       ierr = MatCreateSubMatrix(pcbddc->benign_B0,is_dummy,pcis->is_B_local,MAT_INITIAL_MATRIX,&B0_B);CHKERRQ(ierr);
4644       ierr = MatMatMult(B0_B,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&B0_BPHI);CHKERRQ(ierr);
4645       ierr = MatConvert(B0_BPHI,MATSEQDENSE,MAT_INPLACE_MATRIX,&B0_BPHI);CHKERRQ(ierr);
4646       ierr = MatDenseGetArray(TM1,&data);CHKERRQ(ierr);
4647       ierr = MatDenseGetArray(B0_BPHI,&data2);CHKERRQ(ierr);
4648       for (j=0;j<pcbddc->benign_n;j++) {
4649         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
4650         for (i=0;i<pcbddc->local_primal_size;i++) {
4651           data[primal_idx*pcbddc->local_primal_size+i] += data2[i*pcbddc->benign_n+j];
4652           data[i*pcbddc->local_primal_size+primal_idx] += data2[i*pcbddc->benign_n+j];
4653         }
4654       }
4655       ierr = MatDenseRestoreArray(TM1,&data);CHKERRQ(ierr);
4656       ierr = MatDenseRestoreArray(B0_BPHI,&data2);CHKERRQ(ierr);
4657       ierr = MatDestroy(&B0_B);CHKERRQ(ierr);
4658       ierr = ISDestroy(&is_dummy);CHKERRQ(ierr);
4659       ierr = MatDestroy(&B0_BPHI);CHKERRQ(ierr);
4660     }
4661 #if 0
4662   {
4663     PetscViewer viewer;
4664     char filename[256];
4665     sprintf(filename,"details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level);
4666     ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer);CHKERRQ(ierr);
4667     ierr = PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr);
4668     ierr = PetscObjectSetName((PetscObject)coarse_sub_mat,"computed");CHKERRQ(ierr);
4669     ierr = MatView(coarse_sub_mat,viewer);CHKERRQ(ierr);
4670     ierr = PetscObjectSetName((PetscObject)TM1,"projected");CHKERRQ(ierr);
4671     ierr = MatView(TM1,viewer);CHKERRQ(ierr);
4672     if (pcbddc->coarse_phi_B) {
4673       ierr = PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B");CHKERRQ(ierr);
4674       ierr = MatView(pcbddc->coarse_phi_B,viewer);CHKERRQ(ierr);
4675     }
4676     if (pcbddc->coarse_phi_D) {
4677       ierr = PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D");CHKERRQ(ierr);
4678       ierr = MatView(pcbddc->coarse_phi_D,viewer);CHKERRQ(ierr);
4679     }
4680     if (pcbddc->coarse_psi_B) {
4681       ierr = PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B");CHKERRQ(ierr);
4682       ierr = MatView(pcbddc->coarse_psi_B,viewer);CHKERRQ(ierr);
4683     }
4684     if (pcbddc->coarse_psi_D) {
4685       ierr = PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D");CHKERRQ(ierr);
4686       ierr = MatView(pcbddc->coarse_psi_D,viewer);CHKERRQ(ierr);
4687     }
4688     ierr = PetscObjectSetName((PetscObject)pcbddc->local_mat,"A");CHKERRQ(ierr);
4689     ierr = MatView(pcbddc->local_mat,viewer);CHKERRQ(ierr);
4690     ierr = PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C");CHKERRQ(ierr);
4691     ierr = MatView(pcbddc->ConstraintMatrix,viewer);CHKERRQ(ierr);
4692     ierr = PetscObjectSetName((PetscObject)pcis->is_I_local,"I");CHKERRQ(ierr);
4693     ierr = ISView(pcis->is_I_local,viewer);CHKERRQ(ierr);
4694     ierr = PetscObjectSetName((PetscObject)pcis->is_B_local,"B");CHKERRQ(ierr);
4695     ierr = ISView(pcis->is_B_local,viewer);CHKERRQ(ierr);
4696     ierr = PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R");CHKERRQ(ierr);
4697     ierr = ISView(pcbddc->is_R_local,viewer);CHKERRQ(ierr);
4698     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
4699   }
4700 #endif
4701     ierr = MatAXPY(TM1,m_one,coarse_sub_mat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
4702     ierr = MatNorm(TM1,NORM_FROBENIUS,&real_value);CHKERRQ(ierr);
4703     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
4704     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d          matrix error % 1.14e\n",PetscGlobalRank,real_value);CHKERRQ(ierr);
4705 
4706     /* check constraints */
4707     ierr = ISCreateStride(PETSC_COMM_SELF,pcbddc->local_primal_size-pcbddc->benign_n,0,1,&is_dummy);CHKERRQ(ierr);
4708     ierr = MatCreateSubMatrix(pcbddc->ConstraintMatrix,is_dummy,pcis->is_B_local,MAT_INITIAL_MATRIX,&C_B);CHKERRQ(ierr);
4709     if (!pcbddc->benign_n) { /* TODO: add benign case */
4710       ierr = MatMatMult(C_B,coarse_phi_B,MAT_INITIAL_MATRIX,1.0,&CPHI);CHKERRQ(ierr);
4711     } else {
4712       PetscScalar *data;
4713       Mat         tmat;
4714       ierr = MatDenseGetArray(pcbddc->coarse_phi_B,&data);CHKERRQ(ierr);
4715       ierr = MatCreateSeqDense(PETSC_COMM_SELF,pcis->n_B,pcbddc->local_primal_size-pcbddc->benign_n,data,&tmat);CHKERRQ(ierr);
4716       ierr = MatDenseRestoreArray(pcbddc->coarse_phi_B,&data);CHKERRQ(ierr);
4717       ierr = MatMatMult(C_B,tmat,MAT_INITIAL_MATRIX,1.0,&CPHI);CHKERRQ(ierr);
4718       ierr = MatDestroy(&tmat);CHKERRQ(ierr);
4719     }
4720     ierr = MatCreateVecs(CPHI,&mones,NULL);CHKERRQ(ierr);
4721     ierr = VecSet(mones,-1.0);CHKERRQ(ierr);
4722     ierr = MatDiagonalSet(CPHI,mones,ADD_VALUES);CHKERRQ(ierr);
4723     ierr = MatNorm(CPHI,NORM_FROBENIUS,&real_value);CHKERRQ(ierr);
4724     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d phi constraints error % 1.14e\n",PetscGlobalRank,real_value);CHKERRQ(ierr);
4725     if (!pcbddc->symmetric_primal) {
4726       ierr = MatMatMult(C_B,coarse_psi_B,MAT_REUSE_MATRIX,1.0,&CPHI);CHKERRQ(ierr);
4727       ierr = VecSet(mones,-1.0);CHKERRQ(ierr);
4728       ierr = MatDiagonalSet(CPHI,mones,ADD_VALUES);CHKERRQ(ierr);
4729       ierr = MatNorm(CPHI,NORM_FROBENIUS,&real_value);CHKERRQ(ierr);
4730       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d psi constraints error % 1.14e\n",PetscGlobalRank,real_value);CHKERRQ(ierr);
4731     }
4732     ierr = MatDestroy(&C_B);CHKERRQ(ierr);
4733     ierr = MatDestroy(&CPHI);CHKERRQ(ierr);
4734     ierr = ISDestroy(&is_dummy);CHKERRQ(ierr);
4735     ierr = VecDestroy(&mones);CHKERRQ(ierr);
4736     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
4737     ierr = MatDestroy(&A_II);CHKERRQ(ierr);
4738     ierr = MatDestroy(&A_BB);CHKERRQ(ierr);
4739     ierr = MatDestroy(&A_IB);CHKERRQ(ierr);
4740     ierr = MatDestroy(&A_BI);CHKERRQ(ierr);
4741     ierr = MatDestroy(&TM1);CHKERRQ(ierr);
4742     ierr = MatDestroy(&TM2);CHKERRQ(ierr);
4743     ierr = MatDestroy(&TM3);CHKERRQ(ierr);
4744     ierr = MatDestroy(&TM4);CHKERRQ(ierr);
4745     ierr = MatDestroy(&coarse_phi_D);CHKERRQ(ierr);
4746     ierr = MatDestroy(&coarse_phi_B);CHKERRQ(ierr);
4747     if (!pcbddc->symmetric_primal) {
4748       ierr = MatDestroy(&coarse_psi_D);CHKERRQ(ierr);
4749       ierr = MatDestroy(&coarse_psi_B);CHKERRQ(ierr);
4750     }
4751     ierr = MatDestroy(&coarse_sub_mat);CHKERRQ(ierr);
4752   }
4753   /* get back data */
4754   *coarse_submat_vals_n = coarse_submat_vals;
4755   ierr = PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
4756   PetscFunctionReturn(0);
4757 }
4758 
4759 PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat* B)
4760 {
4761   Mat            *work_mat;
4762   IS             isrow_s,iscol_s;
4763   PetscBool      rsorted,csorted;
4764   PetscInt       rsize,*idxs_perm_r=NULL,csize,*idxs_perm_c=NULL;
4765   PetscErrorCode ierr;
4766 
4767   PetscFunctionBegin;
4768   ierr = ISSorted(isrow,&rsorted);CHKERRQ(ierr);
4769   ierr = ISSorted(iscol,&csorted);CHKERRQ(ierr);
4770   ierr = ISGetLocalSize(isrow,&rsize);CHKERRQ(ierr);
4771   ierr = ISGetLocalSize(iscol,&csize);CHKERRQ(ierr);
4772 
4773   if (!rsorted) {
4774     const PetscInt *idxs;
4775     PetscInt *idxs_sorted,i;
4776 
4777     ierr = PetscMalloc1(rsize,&idxs_perm_r);CHKERRQ(ierr);
4778     ierr = PetscMalloc1(rsize,&idxs_sorted);CHKERRQ(ierr);
4779     for (i=0;i<rsize;i++) {
4780       idxs_perm_r[i] = i;
4781     }
4782     ierr = ISGetIndices(isrow,&idxs);CHKERRQ(ierr);
4783     ierr = PetscSortIntWithPermutation(rsize,idxs,idxs_perm_r);CHKERRQ(ierr);
4784     for (i=0;i<rsize;i++) {
4785       idxs_sorted[i] = idxs[idxs_perm_r[i]];
4786     }
4787     ierr = ISRestoreIndices(isrow,&idxs);CHKERRQ(ierr);
4788     ierr = ISCreateGeneral(PETSC_COMM_SELF,rsize,idxs_sorted,PETSC_OWN_POINTER,&isrow_s);CHKERRQ(ierr);
4789   } else {
4790     ierr = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
4791     isrow_s = isrow;
4792   }
4793 
4794   if (!csorted) {
4795     if (isrow == iscol) {
4796       ierr = PetscObjectReference((PetscObject)isrow_s);CHKERRQ(ierr);
4797       iscol_s = isrow_s;
4798     } else {
4799       const PetscInt *idxs;
4800       PetscInt       *idxs_sorted,i;
4801 
4802       ierr = PetscMalloc1(csize,&idxs_perm_c);CHKERRQ(ierr);
4803       ierr = PetscMalloc1(csize,&idxs_sorted);CHKERRQ(ierr);
4804       for (i=0;i<csize;i++) {
4805         idxs_perm_c[i] = i;
4806       }
4807       ierr = ISGetIndices(iscol,&idxs);CHKERRQ(ierr);
4808       ierr = PetscSortIntWithPermutation(csize,idxs,idxs_perm_c);CHKERRQ(ierr);
4809       for (i=0;i<csize;i++) {
4810         idxs_sorted[i] = idxs[idxs_perm_c[i]];
4811       }
4812       ierr = ISRestoreIndices(iscol,&idxs);CHKERRQ(ierr);
4813       ierr = ISCreateGeneral(PETSC_COMM_SELF,csize,idxs_sorted,PETSC_OWN_POINTER,&iscol_s);CHKERRQ(ierr);
4814     }
4815   } else {
4816     ierr = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
4817     iscol_s = iscol;
4818   }
4819 
4820   ierr = MatCreateSubMatrices(A,1,&isrow_s,&iscol_s,MAT_INITIAL_MATRIX,&work_mat);CHKERRQ(ierr);
4821 
4822   if (!rsorted || !csorted) {
4823     Mat      new_mat;
4824     IS       is_perm_r,is_perm_c;
4825 
4826     if (!rsorted) {
4827       PetscInt *idxs_r,i;
4828       ierr = PetscMalloc1(rsize,&idxs_r);CHKERRQ(ierr);
4829       for (i=0;i<rsize;i++) {
4830         idxs_r[idxs_perm_r[i]] = i;
4831       }
4832       ierr = PetscFree(idxs_perm_r);CHKERRQ(ierr);
4833       ierr = ISCreateGeneral(PETSC_COMM_SELF,rsize,idxs_r,PETSC_OWN_POINTER,&is_perm_r);CHKERRQ(ierr);
4834     } else {
4835       ierr = ISCreateStride(PETSC_COMM_SELF,rsize,0,1,&is_perm_r);CHKERRQ(ierr);
4836     }
4837     ierr = ISSetPermutation(is_perm_r);CHKERRQ(ierr);
4838 
4839     if (!csorted) {
4840       if (isrow_s == iscol_s) {
4841         ierr = PetscObjectReference((PetscObject)is_perm_r);CHKERRQ(ierr);
4842         is_perm_c = is_perm_r;
4843       } else {
4844         PetscInt *idxs_c,i;
4845         if (!idxs_perm_c) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Permutation array not present");
4846         ierr = PetscMalloc1(csize,&idxs_c);CHKERRQ(ierr);
4847         for (i=0;i<csize;i++) {
4848           idxs_c[idxs_perm_c[i]] = i;
4849         }
4850         ierr = PetscFree(idxs_perm_c);CHKERRQ(ierr);
4851         ierr = ISCreateGeneral(PETSC_COMM_SELF,csize,idxs_c,PETSC_OWN_POINTER,&is_perm_c);CHKERRQ(ierr);
4852       }
4853     } else {
4854       ierr = ISCreateStride(PETSC_COMM_SELF,csize,0,1,&is_perm_c);CHKERRQ(ierr);
4855     }
4856     ierr = ISSetPermutation(is_perm_c);CHKERRQ(ierr);
4857 
4858     ierr = MatPermute(work_mat[0],is_perm_r,is_perm_c,&new_mat);CHKERRQ(ierr);
4859     ierr = MatDestroy(&work_mat[0]);CHKERRQ(ierr);
4860     work_mat[0] = new_mat;
4861     ierr = ISDestroy(&is_perm_r);CHKERRQ(ierr);
4862     ierr = ISDestroy(&is_perm_c);CHKERRQ(ierr);
4863   }
4864 
4865   ierr = PetscObjectReference((PetscObject)work_mat[0]);CHKERRQ(ierr);
4866   *B = work_mat[0];
4867   ierr = MatDestroyMatrices(1,&work_mat);CHKERRQ(ierr);
4868   ierr = ISDestroy(&isrow_s);CHKERRQ(ierr);
4869   ierr = ISDestroy(&iscol_s);CHKERRQ(ierr);
4870   PetscFunctionReturn(0);
4871 }
4872 
4873 PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
4874 {
4875   Mat_IS*        matis = (Mat_IS*)pc->pmat->data;
4876   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
4877   Mat            new_mat,lA;
4878   IS             is_local,is_global;
4879   PetscInt       local_size;
4880   PetscBool      isseqaij;
4881   PetscErrorCode ierr;
4882 
4883   PetscFunctionBegin;
4884   ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
4885   ierr = MatGetSize(matis->A,&local_size,NULL);CHKERRQ(ierr);
4886   ierr = ISCreateStride(PetscObjectComm((PetscObject)matis->A),local_size,0,1,&is_local);CHKERRQ(ierr);
4887   ierr = ISLocalToGlobalMappingApplyIS(pc->pmat->rmap->mapping,is_local,&is_global);CHKERRQ(ierr);
4888   ierr = ISDestroy(&is_local);CHKERRQ(ierr);
4889   ierr = MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix,is_global,is_global,&new_mat);CHKERRQ(ierr);
4890   ierr = ISDestroy(&is_global);CHKERRQ(ierr);
4891 
4892   /* check */
4893   if (pcbddc->dbg_flag) {
4894     Vec       x,x_change;
4895     PetscReal error;
4896 
4897     ierr = MatCreateVecs(ChangeOfBasisMatrix,&x,&x_change);CHKERRQ(ierr);
4898     ierr = VecSetRandom(x,NULL);CHKERRQ(ierr);
4899     ierr = MatMult(ChangeOfBasisMatrix,x,x_change);CHKERRQ(ierr);
4900     ierr = VecScatterBegin(matis->cctx,x,matis->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4901     ierr = VecScatterEnd(matis->cctx,x,matis->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4902     ierr = MatMult(new_mat,matis->x,matis->y);CHKERRQ(ierr);
4903     if (!pcbddc->change_interior) {
4904       const PetscScalar *x,*y,*v;
4905       PetscReal         lerror = 0.;
4906       PetscInt          i;
4907 
4908       ierr = VecGetArrayRead(matis->x,&x);CHKERRQ(ierr);
4909       ierr = VecGetArrayRead(matis->y,&y);CHKERRQ(ierr);
4910       ierr = VecGetArrayRead(matis->counter,&v);CHKERRQ(ierr);
4911       for (i=0;i<local_size;i++)
4912         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i]-y[i]) > lerror)
4913           lerror = PetscAbsScalar(x[i]-y[i]);
4914       ierr = VecRestoreArrayRead(matis->x,&x);CHKERRQ(ierr);
4915       ierr = VecRestoreArrayRead(matis->y,&y);CHKERRQ(ierr);
4916       ierr = VecRestoreArrayRead(matis->counter,&v);CHKERRQ(ierr);
4917       ierr = MPIU_Allreduce(&lerror,&error,1,MPIU_REAL,MPI_MAX,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
4918       if (error > PETSC_SMALL) {
4919         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
4920           SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Error global vs local change on I: %1.6e\n",error);
4921         } else {
4922           SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"Error global vs local change on I: %1.6e\n",error);
4923         }
4924       }
4925     }
4926     ierr = VecScatterBegin(matis->rctx,matis->y,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4927     ierr = VecScatterEnd(matis->rctx,matis->y,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4928     ierr = VecAXPY(x,-1.0,x_change);CHKERRQ(ierr);
4929     ierr = VecNorm(x,NORM_INFINITY,&error);CHKERRQ(ierr);
4930     if (error > PETSC_SMALL) {
4931       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
4932         SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Error global vs local change on N: %1.6e\n",error);
4933       } else {
4934         SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"Error global vs local change on N: %1.6e\n",error);
4935       }
4936     }
4937     ierr = VecDestroy(&x);CHKERRQ(ierr);
4938     ierr = VecDestroy(&x_change);CHKERRQ(ierr);
4939   }
4940 
4941   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
4942   ierr = PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_lA" ,(PetscObject*)&lA);CHKERRQ(ierr);
4943 
4944   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
4945   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
4946   if (isseqaij) {
4947     ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
4948     ierr = MatPtAP(matis->A,new_mat,MAT_INITIAL_MATRIX,2.0,&pcbddc->local_mat);CHKERRQ(ierr);
4949     if (lA) {
4950       Mat work;
4951       ierr = MatPtAP(lA,new_mat,MAT_INITIAL_MATRIX,2.0,&work);CHKERRQ(ierr);
4952       ierr = PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_lA" ,(PetscObject)work);CHKERRQ(ierr);
4953       ierr = MatDestroy(&work);CHKERRQ(ierr);
4954     }
4955   } else {
4956     Mat work_mat;
4957 
4958     ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
4959     ierr = MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&work_mat);CHKERRQ(ierr);
4960     ierr = MatPtAP(work_mat,new_mat,MAT_INITIAL_MATRIX,2.0,&pcbddc->local_mat);CHKERRQ(ierr);
4961     ierr = MatDestroy(&work_mat);CHKERRQ(ierr);
4962     if (lA) {
4963       Mat work;
4964       ierr = MatConvert(lA,MATSEQAIJ,MAT_INITIAL_MATRIX,&work_mat);CHKERRQ(ierr);
4965       ierr = MatPtAP(work_mat,new_mat,MAT_INITIAL_MATRIX,2.0,&work);CHKERRQ(ierr);
4966       ierr = PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_lA" ,(PetscObject)work);CHKERRQ(ierr);
4967       ierr = MatDestroy(&work);CHKERRQ(ierr);
4968     }
4969   }
4970   if (matis->A->symmetric_set) {
4971     ierr = MatSetOption(pcbddc->local_mat,MAT_SYMMETRIC,matis->A->symmetric);CHKERRQ(ierr);
4972 #if !defined(PETSC_USE_COMPLEX)
4973     ierr = MatSetOption(pcbddc->local_mat,MAT_HERMITIAN,matis->A->symmetric);CHKERRQ(ierr);
4974 #endif
4975   }
4976   ierr = MatDestroy(&new_mat);CHKERRQ(ierr);
4977   PetscFunctionReturn(0);
4978 }
4979 
4980 PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
4981 {
4982   PC_IS*          pcis = (PC_IS*)(pc->data);
4983   PC_BDDC*        pcbddc = (PC_BDDC*)pc->data;
4984   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
4985   PetscInt        *idx_R_local=NULL;
4986   PetscInt        n_vertices,i,j,n_R,n_D,n_B;
4987   PetscInt        vbs,bs;
4988   PetscBT         bitmask=NULL;
4989   PetscErrorCode  ierr;
4990 
4991   PetscFunctionBegin;
4992   /*
4993     No need to setup local scatters if
4994       - primal space is unchanged
4995         AND
4996       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
4997         AND
4998       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
4999   */
5000   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) {
5001     PetscFunctionReturn(0);
5002   }
5003   /* destroy old objects */
5004   ierr = ISDestroy(&pcbddc->is_R_local);CHKERRQ(ierr);
5005   ierr = VecScatterDestroy(&pcbddc->R_to_B);CHKERRQ(ierr);
5006   ierr = VecScatterDestroy(&pcbddc->R_to_D);CHKERRQ(ierr);
5007   /* Set Non-overlapping dimensions */
5008   n_B = pcis->n_B;
5009   n_D = pcis->n - n_B;
5010   n_vertices = pcbddc->n_vertices;
5011 
5012   /* Dohrmann's notation: dofs splitted in R (Remaining: all dofs but the vertices) and V (Vertices) */
5013 
5014   /* create auxiliary bitmask and allocate workspace */
5015   if (!sub_schurs || !sub_schurs->reuse_solver) {
5016     ierr = PetscMalloc1(pcis->n-n_vertices,&idx_R_local);CHKERRQ(ierr);
5017     ierr = PetscBTCreate(pcis->n,&bitmask);CHKERRQ(ierr);
5018     for (i=0;i<n_vertices;i++) {
5019       ierr = PetscBTSet(bitmask,pcbddc->local_primal_ref_node[i]);CHKERRQ(ierr);
5020     }
5021 
5022     for (i=0, n_R=0; i<pcis->n; i++) {
5023       if (!PetscBTLookup(bitmask,i)) {
5024         idx_R_local[n_R++] = i;
5025       }
5026     }
5027   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5028     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5029 
5030     ierr = ISGetIndices(reuse_solver->is_R,(const PetscInt**)&idx_R_local);CHKERRQ(ierr);
5031     ierr = ISGetLocalSize(reuse_solver->is_R,&n_R);CHKERRQ(ierr);
5032   }
5033 
5034   /* Block code */
5035   vbs = 1;
5036   ierr = MatGetBlockSize(pcbddc->local_mat,&bs);CHKERRQ(ierr);
5037   if (bs>1 && !(n_vertices%bs)) {
5038     PetscBool is_blocked = PETSC_TRUE;
5039     PetscInt  *vary;
5040     if (!sub_schurs || !sub_schurs->reuse_solver) {
5041       ierr = PetscMalloc1(pcis->n/bs,&vary);CHKERRQ(ierr);
5042       ierr = PetscMemzero(vary,pcis->n/bs*sizeof(PetscInt));CHKERRQ(ierr);
5043       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5044       /* it is ok to check this way since local_primal_ref_node are always sorted by local numbering and idx_R_local is obtained as a complement */
5045       for (i=0; i<n_vertices; i++) vary[pcbddc->local_primal_ref_node[i]/bs]++;
5046       for (i=0; i<pcis->n/bs; i++) {
5047         if (vary[i]!=0 && vary[i]!=bs) {
5048           is_blocked = PETSC_FALSE;
5049           break;
5050         }
5051       }
5052       ierr = PetscFree(vary);CHKERRQ(ierr);
5053     } else {
5054       /* Verify directly the R set */
5055       for (i=0; i<n_R/bs; i++) {
5056         PetscInt j,node=idx_R_local[bs*i];
5057         for (j=1; j<bs; j++) {
5058           if (node != idx_R_local[bs*i+j]-j) {
5059             is_blocked = PETSC_FALSE;
5060             break;
5061           }
5062         }
5063       }
5064     }
5065     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
5066       vbs = bs;
5067       for (i=0;i<n_R/vbs;i++) {
5068         idx_R_local[i] = idx_R_local[vbs*i]/vbs;
5069       }
5070     }
5071   }
5072   ierr = ISCreateBlock(PETSC_COMM_SELF,vbs,n_R/vbs,idx_R_local,PETSC_COPY_VALUES,&pcbddc->is_R_local);CHKERRQ(ierr);
5073   if (sub_schurs && sub_schurs->reuse_solver) {
5074     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5075 
5076     ierr = ISRestoreIndices(reuse_solver->is_R,(const PetscInt**)&idx_R_local);CHKERRQ(ierr);
5077     ierr = ISDestroy(&reuse_solver->is_R);CHKERRQ(ierr);
5078     ierr = PetscObjectReference((PetscObject)pcbddc->is_R_local);CHKERRQ(ierr);
5079     reuse_solver->is_R = pcbddc->is_R_local;
5080   } else {
5081     ierr = PetscFree(idx_R_local);CHKERRQ(ierr);
5082   }
5083 
5084   /* print some info if requested */
5085   if (pcbddc->dbg_flag) {
5086     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
5087     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5088     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
5089     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d local dimensions\n",PetscGlobalRank);CHKERRQ(ierr);
5090     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"local_size = %d, dirichlet_size = %d, boundary_size = %d\n",pcis->n,n_D,n_B);CHKERRQ(ierr);
5091     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"r_size = %d, v_size = %d, constraints = %d, local_primal_size = %d\n",n_R,n_vertices,pcbddc->local_primal_size-n_vertices-pcbddc->benign_n,pcbddc->local_primal_size);CHKERRQ(ierr);
5092     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5093   }
5094 
5095   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5096   if (!sub_schurs || !sub_schurs->reuse_solver) {
5097     IS       is_aux1,is_aux2;
5098     PetscInt *aux_array1,*aux_array2,*is_indices,*idx_R_local;
5099 
5100     ierr = ISGetIndices(pcbddc->is_R_local,(const PetscInt**)&idx_R_local);CHKERRQ(ierr);
5101     ierr = PetscMalloc1(pcis->n_B-n_vertices,&aux_array1);CHKERRQ(ierr);
5102     ierr = PetscMalloc1(pcis->n_B-n_vertices,&aux_array2);CHKERRQ(ierr);
5103     ierr = ISGetIndices(pcis->is_I_local,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5104     for (i=0; i<n_D; i++) {
5105       ierr = PetscBTSet(bitmask,is_indices[i]);CHKERRQ(ierr);
5106     }
5107     ierr = ISRestoreIndices(pcis->is_I_local,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5108     for (i=0, j=0; i<n_R; i++) {
5109       if (!PetscBTLookup(bitmask,idx_R_local[i])) {
5110         aux_array1[j++] = i;
5111       }
5112     }
5113     ierr = ISCreateGeneral(PETSC_COMM_SELF,j,aux_array1,PETSC_OWN_POINTER,&is_aux1);CHKERRQ(ierr);
5114     ierr = ISGetIndices(pcis->is_B_local,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5115     for (i=0, j=0; i<n_B; i++) {
5116       if (!PetscBTLookup(bitmask,is_indices[i])) {
5117         aux_array2[j++] = i;
5118       }
5119     }
5120     ierr = ISRestoreIndices(pcis->is_B_local,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5121     ierr = ISCreateGeneral(PETSC_COMM_SELF,j,aux_array2,PETSC_OWN_POINTER,&is_aux2);CHKERRQ(ierr);
5122     ierr = VecScatterCreate(pcbddc->vec1_R,is_aux1,pcis->vec1_B,is_aux2,&pcbddc->R_to_B);CHKERRQ(ierr);
5123     ierr = ISDestroy(&is_aux1);CHKERRQ(ierr);
5124     ierr = ISDestroy(&is_aux2);CHKERRQ(ierr);
5125 
5126     if (pcbddc->switch_static || pcbddc->dbg_flag) {
5127       ierr = PetscMalloc1(n_D,&aux_array1);CHKERRQ(ierr);
5128       for (i=0, j=0; i<n_R; i++) {
5129         if (PetscBTLookup(bitmask,idx_R_local[i])) {
5130           aux_array1[j++] = i;
5131         }
5132       }
5133       ierr = ISCreateGeneral(PETSC_COMM_SELF,j,aux_array1,PETSC_OWN_POINTER,&is_aux1);CHKERRQ(ierr);
5134       ierr = VecScatterCreate(pcbddc->vec1_R,is_aux1,pcis->vec1_D,(IS)0,&pcbddc->R_to_D);CHKERRQ(ierr);
5135       ierr = ISDestroy(&is_aux1);CHKERRQ(ierr);
5136     }
5137     ierr = PetscBTDestroy(&bitmask);CHKERRQ(ierr);
5138     ierr = ISRestoreIndices(pcbddc->is_R_local,(const PetscInt**)&idx_R_local);CHKERRQ(ierr);
5139   } else {
5140     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5141     IS                 tis;
5142     PetscInt           schur_size;
5143 
5144     ierr = ISGetLocalSize(reuse_solver->is_B,&schur_size);CHKERRQ(ierr);
5145     ierr = ISCreateStride(PETSC_COMM_SELF,schur_size,n_D,1,&tis);CHKERRQ(ierr);
5146     ierr = VecScatterCreate(pcbddc->vec1_R,tis,pcis->vec1_B,reuse_solver->is_B,&pcbddc->R_to_B);CHKERRQ(ierr);
5147     ierr = ISDestroy(&tis);CHKERRQ(ierr);
5148     if (pcbddc->switch_static || pcbddc->dbg_flag) {
5149       ierr = ISCreateStride(PETSC_COMM_SELF,n_D,0,1,&tis);CHKERRQ(ierr);
5150       ierr = VecScatterCreate(pcbddc->vec1_R,tis,pcis->vec1_D,(IS)0,&pcbddc->R_to_D);CHKERRQ(ierr);
5151       ierr = ISDestroy(&tis);CHKERRQ(ierr);
5152     }
5153   }
5154   PetscFunctionReturn(0);
5155 }
5156 
5157 
5158 PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5159 {
5160   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
5161   PC_IS          *pcis = (PC_IS*)pc->data;
5162   PC             pc_temp;
5163   Mat            A_RR;
5164   MatReuse       reuse;
5165   PetscScalar    m_one = -1.0;
5166   PetscReal      value;
5167   PetscInt       n_D,n_R;
5168   PetscBool      check_corr,issbaij;
5169   PetscErrorCode ierr;
5170   /* prefixes stuff */
5171   char           dir_prefix[256],neu_prefix[256],str_level[16];
5172   size_t         len;
5173 
5174   PetscFunctionBegin;
5175   ierr = PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
5176   /* compute prefixes */
5177   ierr = PetscStrcpy(dir_prefix,"");CHKERRQ(ierr);
5178   ierr = PetscStrcpy(neu_prefix,"");CHKERRQ(ierr);
5179   if (!pcbddc->current_level) {
5180     ierr = PetscStrncpy(dir_prefix,((PetscObject)pc)->prefix,sizeof(dir_prefix));CHKERRQ(ierr);
5181     ierr = PetscStrncpy(neu_prefix,((PetscObject)pc)->prefix,sizeof(neu_prefix));CHKERRQ(ierr);
5182     ierr = PetscStrlcat(dir_prefix,"pc_bddc_dirichlet_",sizeof(dir_prefix));CHKERRQ(ierr);
5183     ierr = PetscStrlcat(neu_prefix,"pc_bddc_neumann_",sizeof(neu_prefix));CHKERRQ(ierr);
5184   } else {
5185     ierr = PetscSNPrintf(str_level,sizeof(str_level),"l%d_",(int)(pcbddc->current_level));CHKERRQ(ierr);
5186     ierr = PetscStrlen(((PetscObject)pc)->prefix,&len);CHKERRQ(ierr);
5187     len -= 15; /* remove "pc_bddc_coarse_" */
5188     if (pcbddc->current_level>1) len -= 3; /* remove "lX_" with X level number */
5189     if (pcbddc->current_level>10) len -= 1; /* remove another char from level number */
5190     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
5191     ierr = PetscStrncpy(dir_prefix,((PetscObject)pc)->prefix,len+1);CHKERRQ(ierr);
5192     ierr = PetscStrncpy(neu_prefix,((PetscObject)pc)->prefix,len+1);CHKERRQ(ierr);
5193     ierr = PetscStrlcat(dir_prefix,"pc_bddc_dirichlet_",sizeof(dir_prefix));CHKERRQ(ierr);
5194     ierr = PetscStrlcat(neu_prefix,"pc_bddc_neumann_",sizeof(neu_prefix));CHKERRQ(ierr);
5195     ierr = PetscStrlcat(dir_prefix,str_level,sizeof(dir_prefix));CHKERRQ(ierr);
5196     ierr = PetscStrlcat(neu_prefix,str_level,sizeof(neu_prefix));CHKERRQ(ierr);
5197   }
5198 
5199   /* DIRICHLET PROBLEM */
5200   if (dirichlet) {
5201     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5202     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
5203       if (!sub_schurs || !sub_schurs->reuse_solver) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not yet implemented\n");
5204       if (pcbddc->dbg_flag) {
5205         Mat    A_IIn;
5206 
5207         ierr = PCBDDCBenignProject(pc,pcis->is_I_local,pcis->is_I_local,&A_IIn);CHKERRQ(ierr);
5208         ierr = MatDestroy(&pcis->A_II);CHKERRQ(ierr);
5209         pcis->A_II = A_IIn;
5210       }
5211     }
5212     if (pcbddc->local_mat->symmetric_set) {
5213       ierr = MatSetOption(pcis->A_II,MAT_SYMMETRIC,pcbddc->local_mat->symmetric_set);CHKERRQ(ierr);
5214     }
5215     /* Matrix for Dirichlet problem is pcis->A_II */
5216     n_D = pcis->n - pcis->n_B;
5217     if (!pcbddc->ksp_D) { /* create object if not yet build */
5218       void (*f)(void) = 0;
5219 
5220       ierr = KSPCreate(PETSC_COMM_SELF,&pcbddc->ksp_D);CHKERRQ(ierr);
5221       ierr = PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D,(PetscObject)pc,1);CHKERRQ(ierr);
5222       /* default */
5223       ierr = KSPSetType(pcbddc->ksp_D,KSPPREONLY);CHKERRQ(ierr);
5224       ierr = KSPSetOptionsPrefix(pcbddc->ksp_D,dir_prefix);CHKERRQ(ierr);
5225       ierr = PetscObjectTypeCompare((PetscObject)pcis->A_II,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
5226       ierr = KSPGetPC(pcbddc->ksp_D,&pc_temp);CHKERRQ(ierr);
5227       if (issbaij) {
5228         ierr = PCSetType(pc_temp,PCCHOLESKY);CHKERRQ(ierr);
5229       } else {
5230         ierr = PCSetType(pc_temp,PCLU);CHKERRQ(ierr);
5231       }
5232       /* Allow user's customization */
5233       ierr = KSPSetFromOptions(pcbddc->ksp_D);CHKERRQ(ierr);
5234       ierr = PetscObjectQueryFunction((PetscObject)pc_temp,"PCSetCoordinates_C",&f);CHKERRQ(ierr);
5235       if (f && pcbddc->mat_graph->cloc) {
5236         PetscReal      *coords = pcbddc->mat_graph->coords,*scoords;
5237         const PetscInt *idxs;
5238         PetscInt       cdim = pcbddc->mat_graph->cdim,nl,i,d;
5239 
5240         ierr = ISGetLocalSize(pcis->is_I_local,&nl);CHKERRQ(ierr);
5241         ierr = ISGetIndices(pcis->is_I_local,&idxs);CHKERRQ(ierr);
5242         ierr = PetscMalloc1(nl*cdim,&scoords);CHKERRQ(ierr);
5243         for (i=0;i<nl;i++) {
5244           for (d=0;d<cdim;d++) {
5245             scoords[i*cdim+d] = coords[idxs[i]*cdim+d];
5246           }
5247         }
5248         ierr = ISRestoreIndices(pcis->is_I_local,&idxs);CHKERRQ(ierr);
5249         ierr = PCSetCoordinates(pc_temp,cdim,nl,scoords);CHKERRQ(ierr);
5250         ierr = PetscFree(scoords);CHKERRQ(ierr);
5251       }
5252     }
5253     ierr = KSPSetOperators(pcbddc->ksp_D,pcis->A_II,pcis->A_II);CHKERRQ(ierr);
5254     if (sub_schurs && sub_schurs->reuse_solver) {
5255       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5256 
5257       ierr = KSPSetPC(pcbddc->ksp_D,reuse_solver->interior_solver);CHKERRQ(ierr);
5258     }
5259     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5260     if (!n_D) {
5261       ierr = KSPGetPC(pcbddc->ksp_D,&pc_temp);CHKERRQ(ierr);
5262       ierr = PCSetType(pc_temp,PCNONE);CHKERRQ(ierr);
5263     }
5264     /* set ksp_D into pcis data */
5265     ierr = KSPDestroy(&pcis->ksp_D);CHKERRQ(ierr);
5266     ierr = PetscObjectReference((PetscObject)pcbddc->ksp_D);CHKERRQ(ierr);
5267     pcis->ksp_D = pcbddc->ksp_D;
5268   }
5269 
5270   /* NEUMANN PROBLEM */
5271   A_RR = 0;
5272   if (neumann) {
5273     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5274     PetscInt        ibs,mbs;
5275     PetscBool       issbaij, reuse_neumann_solver;
5276     Mat_IS*         matis = (Mat_IS*)pc->pmat->data;
5277 
5278     reuse_neumann_solver = PETSC_FALSE;
5279     if (sub_schurs && sub_schurs->reuse_solver) {
5280       IS iP;
5281 
5282       reuse_neumann_solver = PETSC_TRUE;
5283       ierr = PetscObjectQuery((PetscObject)sub_schurs->A,"__KSPFETIDP_iP",(PetscObject*)&iP);CHKERRQ(ierr);
5284       if (iP) reuse_neumann_solver = PETSC_FALSE;
5285     }
5286     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
5287     ierr = ISGetSize(pcbddc->is_R_local,&n_R);CHKERRQ(ierr);
5288     if (pcbddc->ksp_R) { /* already created ksp */
5289       PetscInt nn_R;
5290       ierr = KSPGetOperators(pcbddc->ksp_R,NULL,&A_RR);CHKERRQ(ierr);
5291       ierr = PetscObjectReference((PetscObject)A_RR);CHKERRQ(ierr);
5292       ierr = MatGetSize(A_RR,&nn_R,NULL);CHKERRQ(ierr);
5293       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
5294         ierr = KSPReset(pcbddc->ksp_R);CHKERRQ(ierr);
5295         ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5296         reuse = MAT_INITIAL_MATRIX;
5297       } else { /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5298         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
5299           ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5300           reuse = MAT_INITIAL_MATRIX;
5301         } else { /* safe to reuse the matrix */
5302           reuse = MAT_REUSE_MATRIX;
5303         }
5304       }
5305       /* last check */
5306       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
5307         ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5308         reuse = MAT_INITIAL_MATRIX;
5309       }
5310     } else { /* first time, so we need to create the matrix */
5311       reuse = MAT_INITIAL_MATRIX;
5312     }
5313     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection */
5314     ierr = MatGetBlockSize(pcbddc->local_mat,&mbs);CHKERRQ(ierr);
5315     ierr = ISGetBlockSize(pcbddc->is_R_local,&ibs);CHKERRQ(ierr);
5316     ierr = PetscObjectTypeCompare((PetscObject)pcbddc->local_mat,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
5317     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
5318       if (matis->A == pcbddc->local_mat) {
5319         ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
5320         ierr = MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
5321       } else {
5322         ierr = MatConvert(pcbddc->local_mat,MATSEQAIJ,MAT_INPLACE_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
5323       }
5324     } else if (issbaij) { /* need to convert to BAIJ to get offdiagonal blocks */
5325       if (matis->A == pcbddc->local_mat) {
5326         ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
5327         ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
5328       } else {
5329         ierr = MatConvert(pcbddc->local_mat,MATSEQBAIJ,MAT_INPLACE_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
5330       }
5331     }
5332     /* extract A_RR */
5333     if (reuse_neumann_solver) {
5334       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5335 
5336       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
5337         ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5338         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
5339           ierr = PCBDDCBenignProject(pc,pcbddc->is_R_local,pcbddc->is_R_local,&A_RR);CHKERRQ(ierr);
5340         } else {
5341           ierr = MatCreateSubMatrix(pcbddc->local_mat,pcbddc->is_R_local,pcbddc->is_R_local,MAT_INITIAL_MATRIX,&A_RR);CHKERRQ(ierr);
5342         }
5343       } else {
5344         ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5345         ierr = PCGetOperators(reuse_solver->correction_solver,&A_RR,NULL);CHKERRQ(ierr);
5346         ierr = PetscObjectReference((PetscObject)A_RR);CHKERRQ(ierr);
5347       }
5348     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
5349       ierr = MatCreateSubMatrix(pcbddc->local_mat,pcbddc->is_R_local,pcbddc->is_R_local,reuse,&A_RR);CHKERRQ(ierr);
5350     }
5351     if (pcbddc->local_mat->symmetric_set) {
5352       ierr = MatSetOption(A_RR,MAT_SYMMETRIC,pcbddc->local_mat->symmetric_set);CHKERRQ(ierr);
5353     }
5354     if (!pcbddc->ksp_R) { /* create object if not present */
5355       void (*f)(void) = 0;
5356 
5357       ierr = KSPCreate(PETSC_COMM_SELF,&pcbddc->ksp_R);CHKERRQ(ierr);
5358       ierr = PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R,(PetscObject)pc,1);CHKERRQ(ierr);
5359       /* default */
5360       ierr = KSPSetType(pcbddc->ksp_R,KSPPREONLY);CHKERRQ(ierr);
5361       ierr = KSPSetOptionsPrefix(pcbddc->ksp_R,neu_prefix);CHKERRQ(ierr);
5362       ierr = KSPGetPC(pcbddc->ksp_R,&pc_temp);CHKERRQ(ierr);
5363       ierr = PetscObjectTypeCompare((PetscObject)A_RR,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
5364       if (issbaij) {
5365         ierr = PCSetType(pc_temp,PCCHOLESKY);CHKERRQ(ierr);
5366       } else {
5367         ierr = PCSetType(pc_temp,PCLU);CHKERRQ(ierr);
5368       }
5369       /* Allow user's customization */
5370       ierr = KSPSetFromOptions(pcbddc->ksp_R);CHKERRQ(ierr);
5371       ierr = PetscObjectQueryFunction((PetscObject)pc_temp,"PCSetCoordinates_C",&f);CHKERRQ(ierr);
5372       if (f && pcbddc->mat_graph->cloc) {
5373         PetscReal      *coords = pcbddc->mat_graph->coords,*scoords;
5374         const PetscInt *idxs;
5375         PetscInt       cdim = pcbddc->mat_graph->cdim,nl,i,d;
5376 
5377         ierr = ISGetLocalSize(pcbddc->is_R_local,&nl);CHKERRQ(ierr);
5378         ierr = ISGetIndices(pcbddc->is_R_local,&idxs);CHKERRQ(ierr);
5379         ierr = PetscMalloc1(nl*cdim,&scoords);CHKERRQ(ierr);
5380         for (i=0;i<nl;i++) {
5381           for (d=0;d<cdim;d++) {
5382             scoords[i*cdim+d] = coords[idxs[i]*cdim+d];
5383           }
5384         }
5385         ierr = ISRestoreIndices(pcbddc->is_R_local,&idxs);CHKERRQ(ierr);
5386         ierr = PCSetCoordinates(pc_temp,cdim,nl,scoords);CHKERRQ(ierr);
5387         ierr = PetscFree(scoords);CHKERRQ(ierr);
5388       }
5389     }
5390     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5391     if (!n_R) {
5392       ierr = KSPGetPC(pcbddc->ksp_R,&pc_temp);CHKERRQ(ierr);
5393       ierr = PCSetType(pc_temp,PCNONE);CHKERRQ(ierr);
5394     }
5395     ierr = KSPSetOperators(pcbddc->ksp_R,A_RR,A_RR);CHKERRQ(ierr);
5396     /* Reuse solver if it is present */
5397     if (reuse_neumann_solver) {
5398       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5399 
5400       ierr = KSPSetPC(pcbddc->ksp_R,reuse_solver->correction_solver);CHKERRQ(ierr);
5401     }
5402   }
5403 
5404   if (pcbddc->dbg_flag) {
5405     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5406     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
5407     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
5408   }
5409 
5410   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
5411   check_corr = PETSC_FALSE;
5412   if (pcbddc->NullSpace_corr[0]) {
5413     ierr = PCBDDCSetUseExactDirichlet(pc,PETSC_FALSE);CHKERRQ(ierr);
5414   }
5415   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) {
5416     check_corr = PETSC_TRUE;
5417     ierr = PCBDDCNullSpaceAssembleCorrection(pc,PETSC_TRUE,pcbddc->NullSpace_corr[1]);CHKERRQ(ierr);
5418   }
5419   if (neumann && pcbddc->NullSpace_corr[2]) {
5420     check_corr = PETSC_TRUE;
5421     ierr = PCBDDCNullSpaceAssembleCorrection(pc,PETSC_FALSE,pcbddc->NullSpace_corr[3]);CHKERRQ(ierr);
5422   }
5423   /* check Dirichlet and Neumann solvers */
5424   if (pcbddc->dbg_flag) {
5425     if (dirichlet) { /* Dirichlet */
5426       ierr = VecSetRandom(pcis->vec1_D,NULL);CHKERRQ(ierr);
5427       ierr = MatMult(pcis->A_II,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
5428       ierr = KSPSolve(pcbddc->ksp_D,pcis->vec2_D,pcis->vec2_D);CHKERRQ(ierr);
5429       ierr = VecAXPY(pcis->vec1_D,m_one,pcis->vec2_D);CHKERRQ(ierr);
5430       ierr = VecNorm(pcis->vec1_D,NORM_INFINITY,&value);CHKERRQ(ierr);
5431       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d infinity error for Dirichlet solve (%s) = % 1.14e \n",PetscGlobalRank,((PetscObject)(pcbddc->ksp_D))->prefix,value);CHKERRQ(ierr);
5432       if (check_corr) {
5433         ierr = PCBDDCNullSpaceCheckCorrection(pc,PETSC_TRUE);CHKERRQ(ierr);
5434       }
5435       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5436     }
5437     if (neumann) { /* Neumann */
5438       ierr = VecSetRandom(pcbddc->vec1_R,NULL);CHKERRQ(ierr);
5439       ierr = MatMult(A_RR,pcbddc->vec1_R,pcbddc->vec2_R);CHKERRQ(ierr);
5440       ierr = KSPSolve(pcbddc->ksp_R,pcbddc->vec2_R,pcbddc->vec2_R);CHKERRQ(ierr);
5441       ierr = VecAXPY(pcbddc->vec1_R,m_one,pcbddc->vec2_R);CHKERRQ(ierr);
5442       ierr = VecNorm(pcbddc->vec1_R,NORM_INFINITY,&value);CHKERRQ(ierr);
5443       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d infinity error for Neumann solve (%s) = % 1.14e\n",PetscGlobalRank,((PetscObject)(pcbddc->ksp_R))->prefix,value);CHKERRQ(ierr);
5444       if (check_corr) {
5445         ierr = PCBDDCNullSpaceCheckCorrection(pc,PETSC_FALSE);CHKERRQ(ierr);
5446       }
5447       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5448     }
5449   }
5450   /* free Neumann problem's matrix */
5451   ierr = MatDestroy(&A_RR);CHKERRQ(ierr);
5452   ierr = PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
5453   PetscFunctionReturn(0);
5454 }
5455 
5456 static PetscErrorCode  PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
5457 {
5458   PetscErrorCode  ierr;
5459   PC_BDDC*        pcbddc = (PC_BDDC*)(pc->data);
5460   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5461   PetscBool       reuse_solver = sub_schurs ? ( sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE ) : PETSC_FALSE;
5462 
5463   PetscFunctionBegin;
5464   if (!reuse_solver) {
5465     ierr = VecSet(pcbddc->vec1_R,0.);CHKERRQ(ierr);
5466   }
5467   if (!pcbddc->switch_static) {
5468     if (applytranspose && pcbddc->local_auxmat1) {
5469       ierr = MatMultTranspose(pcbddc->local_auxmat2,inout_B,pcbddc->vec1_C);CHKERRQ(ierr);
5470       ierr = MatMultTransposeAdd(pcbddc->local_auxmat1,pcbddc->vec1_C,inout_B,inout_B);CHKERRQ(ierr);
5471     }
5472     if (!reuse_solver) {
5473       ierr = VecScatterBegin(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5474       ierr = VecScatterEnd(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5475     } else {
5476       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5477 
5478       ierr = VecScatterBegin(reuse_solver->correction_scatter_B,inout_B,reuse_solver->rhs_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5479       ierr = VecScatterEnd(reuse_solver->correction_scatter_B,inout_B,reuse_solver->rhs_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5480     }
5481   } else {
5482     ierr = VecScatterBegin(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5483     ierr = VecScatterEnd(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5484     ierr = VecScatterBegin(pcbddc->R_to_D,inout_D,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5485     ierr = VecScatterEnd(pcbddc->R_to_D,inout_D,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5486     if (applytranspose && pcbddc->local_auxmat1) {
5487       ierr = MatMultTranspose(pcbddc->local_auxmat2,pcbddc->vec1_R,pcbddc->vec1_C);CHKERRQ(ierr);
5488       ierr = MatMultTransposeAdd(pcbddc->local_auxmat1,pcbddc->vec1_C,inout_B,inout_B);CHKERRQ(ierr);
5489       ierr = VecScatterBegin(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5490       ierr = VecScatterEnd(pcbddc->R_to_B,inout_B,pcbddc->vec1_R,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5491     }
5492   }
5493   if (!reuse_solver || pcbddc->switch_static) {
5494     if (applytranspose) {
5495       ierr = KSPSolveTranspose(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec1_R);CHKERRQ(ierr);
5496     } else {
5497       ierr = KSPSolve(pcbddc->ksp_R,pcbddc->vec1_R,pcbddc->vec1_R);CHKERRQ(ierr);
5498     }
5499   } else {
5500     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5501 
5502     if (applytranspose) {
5503       ierr = MatFactorSolveSchurComplementTranspose(reuse_solver->F,reuse_solver->rhs_B,reuse_solver->sol_B);CHKERRQ(ierr);
5504     } else {
5505       ierr = MatFactorSolveSchurComplement(reuse_solver->F,reuse_solver->rhs_B,reuse_solver->sol_B);CHKERRQ(ierr);
5506     }
5507   }
5508   ierr = VecSet(inout_B,0.);CHKERRQ(ierr);
5509   if (!pcbddc->switch_static) {
5510     if (!reuse_solver) {
5511       ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5512       ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5513     } else {
5514       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5515 
5516       ierr = VecScatterBegin(reuse_solver->correction_scatter_B,reuse_solver->sol_B,inout_B,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5517       ierr = VecScatterEnd(reuse_solver->correction_scatter_B,reuse_solver->sol_B,inout_B,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5518     }
5519     if (!applytranspose && pcbddc->local_auxmat1) {
5520       ierr = MatMult(pcbddc->local_auxmat1,inout_B,pcbddc->vec1_C);CHKERRQ(ierr);
5521       ierr = MatMultAdd(pcbddc->local_auxmat2,pcbddc->vec1_C,inout_B,inout_B);CHKERRQ(ierr);
5522     }
5523   } else {
5524     ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5525     ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5526     ierr = VecScatterBegin(pcbddc->R_to_D,pcbddc->vec1_R,inout_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5527     ierr = VecScatterEnd(pcbddc->R_to_D,pcbddc->vec1_R,inout_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5528     if (!applytranspose && pcbddc->local_auxmat1) {
5529       ierr = MatMult(pcbddc->local_auxmat1,inout_B,pcbddc->vec1_C);CHKERRQ(ierr);
5530       ierr = MatMultAdd(pcbddc->local_auxmat2,pcbddc->vec1_C,pcbddc->vec1_R,pcbddc->vec1_R);CHKERRQ(ierr);
5531     }
5532     ierr = VecScatterBegin(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5533     ierr = VecScatterEnd(pcbddc->R_to_B,pcbddc->vec1_R,inout_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5534     ierr = VecScatterBegin(pcbddc->R_to_D,pcbddc->vec1_R,inout_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5535     ierr = VecScatterEnd(pcbddc->R_to_D,pcbddc->vec1_R,inout_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5536   }
5537   PetscFunctionReturn(0);
5538 }
5539 
5540 /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
5541 PetscErrorCode  PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
5542 {
5543   PetscErrorCode ierr;
5544   PC_BDDC*        pcbddc = (PC_BDDC*)(pc->data);
5545   PC_IS*            pcis = (PC_IS*)  (pc->data);
5546   const PetscScalar zero = 0.0;
5547 
5548   PetscFunctionBegin;
5549   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
5550   if (!pcbddc->benign_apply_coarse_only) {
5551     if (applytranspose) {
5552       ierr = MatMultTranspose(pcbddc->coarse_phi_B,pcis->vec1_B,pcbddc->vec1_P);CHKERRQ(ierr);
5553       if (pcbddc->switch_static) { ierr = MatMultTransposeAdd(pcbddc->coarse_phi_D,pcis->vec1_D,pcbddc->vec1_P,pcbddc->vec1_P);CHKERRQ(ierr); }
5554     } else {
5555       ierr = MatMultTranspose(pcbddc->coarse_psi_B,pcis->vec1_B,pcbddc->vec1_P);CHKERRQ(ierr);
5556       if (pcbddc->switch_static) { ierr = MatMultTransposeAdd(pcbddc->coarse_psi_D,pcis->vec1_D,pcbddc->vec1_P,pcbddc->vec1_P);CHKERRQ(ierr); }
5557     }
5558   } else {
5559     ierr = VecSet(pcbddc->vec1_P,zero);CHKERRQ(ierr);
5560   }
5561 
5562   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
5563   if (pcbddc->benign_n) {
5564     PetscScalar *array;
5565     PetscInt    j;
5566 
5567     ierr = VecGetArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
5568     for (j=0;j<pcbddc->benign_n;j++) array[pcbddc->local_primal_size-pcbddc->benign_n+j] += pcbddc->benign_p0[j];
5569     ierr = VecRestoreArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
5570   }
5571 
5572   /* start communications from local primal nodes to rhs of coarse solver */
5573   ierr = VecSet(pcbddc->coarse_vec,zero);CHKERRQ(ierr);
5574   ierr = PCBDDCScatterCoarseDataBegin(pc,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5575   ierr = PCBDDCScatterCoarseDataEnd(pc,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5576 
5577   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
5578   if (pcbddc->coarse_ksp) {
5579     Mat          coarse_mat;
5580     Vec          rhs,sol;
5581     MatNullSpace nullsp;
5582     PetscBool    isbddc = PETSC_FALSE;
5583 
5584     if (pcbddc->benign_have_null) {
5585       PC        coarse_pc;
5586 
5587       ierr = KSPGetPC(pcbddc->coarse_ksp,&coarse_pc);CHKERRQ(ierr);
5588       ierr = PetscObjectTypeCompare((PetscObject)coarse_pc,PCBDDC,&isbddc);CHKERRQ(ierr);
5589       /* we need to propagate to coarser levels the need for a possible benign correction */
5590       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
5591         PC_BDDC* coarsepcbddc = (PC_BDDC*)(coarse_pc->data);
5592         coarsepcbddc->benign_skip_correction = PETSC_FALSE;
5593         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
5594       }
5595     }
5596     ierr = KSPGetRhs(pcbddc->coarse_ksp,&rhs);CHKERRQ(ierr);
5597     ierr = KSPGetSolution(pcbddc->coarse_ksp,&sol);CHKERRQ(ierr);
5598     ierr = KSPGetOperators(pcbddc->coarse_ksp,&coarse_mat,NULL);CHKERRQ(ierr);
5599     ierr = MatGetNullSpace(coarse_mat,&nullsp);CHKERRQ(ierr);
5600     if (nullsp) {
5601       ierr = MatNullSpaceRemove(nullsp,rhs);CHKERRQ(ierr);
5602     }
5603     if (applytranspose) {
5604       if (pcbddc->benign_apply_coarse_only) SETERRQ(PetscObjectComm((PetscObject)pcbddc->coarse_ksp),PETSC_ERR_SUP,"Not yet implemented");
5605       ierr = KSPSolveTranspose(pcbddc->coarse_ksp,rhs,sol);CHKERRQ(ierr);
5606     } else {
5607       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
5608         PC        coarse_pc;
5609 
5610         ierr = KSPGetPC(pcbddc->coarse_ksp,&coarse_pc);CHKERRQ(ierr);
5611         ierr = PCPreSolve(coarse_pc,pcbddc->coarse_ksp);CHKERRQ(ierr);
5612         ierr = PCBDDCBenignRemoveInterior(coarse_pc,rhs,sol);CHKERRQ(ierr);
5613         ierr = PCPostSolve(coarse_pc,pcbddc->coarse_ksp);CHKERRQ(ierr);
5614       } else {
5615         ierr = KSPSolve(pcbddc->coarse_ksp,rhs,sol);CHKERRQ(ierr);
5616       }
5617     }
5618     /* we don't need the benign correction at coarser levels anymore */
5619     if (pcbddc->benign_have_null && isbddc) {
5620       PC        coarse_pc;
5621       PC_BDDC*  coarsepcbddc;
5622 
5623       ierr = KSPGetPC(pcbddc->coarse_ksp,&coarse_pc);CHKERRQ(ierr);
5624       coarsepcbddc = (PC_BDDC*)(coarse_pc->data);
5625       coarsepcbddc->benign_skip_correction = PETSC_TRUE;
5626       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
5627     }
5628     if (nullsp) {
5629       ierr = MatNullSpaceRemove(nullsp,sol);CHKERRQ(ierr);
5630     }
5631   }
5632 
5633   /* Local solution on R nodes */
5634   if (pcis->n && !pcbddc->benign_apply_coarse_only) {
5635     ierr = PCBDDCSolveSubstructureCorrection(pc,pcis->vec1_B,pcis->vec1_D,applytranspose);CHKERRQ(ierr);
5636   }
5637   /* communications from coarse sol to local primal nodes */
5638   ierr = PCBDDCScatterCoarseDataBegin(pc,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5639   ierr = PCBDDCScatterCoarseDataEnd(pc,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5640 
5641   /* Sum contributions from the two levels */
5642   if (!pcbddc->benign_apply_coarse_only) {
5643     if (applytranspose) {
5644       ierr = MatMultAdd(pcbddc->coarse_psi_B,pcbddc->vec1_P,pcis->vec1_B,pcis->vec1_B);CHKERRQ(ierr);
5645       if (pcbddc->switch_static) { ierr = MatMultAdd(pcbddc->coarse_psi_D,pcbddc->vec1_P,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
5646     } else {
5647       ierr = MatMultAdd(pcbddc->coarse_phi_B,pcbddc->vec1_P,pcis->vec1_B,pcis->vec1_B);CHKERRQ(ierr);
5648       if (pcbddc->switch_static) { ierr = MatMultAdd(pcbddc->coarse_phi_D,pcbddc->vec1_P,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
5649     }
5650     /* store p0 */
5651     if (pcbddc->benign_n) {
5652       PetscScalar *array;
5653       PetscInt    j;
5654 
5655       ierr = VecGetArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
5656       for (j=0;j<pcbddc->benign_n;j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size-pcbddc->benign_n+j];
5657       ierr = VecRestoreArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
5658     }
5659   } else { /* expand the coarse solution */
5660     if (applytranspose) {
5661       ierr = MatMult(pcbddc->coarse_psi_B,pcbddc->vec1_P,pcis->vec1_B);CHKERRQ(ierr);
5662     } else {
5663       ierr = MatMult(pcbddc->coarse_phi_B,pcbddc->vec1_P,pcis->vec1_B);CHKERRQ(ierr);
5664     }
5665   }
5666   PetscFunctionReturn(0);
5667 }
5668 
5669 PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc,InsertMode imode, ScatterMode smode)
5670 {
5671   PetscErrorCode ierr;
5672   PC_BDDC*       pcbddc = (PC_BDDC*)(pc->data);
5673   PetscScalar    *array;
5674   Vec            from,to;
5675 
5676   PetscFunctionBegin;
5677   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
5678     from = pcbddc->coarse_vec;
5679     to = pcbddc->vec1_P;
5680     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
5681       Vec tvec;
5682 
5683       ierr = KSPGetRhs(pcbddc->coarse_ksp,&tvec);CHKERRQ(ierr);
5684       ierr = VecResetArray(tvec);CHKERRQ(ierr);
5685       ierr = KSPGetSolution(pcbddc->coarse_ksp,&tvec);CHKERRQ(ierr);
5686       ierr = VecGetArray(tvec,&array);CHKERRQ(ierr);
5687       ierr = VecPlaceArray(from,array);CHKERRQ(ierr);
5688       ierr = VecRestoreArray(tvec,&array);CHKERRQ(ierr);
5689     }
5690   } else { /* from local to global -> put data in coarse right hand side */
5691     from = pcbddc->vec1_P;
5692     to = pcbddc->coarse_vec;
5693   }
5694   ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,from,to,imode,smode);CHKERRQ(ierr);
5695   PetscFunctionReturn(0);
5696 }
5697 
5698 PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
5699 {
5700   PetscErrorCode ierr;
5701   PC_BDDC*       pcbddc = (PC_BDDC*)(pc->data);
5702   PetscScalar    *array;
5703   Vec            from,to;
5704 
5705   PetscFunctionBegin;
5706   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
5707     from = pcbddc->coarse_vec;
5708     to = pcbddc->vec1_P;
5709   } else { /* from local to global -> put data in coarse right hand side */
5710     from = pcbddc->vec1_P;
5711     to = pcbddc->coarse_vec;
5712   }
5713   ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,from,to,imode,smode);CHKERRQ(ierr);
5714   if (smode == SCATTER_FORWARD) {
5715     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
5716       Vec tvec;
5717 
5718       ierr = KSPGetRhs(pcbddc->coarse_ksp,&tvec);CHKERRQ(ierr);
5719       ierr = VecGetArray(to,&array);CHKERRQ(ierr);
5720       ierr = VecPlaceArray(tvec,array);CHKERRQ(ierr);
5721       ierr = VecRestoreArray(to,&array);CHKERRQ(ierr);
5722     }
5723   } else {
5724     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
5725      ierr = VecResetArray(from);CHKERRQ(ierr);
5726     }
5727   }
5728   PetscFunctionReturn(0);
5729 }
5730 
5731 /* uncomment for testing purposes */
5732 /* #define PETSC_MISSING_LAPACK_GESVD 1 */
5733 PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
5734 {
5735   PetscErrorCode    ierr;
5736   PC_IS*            pcis = (PC_IS*)(pc->data);
5737   PC_BDDC*          pcbddc = (PC_BDDC*)pc->data;
5738   Mat_IS*           matis = (Mat_IS*)pc->pmat->data;
5739   /* one and zero */
5740   PetscScalar       one=1.0,zero=0.0;
5741   /* space to store constraints and their local indices */
5742   PetscScalar       *constraints_data;
5743   PetscInt          *constraints_idxs,*constraints_idxs_B;
5744   PetscInt          *constraints_idxs_ptr,*constraints_data_ptr;
5745   PetscInt          *constraints_n;
5746   /* iterators */
5747   PetscInt          i,j,k,total_counts,total_counts_cc,cum;
5748   /* BLAS integers */
5749   PetscBLASInt      lwork,lierr;
5750   PetscBLASInt      Blas_N,Blas_M,Blas_K,Blas_one=1;
5751   PetscBLASInt      Blas_LDA,Blas_LDB,Blas_LDC;
5752   /* reuse */
5753   PetscInt          olocal_primal_size,olocal_primal_size_cc;
5754   PetscInt          *olocal_primal_ref_node,*olocal_primal_ref_mult;
5755   /* change of basis */
5756   PetscBool         qr_needed;
5757   PetscBT           change_basis,qr_needed_idx;
5758   /* auxiliary stuff */
5759   PetscInt          *nnz,*is_indices;
5760   PetscInt          ncc;
5761   /* some quantities */
5762   PetscInt          n_vertices,total_primal_vertices,valid_constraints;
5763   PetscInt          size_of_constraint,max_size_of_constraint=0,max_constraints,temp_constraints;
5764   PetscReal         tol; /* tolerance for retaining eigenmodes */
5765 
5766   PetscFunctionBegin;
5767   tol  = PetscSqrtReal(PETSC_SMALL);
5768   /* Destroy Mat objects computed previously */
5769   ierr = MatDestroy(&pcbddc->ChangeOfBasisMatrix);CHKERRQ(ierr);
5770   ierr = MatDestroy(&pcbddc->ConstraintMatrix);CHKERRQ(ierr);
5771   ierr = MatDestroy(&pcbddc->switch_static_change);CHKERRQ(ierr);
5772   /* save info on constraints from previous setup (if any) */
5773   olocal_primal_size = pcbddc->local_primal_size;
5774   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
5775   ierr = PetscMalloc2(olocal_primal_size_cc,&olocal_primal_ref_node,olocal_primal_size_cc,&olocal_primal_ref_mult);CHKERRQ(ierr);
5776   ierr = PetscMemcpy(olocal_primal_ref_node,pcbddc->local_primal_ref_node,olocal_primal_size_cc*sizeof(PetscInt));CHKERRQ(ierr);
5777   ierr = PetscMemcpy(olocal_primal_ref_mult,pcbddc->local_primal_ref_mult,olocal_primal_size_cc*sizeof(PetscInt));CHKERRQ(ierr);
5778   ierr = PetscFree2(pcbddc->local_primal_ref_node,pcbddc->local_primal_ref_mult);CHKERRQ(ierr);
5779   ierr = PetscFree(pcbddc->primal_indices_local_idxs);CHKERRQ(ierr);
5780 
5781   if (!pcbddc->adaptive_selection) {
5782     IS           ISForVertices,*ISForFaces,*ISForEdges;
5783     MatNullSpace nearnullsp;
5784     const Vec    *nearnullvecs;
5785     Vec          *localnearnullsp;
5786     PetscScalar  *array;
5787     PetscInt     n_ISForFaces,n_ISForEdges,nnsp_size;
5788     PetscBool    nnsp_has_cnst;
5789     /* LAPACK working arrays for SVD or POD */
5790     PetscBool    skip_lapack,boolforchange;
5791     PetscScalar  *work;
5792     PetscReal    *singular_vals;
5793 #if defined(PETSC_USE_COMPLEX)
5794     PetscReal    *rwork;
5795 #endif
5796 #if defined(PETSC_MISSING_LAPACK_GESVD)
5797     PetscScalar  *temp_basis,*correlation_mat;
5798 #else
5799     PetscBLASInt dummy_int=1;
5800     PetscScalar  dummy_scalar=1.;
5801 #endif
5802 
5803     /* Get index sets for faces, edges and vertices from graph */
5804     ierr = PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,&n_ISForFaces,&ISForFaces,&n_ISForEdges,&ISForEdges,&ISForVertices);CHKERRQ(ierr);
5805     /* print some info */
5806     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
5807       PetscInt nv;
5808 
5809       ierr = PCBDDCGraphASCIIView(pcbddc->mat_graph,pcbddc->dbg_flag,pcbddc->dbg_viewer);CHKERRQ(ierr);
5810       ierr = ISGetSize(ISForVertices,&nv);CHKERRQ(ierr);
5811       ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
5812       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"--------------------------------------------------------------\n");CHKERRQ(ierr);
5813       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate vertices (%d)\n",PetscGlobalRank,nv,pcbddc->use_vertices);CHKERRQ(ierr);
5814       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate edges    (%d)\n",PetscGlobalRank,n_ISForEdges,pcbddc->use_edges);CHKERRQ(ierr);
5815       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate faces    (%d)\n",PetscGlobalRank,n_ISForFaces,pcbddc->use_faces);CHKERRQ(ierr);
5816       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
5817       ierr = PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
5818     }
5819 
5820     /* free unneeded index sets */
5821     if (!pcbddc->use_vertices) {
5822       ierr = ISDestroy(&ISForVertices);CHKERRQ(ierr);
5823     }
5824     if (!pcbddc->use_edges) {
5825       for (i=0;i<n_ISForEdges;i++) {
5826         ierr = ISDestroy(&ISForEdges[i]);CHKERRQ(ierr);
5827       }
5828       ierr = PetscFree(ISForEdges);CHKERRQ(ierr);
5829       n_ISForEdges = 0;
5830     }
5831     if (!pcbddc->use_faces) {
5832       for (i=0;i<n_ISForFaces;i++) {
5833         ierr = ISDestroy(&ISForFaces[i]);CHKERRQ(ierr);
5834       }
5835       ierr = PetscFree(ISForFaces);CHKERRQ(ierr);
5836       n_ISForFaces = 0;
5837     }
5838 
5839     /* check if near null space is attached to global mat */
5840     ierr = MatGetNearNullSpace(pc->pmat,&nearnullsp);CHKERRQ(ierr);
5841     if (nearnullsp) {
5842       ierr = MatNullSpaceGetVecs(nearnullsp,&nnsp_has_cnst,&nnsp_size,&nearnullvecs);CHKERRQ(ierr);
5843       /* remove any stored info */
5844       ierr = MatNullSpaceDestroy(&pcbddc->onearnullspace);CHKERRQ(ierr);
5845       ierr = PetscFree(pcbddc->onearnullvecs_state);CHKERRQ(ierr);
5846       /* store information for BDDC solver reuse */
5847       ierr = PetscObjectReference((PetscObject)nearnullsp);CHKERRQ(ierr);
5848       pcbddc->onearnullspace = nearnullsp;
5849       ierr = PetscMalloc1(nnsp_size,&pcbddc->onearnullvecs_state);CHKERRQ(ierr);
5850       for (i=0;i<nnsp_size;i++) {
5851         ierr = PetscObjectStateGet((PetscObject)nearnullvecs[i],&pcbddc->onearnullvecs_state[i]);CHKERRQ(ierr);
5852       }
5853     } else { /* if near null space is not provided BDDC uses constants by default */
5854       nnsp_size = 0;
5855       nnsp_has_cnst = PETSC_TRUE;
5856     }
5857     /* get max number of constraints on a single cc */
5858     max_constraints = nnsp_size;
5859     if (nnsp_has_cnst) max_constraints++;
5860 
5861     /*
5862          Evaluate maximum storage size needed by the procedure
5863          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
5864          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
5865          There can be multiple constraints per connected component
5866                                                                                                                                                            */
5867     n_vertices = 0;
5868     if (ISForVertices) {
5869       ierr = ISGetSize(ISForVertices,&n_vertices);CHKERRQ(ierr);
5870     }
5871     ncc = n_vertices+n_ISForFaces+n_ISForEdges;
5872     ierr = PetscMalloc3(ncc+1,&constraints_idxs_ptr,ncc+1,&constraints_data_ptr,ncc,&constraints_n);CHKERRQ(ierr);
5873 
5874     total_counts = n_ISForFaces+n_ISForEdges;
5875     total_counts *= max_constraints;
5876     total_counts += n_vertices;
5877     ierr = PetscBTCreate(total_counts,&change_basis);CHKERRQ(ierr);
5878 
5879     total_counts = 0;
5880     max_size_of_constraint = 0;
5881     for (i=0;i<n_ISForEdges+n_ISForFaces;i++) {
5882       IS used_is;
5883       if (i<n_ISForEdges) {
5884         used_is = ISForEdges[i];
5885       } else {
5886         used_is = ISForFaces[i-n_ISForEdges];
5887       }
5888       ierr = ISGetSize(used_is,&j);CHKERRQ(ierr);
5889       total_counts += j;
5890       max_size_of_constraint = PetscMax(j,max_size_of_constraint);
5891     }
5892     ierr = PetscMalloc3(total_counts*max_constraints+n_vertices,&constraints_data,total_counts+n_vertices,&constraints_idxs,total_counts+n_vertices,&constraints_idxs_B);CHKERRQ(ierr);
5893 
5894     /* get local part of global near null space vectors */
5895     ierr = PetscMalloc1(nnsp_size,&localnearnullsp);CHKERRQ(ierr);
5896     for (k=0;k<nnsp_size;k++) {
5897       ierr = VecDuplicate(pcis->vec1_N,&localnearnullsp[k]);CHKERRQ(ierr);
5898       ierr = VecScatterBegin(matis->rctx,nearnullvecs[k],localnearnullsp[k],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5899       ierr = VecScatterEnd(matis->rctx,nearnullvecs[k],localnearnullsp[k],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5900     }
5901 
5902     /* whether or not to skip lapack calls */
5903     skip_lapack = PETSC_TRUE;
5904     if (n_ISForFaces+n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
5905 
5906     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
5907     if (!skip_lapack) {
5908       PetscScalar temp_work;
5909 
5910 #if defined(PETSC_MISSING_LAPACK_GESVD)
5911       /* Proper Orthogonal Decomposition (POD) using the snapshot method */
5912       ierr = PetscMalloc1(max_constraints*max_constraints,&correlation_mat);CHKERRQ(ierr);
5913       ierr = PetscMalloc1(max_constraints,&singular_vals);CHKERRQ(ierr);
5914       ierr = PetscMalloc1(max_size_of_constraint*max_constraints,&temp_basis);CHKERRQ(ierr);
5915 #if defined(PETSC_USE_COMPLEX)
5916       ierr = PetscMalloc1(3*max_constraints,&rwork);CHKERRQ(ierr);
5917 #endif
5918       /* now we evaluate the optimal workspace using query with lwork=-1 */
5919       ierr = PetscBLASIntCast(max_constraints,&Blas_N);CHKERRQ(ierr);
5920       ierr = PetscBLASIntCast(max_constraints,&Blas_LDA);CHKERRQ(ierr);
5921       lwork = -1;
5922       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
5923 #if !defined(PETSC_USE_COMPLEX)
5924       PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&Blas_N,correlation_mat,&Blas_LDA,singular_vals,&temp_work,&lwork,&lierr));
5925 #else
5926       PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&Blas_N,correlation_mat,&Blas_LDA,singular_vals,&temp_work,&lwork,rwork,&lierr));
5927 #endif
5928       ierr = PetscFPTrapPop();CHKERRQ(ierr);
5929       if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in query to SYEV Lapack routine %d",(int)lierr);
5930 #else /* on missing GESVD */
5931       /* SVD */
5932       PetscInt max_n,min_n;
5933       max_n = max_size_of_constraint;
5934       min_n = max_constraints;
5935       if (max_size_of_constraint < max_constraints) {
5936         min_n = max_size_of_constraint;
5937         max_n = max_constraints;
5938       }
5939       ierr = PetscMalloc1(min_n,&singular_vals);CHKERRQ(ierr);
5940 #if defined(PETSC_USE_COMPLEX)
5941       ierr = PetscMalloc1(5*min_n,&rwork);CHKERRQ(ierr);
5942 #endif
5943       /* now we evaluate the optimal workspace using query with lwork=-1 */
5944       lwork = -1;
5945       ierr = PetscBLASIntCast(max_n,&Blas_M);CHKERRQ(ierr);
5946       ierr = PetscBLASIntCast(min_n,&Blas_N);CHKERRQ(ierr);
5947       ierr = PetscBLASIntCast(max_n,&Blas_LDA);CHKERRQ(ierr);
5948       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
5949 #if !defined(PETSC_USE_COMPLEX)
5950       PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("O","N",&Blas_M,&Blas_N,&constraints_data[0],&Blas_LDA,singular_vals,&dummy_scalar,&dummy_int,&dummy_scalar,&dummy_int,&temp_work,&lwork,&lierr));
5951 #else
5952       PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("O","N",&Blas_M,&Blas_N,&constraints_data[0],&Blas_LDA,singular_vals,&dummy_scalar,&dummy_int,&dummy_scalar,&dummy_int,&temp_work,&lwork,rwork,&lierr));
5953 #endif
5954       ierr = PetscFPTrapPop();CHKERRQ(ierr);
5955       if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in query to GESVD Lapack routine %d",(int)lierr);
5956 #endif /* on missing GESVD */
5957       /* Allocate optimal workspace */
5958       ierr = PetscBLASIntCast((PetscInt)PetscRealPart(temp_work),&lwork);CHKERRQ(ierr);
5959       ierr = PetscMalloc1(lwork,&work);CHKERRQ(ierr);
5960     }
5961     /* Now we can loop on constraining sets */
5962     total_counts = 0;
5963     constraints_idxs_ptr[0] = 0;
5964     constraints_data_ptr[0] = 0;
5965     /* vertices */
5966     if (n_vertices) {
5967       ierr = ISGetIndices(ISForVertices,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5968       ierr = PetscMemcpy(constraints_idxs,is_indices,n_vertices*sizeof(PetscInt));CHKERRQ(ierr);
5969       for (i=0;i<n_vertices;i++) {
5970         constraints_n[total_counts] = 1;
5971         constraints_data[total_counts] = 1.0;
5972         constraints_idxs_ptr[total_counts+1] = constraints_idxs_ptr[total_counts]+1;
5973         constraints_data_ptr[total_counts+1] = constraints_data_ptr[total_counts]+1;
5974         total_counts++;
5975       }
5976       ierr = ISRestoreIndices(ISForVertices,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5977       n_vertices = total_counts;
5978     }
5979 
5980     /* edges and faces */
5981     total_counts_cc = total_counts;
5982     for (ncc=0;ncc<n_ISForEdges+n_ISForFaces;ncc++) {
5983       IS        used_is;
5984       PetscBool idxs_copied = PETSC_FALSE;
5985 
5986       if (ncc<n_ISForEdges) {
5987         used_is = ISForEdges[ncc];
5988         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
5989       } else {
5990         used_is = ISForFaces[ncc-n_ISForEdges];
5991         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
5992       }
5993       temp_constraints = 0;          /* zero the number of constraints I have on this conn comp */
5994 
5995       ierr = ISGetSize(used_is,&size_of_constraint);CHKERRQ(ierr);
5996       ierr = ISGetIndices(used_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
5997       /* change of basis should not be performed on local periodic nodes */
5998       if (pcbddc->mat_graph->mirrors && pcbddc->mat_graph->mirrors[is_indices[0]]) boolforchange = PETSC_FALSE;
5999       if (nnsp_has_cnst) {
6000         PetscScalar quad_value;
6001 
6002         ierr = PetscMemcpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc],is_indices,size_of_constraint*sizeof(PetscInt));CHKERRQ(ierr);
6003         idxs_copied = PETSC_TRUE;
6004 
6005         if (!pcbddc->use_nnsp_true) {
6006           quad_value = (PetscScalar)(1.0/PetscSqrtReal((PetscReal)size_of_constraint));
6007         } else {
6008           quad_value = 1.0;
6009         }
6010         for (j=0;j<size_of_constraint;j++) {
6011           constraints_data[constraints_data_ptr[total_counts_cc]+j] = quad_value;
6012         }
6013         temp_constraints++;
6014         total_counts++;
6015       }
6016       for (k=0;k<nnsp_size;k++) {
6017         PetscReal real_value;
6018         PetscScalar *ptr_to_data;
6019 
6020         ierr = VecGetArrayRead(localnearnullsp[k],(const PetscScalar**)&array);CHKERRQ(ierr);
6021         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]+temp_constraints*size_of_constraint];
6022         for (j=0;j<size_of_constraint;j++) {
6023           ptr_to_data[j] = array[is_indices[j]];
6024         }
6025         ierr = VecRestoreArrayRead(localnearnullsp[k],(const PetscScalar**)&array);CHKERRQ(ierr);
6026         /* check if array is null on the connected component */
6027         ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6028         PetscStackCallBLAS("BLASasum",real_value = BLASasum_(&Blas_N,ptr_to_data,&Blas_one));
6029         if (real_value > tol*size_of_constraint) { /* keep indices and values */
6030           temp_constraints++;
6031           total_counts++;
6032           if (!idxs_copied) {
6033             ierr = PetscMemcpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc],is_indices,size_of_constraint*sizeof(PetscInt));CHKERRQ(ierr);
6034             idxs_copied = PETSC_TRUE;
6035           }
6036         }
6037       }
6038       ierr = ISRestoreIndices(used_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
6039       valid_constraints = temp_constraints;
6040       if (!pcbddc->use_nnsp_true && temp_constraints) {
6041         if (temp_constraints == 1) { /* just normalize the constraint */
6042           PetscScalar norm,*ptr_to_data;
6043 
6044           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6045           ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6046           PetscStackCallBLAS("BLASdot",norm = BLASdot_(&Blas_N,ptr_to_data,&Blas_one,ptr_to_data,&Blas_one));
6047           norm = 1.0/PetscSqrtReal(PetscRealPart(norm));
6048           PetscStackCallBLAS("BLASscal",BLASscal_(&Blas_N,&norm,ptr_to_data,&Blas_one));
6049         } else { /* perform SVD */
6050           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6051 
6052 #if defined(PETSC_MISSING_LAPACK_GESVD)
6053           /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6054              POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6055              -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6056                 the constraints basis will differ (by a complex factor with absolute value equal to 1)
6057                 from that computed using LAPACKgesvd
6058              -> This is due to a different computation of eigenvectors in LAPACKheev
6059              -> The quality of the POD-computed basis will be the same */
6060           ierr = PetscMemzero(correlation_mat,temp_constraints*temp_constraints*sizeof(PetscScalar));CHKERRQ(ierr);
6061           /* Store upper triangular part of correlation matrix */
6062           ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6063           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6064           for (j=0;j<temp_constraints;j++) {
6065             for (k=0;k<j+1;k++) {
6066               PetscStackCallBLAS("BLASdot",correlation_mat[j*temp_constraints+k] = BLASdot_(&Blas_N,ptr_to_data+k*size_of_constraint,&Blas_one,ptr_to_data+j*size_of_constraint,&Blas_one));
6067             }
6068           }
6069           /* compute eigenvalues and eigenvectors of correlation matrix */
6070           ierr = PetscBLASIntCast(temp_constraints,&Blas_N);CHKERRQ(ierr);
6071           ierr = PetscBLASIntCast(temp_constraints,&Blas_LDA);CHKERRQ(ierr);
6072 #if !defined(PETSC_USE_COMPLEX)
6073           PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&Blas_N,correlation_mat,&Blas_LDA,singular_vals,work,&lwork,&lierr));
6074 #else
6075           PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&Blas_N,correlation_mat,&Blas_LDA,singular_vals,work,&lwork,rwork,&lierr));
6076 #endif
6077           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6078           if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SYEV Lapack routine %d",(int)lierr);
6079           /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6080           j = 0;
6081           while (j < temp_constraints && singular_vals[j] < tol) j++;
6082           total_counts = total_counts-j;
6083           valid_constraints = temp_constraints-j;
6084           /* scale and copy POD basis into used quadrature memory */
6085           ierr = PetscBLASIntCast(size_of_constraint,&Blas_M);CHKERRQ(ierr);
6086           ierr = PetscBLASIntCast(temp_constraints,&Blas_N);CHKERRQ(ierr);
6087           ierr = PetscBLASIntCast(temp_constraints,&Blas_K);CHKERRQ(ierr);
6088           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6089           ierr = PetscBLASIntCast(temp_constraints,&Blas_LDB);CHKERRQ(ierr);
6090           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDC);CHKERRQ(ierr);
6091           if (j<temp_constraints) {
6092             PetscInt ii;
6093             for (k=j;k<temp_constraints;k++) singular_vals[k] = 1.0/PetscSqrtReal(singular_vals[k]);
6094             ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6095             PetscStackCallBLAS("BLASgemm",BLASgemm_("N","N",&Blas_M,&Blas_N,&Blas_K,&one,ptr_to_data,&Blas_LDA,correlation_mat,&Blas_LDB,&zero,temp_basis,&Blas_LDC));
6096             ierr = PetscFPTrapPop();CHKERRQ(ierr);
6097             for (k=0;k<temp_constraints-j;k++) {
6098               for (ii=0;ii<size_of_constraint;ii++) {
6099                 ptr_to_data[k*size_of_constraint+ii] = singular_vals[temp_constraints-1-k]*temp_basis[(temp_constraints-1-k)*size_of_constraint+ii];
6100               }
6101             }
6102           }
6103 #else  /* on missing GESVD */
6104           ierr = PetscBLASIntCast(size_of_constraint,&Blas_M);CHKERRQ(ierr);
6105           ierr = PetscBLASIntCast(temp_constraints,&Blas_N);CHKERRQ(ierr);
6106           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6107           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6108 #if !defined(PETSC_USE_COMPLEX)
6109           PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("O","N",&Blas_M,&Blas_N,ptr_to_data,&Blas_LDA,singular_vals,&dummy_scalar,&dummy_int,&dummy_scalar,&dummy_int,work,&lwork,&lierr));
6110 #else
6111           PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("O","N",&Blas_M,&Blas_N,ptr_to_data,&Blas_LDA,singular_vals,&dummy_scalar,&dummy_int,&dummy_scalar,&dummy_int,work,&lwork,rwork,&lierr));
6112 #endif
6113           if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in GESVD Lapack routine %d",(int)lierr);
6114           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6115           /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6116           k = temp_constraints;
6117           if (k > size_of_constraint) k = size_of_constraint;
6118           j = 0;
6119           while (j < k && singular_vals[k-j-1] < tol) j++;
6120           valid_constraints = k-j;
6121           total_counts = total_counts-temp_constraints+valid_constraints;
6122 #endif /* on missing GESVD */
6123         }
6124       }
6125       /* update pointers information */
6126       if (valid_constraints) {
6127         constraints_n[total_counts_cc] = valid_constraints;
6128         constraints_idxs_ptr[total_counts_cc+1] = constraints_idxs_ptr[total_counts_cc]+size_of_constraint;
6129         constraints_data_ptr[total_counts_cc+1] = constraints_data_ptr[total_counts_cc]+size_of_constraint*valid_constraints;
6130         /* set change_of_basis flag */
6131         if (boolforchange) {
6132           PetscBTSet(change_basis,total_counts_cc);
6133         }
6134         total_counts_cc++;
6135       }
6136     }
6137     /* free workspace */
6138     if (!skip_lapack) {
6139       ierr = PetscFree(work);CHKERRQ(ierr);
6140 #if defined(PETSC_USE_COMPLEX)
6141       ierr = PetscFree(rwork);CHKERRQ(ierr);
6142 #endif
6143       ierr = PetscFree(singular_vals);CHKERRQ(ierr);
6144 #if defined(PETSC_MISSING_LAPACK_GESVD)
6145       ierr = PetscFree(correlation_mat);CHKERRQ(ierr);
6146       ierr = PetscFree(temp_basis);CHKERRQ(ierr);
6147 #endif
6148     }
6149     for (k=0;k<nnsp_size;k++) {
6150       ierr = VecDestroy(&localnearnullsp[k]);CHKERRQ(ierr);
6151     }
6152     ierr = PetscFree(localnearnullsp);CHKERRQ(ierr);
6153     /* free index sets of faces, edges and vertices */
6154     for (i=0;i<n_ISForFaces;i++) {
6155       ierr = ISDestroy(&ISForFaces[i]);CHKERRQ(ierr);
6156     }
6157     if (n_ISForFaces) {
6158       ierr = PetscFree(ISForFaces);CHKERRQ(ierr);
6159     }
6160     for (i=0;i<n_ISForEdges;i++) {
6161       ierr = ISDestroy(&ISForEdges[i]);CHKERRQ(ierr);
6162     }
6163     if (n_ISForEdges) {
6164       ierr = PetscFree(ISForEdges);CHKERRQ(ierr);
6165     }
6166     ierr = ISDestroy(&ISForVertices);CHKERRQ(ierr);
6167   } else {
6168     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6169 
6170     total_counts = 0;
6171     n_vertices = 0;
6172     if (sub_schurs->is_vertices && pcbddc->use_vertices) {
6173       ierr = ISGetLocalSize(sub_schurs->is_vertices,&n_vertices);CHKERRQ(ierr);
6174     }
6175     max_constraints = 0;
6176     total_counts_cc = 0;
6177     for (i=0;i<sub_schurs->n_subs+n_vertices;i++) {
6178       total_counts += pcbddc->adaptive_constraints_n[i];
6179       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
6180       max_constraints = PetscMax(max_constraints,pcbddc->adaptive_constraints_n[i]);
6181     }
6182     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
6183     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
6184     constraints_idxs = pcbddc->adaptive_constraints_idxs;
6185     constraints_data = pcbddc->adaptive_constraints_data;
6186     /* constraints_n differs from pcbddc->adaptive_constraints_n */
6187     ierr = PetscMalloc1(total_counts_cc,&constraints_n);CHKERRQ(ierr);
6188     total_counts_cc = 0;
6189     for (i=0;i<sub_schurs->n_subs+n_vertices;i++) {
6190       if (pcbddc->adaptive_constraints_n[i]) {
6191         constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
6192       }
6193     }
6194 #if 0
6195     printf("Found %d totals (%d)\n",total_counts_cc,total_counts);
6196     for (i=0;i<total_counts_cc;i++) {
6197       printf("const %d, start %d",i,constraints_idxs_ptr[i]);
6198       printf(" end %d:\n",constraints_idxs_ptr[i+1]);
6199       for (j=constraints_idxs_ptr[i];j<constraints_idxs_ptr[i+1];j++) {
6200         printf(" %d",constraints_idxs[j]);
6201       }
6202       printf("\n");
6203       printf("number of cc: %d\n",constraints_n[i]);
6204     }
6205     for (i=0;i<n_vertices;i++) {
6206       PetscPrintf(PETSC_COMM_SELF,"[%d] vertex %d, n %d\n",PetscGlobalRank,i,pcbddc->adaptive_constraints_n[i]);
6207     }
6208     for (i=0;i<sub_schurs->n_subs;i++) {
6209       PetscPrintf(PETSC_COMM_SELF,"[%d] sub %d, edge %d, n %d\n",PetscGlobalRank,i,(PetscBool)PetscBTLookup(sub_schurs->is_edge,i),pcbddc->adaptive_constraints_n[i+n_vertices]);
6210     }
6211 #endif
6212 
6213     max_size_of_constraint = 0;
6214     for (i=0;i<total_counts_cc;i++) max_size_of_constraint = PetscMax(max_size_of_constraint,constraints_idxs_ptr[i+1]-constraints_idxs_ptr[i]);
6215     ierr = PetscMalloc1(constraints_idxs_ptr[total_counts_cc],&constraints_idxs_B);CHKERRQ(ierr);
6216     /* Change of basis */
6217     ierr = PetscBTCreate(total_counts_cc,&change_basis);CHKERRQ(ierr);
6218     if (pcbddc->use_change_of_basis) {
6219       for (i=0;i<sub_schurs->n_subs;i++) {
6220         if (PetscBTLookup(sub_schurs->is_edge,i) || pcbddc->use_change_on_faces) {
6221           ierr = PetscBTSet(change_basis,i+n_vertices);CHKERRQ(ierr);
6222         }
6223       }
6224     }
6225   }
6226   pcbddc->local_primal_size = total_counts;
6227   ierr = PetscMalloc1(pcbddc->local_primal_size+pcbddc->benign_n,&pcbddc->primal_indices_local_idxs);CHKERRQ(ierr);
6228 
6229   /* map constraints_idxs in boundary numbering */
6230   ierr = ISGlobalToLocalMappingApply(pcis->BtoNmap,IS_GTOLM_DROP,constraints_idxs_ptr[total_counts_cc],constraints_idxs,&i,constraints_idxs_B);CHKERRQ(ierr);
6231   if (i != constraints_idxs_ptr[total_counts_cc]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in boundary numbering for constraints indices %D != %D\n",constraints_idxs_ptr[total_counts_cc],i);
6232 
6233   /* Create constraint matrix */
6234   ierr = MatCreate(PETSC_COMM_SELF,&pcbddc->ConstraintMatrix);CHKERRQ(ierr);
6235   ierr = MatSetType(pcbddc->ConstraintMatrix,MATAIJ);CHKERRQ(ierr);
6236   ierr = MatSetSizes(pcbddc->ConstraintMatrix,pcbddc->local_primal_size,pcis->n,pcbddc->local_primal_size,pcis->n);CHKERRQ(ierr);
6237 
6238   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6239   /* determine if a QR strategy is needed for change of basis */
6240   qr_needed = PETSC_FALSE;
6241   ierr = PetscBTCreate(total_counts_cc,&qr_needed_idx);CHKERRQ(ierr);
6242   total_primal_vertices=0;
6243   pcbddc->local_primal_size_cc = 0;
6244   for (i=0;i<total_counts_cc;i++) {
6245     size_of_constraint = constraints_idxs_ptr[i+1]-constraints_idxs_ptr[i];
6246     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
6247       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6248       pcbddc->local_primal_size_cc += 1;
6249     } else if (PetscBTLookup(change_basis,i)) {
6250       for (k=0;k<constraints_n[i];k++) {
6251         pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]+k];
6252       }
6253       pcbddc->local_primal_size_cc += constraints_n[i];
6254       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
6255         PetscBTSet(qr_needed_idx,i);
6256         qr_needed = PETSC_TRUE;
6257       }
6258     } else {
6259       pcbddc->local_primal_size_cc += 1;
6260     }
6261   }
6262   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6263   pcbddc->n_vertices = total_primal_vertices;
6264   /* permute indices in order to have a sorted set of vertices */
6265   ierr = PetscSortInt(total_primal_vertices,pcbddc->primal_indices_local_idxs);CHKERRQ(ierr);
6266   ierr = PetscMalloc2(pcbddc->local_primal_size_cc+pcbddc->benign_n,&pcbddc->local_primal_ref_node,pcbddc->local_primal_size_cc+pcbddc->benign_n,&pcbddc->local_primal_ref_mult);CHKERRQ(ierr);
6267   ierr = PetscMemcpy(pcbddc->local_primal_ref_node,pcbddc->primal_indices_local_idxs,total_primal_vertices*sizeof(PetscInt));CHKERRQ(ierr);
6268   for (i=0;i<total_primal_vertices;i++) pcbddc->local_primal_ref_mult[i] = 1;
6269 
6270   /* nonzero structure of constraint matrix */
6271   /* and get reference dof for local constraints */
6272   ierr = PetscMalloc1(pcbddc->local_primal_size,&nnz);CHKERRQ(ierr);
6273   for (i=0;i<total_primal_vertices;i++) nnz[i] = 1;
6274 
6275   j = total_primal_vertices;
6276   total_counts = total_primal_vertices;
6277   cum = total_primal_vertices;
6278   for (i=n_vertices;i<total_counts_cc;i++) {
6279     if (!PetscBTLookup(change_basis,i)) {
6280       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6281       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6282       cum++;
6283       size_of_constraint = constraints_idxs_ptr[i+1]-constraints_idxs_ptr[i];
6284       for (k=0;k<constraints_n[i];k++) {
6285         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i]+k];
6286         nnz[j+k] = size_of_constraint;
6287       }
6288       j += constraints_n[i];
6289     }
6290   }
6291   ierr = MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix,0,nnz);CHKERRQ(ierr);
6292   ierr = PetscFree(nnz);CHKERRQ(ierr);
6293 
6294   /* set values in constraint matrix */
6295   for (i=0;i<total_primal_vertices;i++) {
6296     ierr = MatSetValue(pcbddc->ConstraintMatrix,i,pcbddc->local_primal_ref_node[i],1.0,INSERT_VALUES);CHKERRQ(ierr);
6297   }
6298   total_counts = total_primal_vertices;
6299   for (i=n_vertices;i<total_counts_cc;i++) {
6300     if (!PetscBTLookup(change_basis,i)) {
6301       PetscInt *cols;
6302 
6303       size_of_constraint = constraints_idxs_ptr[i+1]-constraints_idxs_ptr[i];
6304       cols = constraints_idxs+constraints_idxs_ptr[i];
6305       for (k=0;k<constraints_n[i];k++) {
6306         PetscInt    row = total_counts+k;
6307         PetscScalar *vals;
6308 
6309         vals = constraints_data+constraints_data_ptr[i]+k*size_of_constraint;
6310         ierr = MatSetValues(pcbddc->ConstraintMatrix,1,&row,size_of_constraint,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
6311       }
6312       total_counts += constraints_n[i];
6313     }
6314   }
6315   /* assembling */
6316   ierr = MatAssemblyBegin(pcbddc->ConstraintMatrix,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6317   ierr = MatAssemblyEnd(pcbddc->ConstraintMatrix,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6318   ierr = MatChop(pcbddc->ConstraintMatrix,PETSC_SMALL);CHKERRQ(ierr);
6319   ierr = MatSeqAIJCompress(pcbddc->ConstraintMatrix,&pcbddc->ConstraintMatrix);CHKERRQ(ierr);
6320   ierr = MatViewFromOptions(pcbddc->ConstraintMatrix,NULL,"-pc_bddc_constraint_mat_view");CHKERRQ(ierr);
6321 
6322   /*
6323   ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_SELF,PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr);
6324   ierr = MatView(pcbddc->ConstraintMatrix,(PetscViewer)0);CHKERRQ(ierr);
6325   ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
6326   */
6327   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6328   if (pcbddc->use_change_of_basis) {
6329     /* dual and primal dofs on a single cc */
6330     PetscInt     dual_dofs,primal_dofs;
6331     /* working stuff for GEQRF */
6332     PetscScalar  *qr_basis,*qr_tau = NULL,*qr_work,lqr_work_t;
6333     PetscBLASInt lqr_work;
6334     /* working stuff for UNGQR */
6335     PetscScalar  *gqr_work,lgqr_work_t;
6336     PetscBLASInt lgqr_work;
6337     /* working stuff for TRTRS */
6338     PetscScalar  *trs_rhs;
6339     PetscBLASInt Blas_NRHS;
6340     /* pointers for values insertion into change of basis matrix */
6341     PetscInt     *start_rows,*start_cols;
6342     PetscScalar  *start_vals;
6343     /* working stuff for values insertion */
6344     PetscBT      is_primal;
6345     PetscInt     *aux_primal_numbering_B;
6346     /* matrix sizes */
6347     PetscInt     global_size,local_size;
6348     /* temporary change of basis */
6349     Mat          localChangeOfBasisMatrix;
6350     /* extra space for debugging */
6351     PetscScalar  *dbg_work;
6352 
6353     /* local temporary change of basis acts on local interfaces -> dimension is n_B x n_B */
6354     ierr = MatCreate(PETSC_COMM_SELF,&localChangeOfBasisMatrix);CHKERRQ(ierr);
6355     ierr = MatSetType(localChangeOfBasisMatrix,MATAIJ);CHKERRQ(ierr);
6356     ierr = MatSetSizes(localChangeOfBasisMatrix,pcis->n,pcis->n,pcis->n,pcis->n);CHKERRQ(ierr);
6357     /* nonzeros for local mat */
6358     ierr = PetscMalloc1(pcis->n,&nnz);CHKERRQ(ierr);
6359     if (!pcbddc->benign_change || pcbddc->fake_change) {
6360       for (i=0;i<pcis->n;i++) nnz[i]=1;
6361     } else {
6362       const PetscInt *ii;
6363       PetscInt       n;
6364       PetscBool      flg_row;
6365       ierr = MatGetRowIJ(pcbddc->benign_change,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,NULL,&flg_row);CHKERRQ(ierr);
6366       for (i=0;i<n;i++) nnz[i] = ii[i+1]-ii[i];
6367       ierr = MatRestoreRowIJ(pcbddc->benign_change,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,NULL,&flg_row);CHKERRQ(ierr);
6368     }
6369     for (i=n_vertices;i<total_counts_cc;i++) {
6370       if (PetscBTLookup(change_basis,i)) {
6371         size_of_constraint = constraints_idxs_ptr[i+1]-constraints_idxs_ptr[i];
6372         if (PetscBTLookup(qr_needed_idx,i)) {
6373           for (j=0;j<size_of_constraint;j++) nnz[constraints_idxs[constraints_idxs_ptr[i]+j]] = size_of_constraint;
6374         } else {
6375           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
6376           for (j=1;j<size_of_constraint;j++) nnz[constraints_idxs[constraints_idxs_ptr[i]+j]] = 2;
6377         }
6378       }
6379     }
6380     ierr = MatSeqAIJSetPreallocation(localChangeOfBasisMatrix,0,nnz);CHKERRQ(ierr);
6381     ierr = PetscFree(nnz);CHKERRQ(ierr);
6382     /* Set interior change in the matrix */
6383     if (!pcbddc->benign_change || pcbddc->fake_change) {
6384       for (i=0;i<pcis->n;i++) {
6385         ierr = MatSetValue(localChangeOfBasisMatrix,i,i,1.0,INSERT_VALUES);CHKERRQ(ierr);
6386       }
6387     } else {
6388       const PetscInt *ii,*jj;
6389       PetscScalar    *aa;
6390       PetscInt       n;
6391       PetscBool      flg_row;
6392       ierr = MatGetRowIJ(pcbddc->benign_change,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,&jj,&flg_row);CHKERRQ(ierr);
6393       ierr = MatSeqAIJGetArray(pcbddc->benign_change,&aa);CHKERRQ(ierr);
6394       for (i=0;i<n;i++) {
6395         ierr = MatSetValues(localChangeOfBasisMatrix,1,&i,ii[i+1]-ii[i],jj+ii[i],aa+ii[i],INSERT_VALUES);CHKERRQ(ierr);
6396       }
6397       ierr = MatSeqAIJRestoreArray(pcbddc->benign_change,&aa);CHKERRQ(ierr);
6398       ierr = MatRestoreRowIJ(pcbddc->benign_change,0,PETSC_FALSE,PETSC_FALSE,&n,&ii,&jj,&flg_row);CHKERRQ(ierr);
6399     }
6400 
6401     if (pcbddc->dbg_flag) {
6402       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"--------------------------------------------------------------\n");CHKERRQ(ierr);
6403       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Checking change of basis computation for subdomain %04d\n",PetscGlobalRank);CHKERRQ(ierr);
6404     }
6405 
6406 
6407     /* Now we loop on the constraints which need a change of basis */
6408     /*
6409        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
6410        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
6411 
6412        Basic blocks of change of basis matrix T computed by
6413 
6414           - Using the following block transformation if there is only a primal dof on the cc (and -pc_bddc_use_qr_single is not specified)
6415 
6416             | 1        0   ...        0         s_1/S |
6417             | 0        1   ...        0         s_2/S |
6418             |              ...                        |
6419             | 0        ...            1     s_{n-1}/S |
6420             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
6421 
6422             with S = \sum_{i=1}^n s_i^2
6423             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
6424                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
6425 
6426           - QR decomposition of constraints otherwise
6427     */
6428     if (qr_needed) {
6429       /* space to store Q */
6430       ierr = PetscMalloc1(max_size_of_constraint*max_size_of_constraint,&qr_basis);CHKERRQ(ierr);
6431       /* array to store scaling factors for reflectors */
6432       ierr = PetscMalloc1(max_constraints,&qr_tau);CHKERRQ(ierr);
6433       /* first we issue queries for optimal work */
6434       ierr = PetscBLASIntCast(max_size_of_constraint,&Blas_M);CHKERRQ(ierr);
6435       ierr = PetscBLASIntCast(max_constraints,&Blas_N);CHKERRQ(ierr);
6436       ierr = PetscBLASIntCast(max_size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6437       lqr_work = -1;
6438       PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&Blas_M,&Blas_N,qr_basis,&Blas_LDA,qr_tau,&lqr_work_t,&lqr_work,&lierr));
6439       if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in query to GEQRF Lapack routine %d",(int)lierr);
6440       ierr = PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t),&lqr_work);CHKERRQ(ierr);
6441       ierr = PetscMalloc1((PetscInt)PetscRealPart(lqr_work_t),&qr_work);CHKERRQ(ierr);
6442       lgqr_work = -1;
6443       ierr = PetscBLASIntCast(max_size_of_constraint,&Blas_M);CHKERRQ(ierr);
6444       ierr = PetscBLASIntCast(max_size_of_constraint,&Blas_N);CHKERRQ(ierr);
6445       ierr = PetscBLASIntCast(max_constraints,&Blas_K);CHKERRQ(ierr);
6446       ierr = PetscBLASIntCast(max_size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6447       if (Blas_K>Blas_M) Blas_K=Blas_M; /* adjust just for computing optimal work */
6448       PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&Blas_M,&Blas_N,&Blas_K,qr_basis,&Blas_LDA,qr_tau,&lgqr_work_t,&lgqr_work,&lierr));
6449       if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in query to ORGQR/UNGQR Lapack routine %d",(int)lierr);
6450       ierr = PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t),&lgqr_work);CHKERRQ(ierr);
6451       ierr = PetscMalloc1((PetscInt)PetscRealPart(lgqr_work_t),&gqr_work);CHKERRQ(ierr);
6452       /* array to store rhs and solution of triangular solver */
6453       ierr = PetscMalloc1(max_constraints*max_constraints,&trs_rhs);CHKERRQ(ierr);
6454       /* allocating workspace for check */
6455       if (pcbddc->dbg_flag) {
6456         ierr = PetscMalloc1(max_size_of_constraint*(max_constraints+max_size_of_constraint),&dbg_work);CHKERRQ(ierr);
6457       }
6458     }
6459     /* array to store whether a node is primal or not */
6460     ierr = PetscBTCreate(pcis->n_B,&is_primal);CHKERRQ(ierr);
6461     ierr = PetscMalloc1(total_primal_vertices,&aux_primal_numbering_B);CHKERRQ(ierr);
6462     ierr = ISGlobalToLocalMappingApply(pcis->BtoNmap,IS_GTOLM_DROP,total_primal_vertices,pcbddc->local_primal_ref_node,&i,aux_primal_numbering_B);CHKERRQ(ierr);
6463     if (i != total_primal_vertices) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in boundary numbering for BDDC vertices! %D != %D\n",total_primal_vertices,i);
6464     for (i=0;i<total_primal_vertices;i++) {
6465       ierr = PetscBTSet(is_primal,aux_primal_numbering_B[i]);CHKERRQ(ierr);
6466     }
6467     ierr = PetscFree(aux_primal_numbering_B);CHKERRQ(ierr);
6468 
6469     /* loop on constraints and see whether or not they need a change of basis and compute it */
6470     for (total_counts=n_vertices;total_counts<total_counts_cc;total_counts++) {
6471       size_of_constraint = constraints_idxs_ptr[total_counts+1]-constraints_idxs_ptr[total_counts];
6472       if (PetscBTLookup(change_basis,total_counts)) {
6473         /* get constraint info */
6474         primal_dofs = constraints_n[total_counts];
6475         dual_dofs = size_of_constraint-primal_dofs;
6476 
6477         if (pcbddc->dbg_flag) {
6478           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Constraints %d: %d need a change of basis (size %d)\n",total_counts,primal_dofs,size_of_constraint);CHKERRQ(ierr);
6479         }
6480 
6481         if (PetscBTLookup(qr_needed_idx,total_counts)) { /* QR */
6482 
6483           /* copy quadrature constraints for change of basis check */
6484           if (pcbddc->dbg_flag) {
6485             ierr = PetscMemcpy(dbg_work,&constraints_data[constraints_data_ptr[total_counts]],size_of_constraint*primal_dofs*sizeof(PetscScalar));CHKERRQ(ierr);
6486           }
6487           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
6488           ierr = PetscMemcpy(qr_basis,&constraints_data[constraints_data_ptr[total_counts]],size_of_constraint*primal_dofs*sizeof(PetscScalar));CHKERRQ(ierr);
6489 
6490           /* compute QR decomposition of constraints */
6491           ierr = PetscBLASIntCast(size_of_constraint,&Blas_M);CHKERRQ(ierr);
6492           ierr = PetscBLASIntCast(primal_dofs,&Blas_N);CHKERRQ(ierr);
6493           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6494           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6495           PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&Blas_M,&Blas_N,qr_basis,&Blas_LDA,qr_tau,qr_work,&lqr_work,&lierr));
6496           if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in GEQRF Lapack routine %d",(int)lierr);
6497           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6498 
6499           /* explictly compute R^-T */
6500           ierr = PetscMemzero(trs_rhs,primal_dofs*primal_dofs*sizeof(*trs_rhs));CHKERRQ(ierr);
6501           for (j=0;j<primal_dofs;j++) trs_rhs[j*(primal_dofs+1)] = 1.0;
6502           ierr = PetscBLASIntCast(primal_dofs,&Blas_N);CHKERRQ(ierr);
6503           ierr = PetscBLASIntCast(primal_dofs,&Blas_NRHS);CHKERRQ(ierr);
6504           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6505           ierr = PetscBLASIntCast(primal_dofs,&Blas_LDB);CHKERRQ(ierr);
6506           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6507           PetscStackCallBLAS("LAPACKtrtrs",LAPACKtrtrs_("U","T","N",&Blas_N,&Blas_NRHS,qr_basis,&Blas_LDA,trs_rhs,&Blas_LDB,&lierr));
6508           if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in TRTRS Lapack routine %d",(int)lierr);
6509           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6510 
6511           /* explicitly compute all columns of Q (Q = [Q1 | Q2] ) overwriting QR factorization in qr_basis */
6512           ierr = PetscBLASIntCast(size_of_constraint,&Blas_M);CHKERRQ(ierr);
6513           ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6514           ierr = PetscBLASIntCast(primal_dofs,&Blas_K);CHKERRQ(ierr);
6515           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6516           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6517           PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&Blas_M,&Blas_N,&Blas_K,qr_basis,&Blas_LDA,qr_tau,gqr_work,&lgqr_work,&lierr));
6518           if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in ORGQR/UNGQR Lapack routine %d",(int)lierr);
6519           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6520 
6521           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
6522              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
6523              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
6524           ierr = PetscBLASIntCast(size_of_constraint,&Blas_M);CHKERRQ(ierr);
6525           ierr = PetscBLASIntCast(primal_dofs,&Blas_N);CHKERRQ(ierr);
6526           ierr = PetscBLASIntCast(primal_dofs,&Blas_K);CHKERRQ(ierr);
6527           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6528           ierr = PetscBLASIntCast(primal_dofs,&Blas_LDB);CHKERRQ(ierr);
6529           ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDC);CHKERRQ(ierr);
6530           ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6531           PetscStackCallBLAS("BLASgemm",BLASgemm_("N","N",&Blas_M,&Blas_N,&Blas_K,&one,qr_basis,&Blas_LDA,trs_rhs,&Blas_LDB,&zero,constraints_data+constraints_data_ptr[total_counts],&Blas_LDC));
6532           ierr = PetscFPTrapPop();CHKERRQ(ierr);
6533           ierr = PetscMemcpy(qr_basis,&constraints_data[constraints_data_ptr[total_counts]],size_of_constraint*primal_dofs*sizeof(PetscScalar));CHKERRQ(ierr);
6534 
6535           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
6536           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
6537           /* insert cols for primal dofs */
6538           for (j=0;j<primal_dofs;j++) {
6539             start_vals = &qr_basis[j*size_of_constraint];
6540             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts]+j];
6541             ierr = MatSetValues(localChangeOfBasisMatrix,size_of_constraint,start_rows,1,start_cols,start_vals,INSERT_VALUES);CHKERRQ(ierr);
6542           }
6543           /* insert cols for dual dofs */
6544           for (j=0,k=0;j<dual_dofs;k++) {
6545             if (!PetscBTLookup(is_primal,constraints_idxs_B[constraints_idxs_ptr[total_counts]+k])) {
6546               start_vals = &qr_basis[(primal_dofs+j)*size_of_constraint];
6547               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts]+k];
6548               ierr = MatSetValues(localChangeOfBasisMatrix,size_of_constraint,start_rows,1,start_cols,start_vals,INSERT_VALUES);CHKERRQ(ierr);
6549               j++;
6550             }
6551           }
6552 
6553           /* check change of basis */
6554           if (pcbddc->dbg_flag) {
6555             PetscInt   ii,jj;
6556             PetscBool valid_qr=PETSC_TRUE;
6557             ierr = PetscBLASIntCast(primal_dofs,&Blas_M);CHKERRQ(ierr);
6558             ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6559             ierr = PetscBLASIntCast(size_of_constraint,&Blas_K);CHKERRQ(ierr);
6560             ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDA);CHKERRQ(ierr);
6561             ierr = PetscBLASIntCast(size_of_constraint,&Blas_LDB);CHKERRQ(ierr);
6562             ierr = PetscBLASIntCast(primal_dofs,&Blas_LDC);CHKERRQ(ierr);
6563             ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
6564             PetscStackCallBLAS("BLASgemm",BLASgemm_("T","N",&Blas_M,&Blas_N,&Blas_K,&one,dbg_work,&Blas_LDA,qr_basis,&Blas_LDB,&zero,&dbg_work[size_of_constraint*primal_dofs],&Blas_LDC));
6565             ierr = PetscFPTrapPop();CHKERRQ(ierr);
6566             for (jj=0;jj<size_of_constraint;jj++) {
6567               for (ii=0;ii<primal_dofs;ii++) {
6568                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]) > 1.e-12) valid_qr = PETSC_FALSE;
6569                 if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]-(PetscReal)1) > 1.e-12) valid_qr = PETSC_FALSE;
6570               }
6571             }
6572             if (!valid_qr) {
6573               ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"\t-> wrong change of basis!\n");CHKERRQ(ierr);
6574               for (jj=0;jj<size_of_constraint;jj++) {
6575                 for (ii=0;ii<primal_dofs;ii++) {
6576                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]) > 1.e-12) {
6577                     PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"\tQr basis function %d is not orthogonal to constraint %d (%1.14e)!\n",jj,ii,PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]));
6578                   }
6579                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]-(PetscReal)1) > 1.e-12) {
6580                     PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"\tQr basis function %d is not unitary w.r.t constraint %d (%1.14e)!\n",jj,ii,PetscAbsScalar(dbg_work[size_of_constraint*primal_dofs+jj*primal_dofs+ii]));
6581                   }
6582                 }
6583               }
6584             } else {
6585               ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"\t-> right change of basis!\n");CHKERRQ(ierr);
6586             }
6587           }
6588         } else { /* simple transformation block */
6589           PetscInt    row,col;
6590           PetscScalar val,norm;
6591 
6592           ierr = PetscBLASIntCast(size_of_constraint,&Blas_N);CHKERRQ(ierr);
6593           PetscStackCallBLAS("BLASdot",norm = BLASdot_(&Blas_N,constraints_data+constraints_data_ptr[total_counts],&Blas_one,constraints_data+constraints_data_ptr[total_counts],&Blas_one));
6594           for (j=0;j<size_of_constraint;j++) {
6595             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts]+j];
6596             row = constraints_idxs[constraints_idxs_ptr[total_counts]+j];
6597             if (!PetscBTLookup(is_primal,row_B)) {
6598               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
6599               ierr = MatSetValue(localChangeOfBasisMatrix,row,row,1.0,INSERT_VALUES);CHKERRQ(ierr);
6600               ierr = MatSetValue(localChangeOfBasisMatrix,row,col,constraints_data[constraints_data_ptr[total_counts]+j]/norm,INSERT_VALUES);CHKERRQ(ierr);
6601             } else {
6602               for (k=0;k<size_of_constraint;k++) {
6603                 col = constraints_idxs[constraints_idxs_ptr[total_counts]+k];
6604                 if (row != col) {
6605                   val = -constraints_data[constraints_data_ptr[total_counts]+k]/constraints_data[constraints_data_ptr[total_counts]];
6606                 } else {
6607                   val = constraints_data[constraints_data_ptr[total_counts]]/norm;
6608                 }
6609                 ierr = MatSetValue(localChangeOfBasisMatrix,row,col,val,INSERT_VALUES);CHKERRQ(ierr);
6610               }
6611             }
6612           }
6613           if (pcbddc->dbg_flag) {
6614             ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"\t-> using standard change of basis\n");CHKERRQ(ierr);
6615           }
6616         }
6617       } else {
6618         if (pcbddc->dbg_flag) {
6619           ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Constraint %d does not need a change of basis (size %d)\n",total_counts,size_of_constraint);CHKERRQ(ierr);
6620         }
6621       }
6622     }
6623 
6624     /* free workspace */
6625     if (qr_needed) {
6626       if (pcbddc->dbg_flag) {
6627         ierr = PetscFree(dbg_work);CHKERRQ(ierr);
6628       }
6629       ierr = PetscFree(trs_rhs);CHKERRQ(ierr);
6630       ierr = PetscFree(qr_tau);CHKERRQ(ierr);
6631       ierr = PetscFree(qr_work);CHKERRQ(ierr);
6632       ierr = PetscFree(gqr_work);CHKERRQ(ierr);
6633       ierr = PetscFree(qr_basis);CHKERRQ(ierr);
6634     }
6635     ierr = PetscBTDestroy(&is_primal);CHKERRQ(ierr);
6636     ierr = MatAssemblyBegin(localChangeOfBasisMatrix,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6637     ierr = MatAssemblyEnd(localChangeOfBasisMatrix,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6638 
6639     /* assembling of global change of variable */
6640     if (!pcbddc->fake_change) {
6641       Mat      tmat;
6642       PetscInt bs;
6643 
6644       ierr = VecGetSize(pcis->vec1_global,&global_size);CHKERRQ(ierr);
6645       ierr = VecGetLocalSize(pcis->vec1_global,&local_size);CHKERRQ(ierr);
6646       ierr = MatDuplicate(pc->pmat,MAT_DO_NOT_COPY_VALUES,&tmat);CHKERRQ(ierr);
6647       ierr = MatISSetLocalMat(tmat,localChangeOfBasisMatrix);CHKERRQ(ierr);
6648       ierr = MatAssemblyBegin(tmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6649       ierr = MatAssemblyEnd(tmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6650       ierr = MatCreate(PetscObjectComm((PetscObject)pc),&pcbddc->ChangeOfBasisMatrix);CHKERRQ(ierr);
6651       ierr = MatSetType(pcbddc->ChangeOfBasisMatrix,MATAIJ);CHKERRQ(ierr);
6652       ierr = MatGetBlockSize(pc->pmat,&bs);CHKERRQ(ierr);
6653       ierr = MatSetBlockSize(pcbddc->ChangeOfBasisMatrix,bs);CHKERRQ(ierr);
6654       ierr = MatSetSizes(pcbddc->ChangeOfBasisMatrix,local_size,local_size,global_size,global_size);CHKERRQ(ierr);
6655       ierr = MatISSetMPIXAIJPreallocation_Private(tmat,pcbddc->ChangeOfBasisMatrix,PETSC_TRUE);CHKERRQ(ierr);
6656       ierr = MatConvert(tmat,MATAIJ,MAT_REUSE_MATRIX,&pcbddc->ChangeOfBasisMatrix);CHKERRQ(ierr);
6657       ierr = MatDestroy(&tmat);CHKERRQ(ierr);
6658       ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr);
6659       ierr = VecSet(pcis->vec1_N,1.0);CHKERRQ(ierr);
6660       ierr = VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6661       ierr = VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6662       ierr = VecReciprocal(pcis->vec1_global);CHKERRQ(ierr);
6663       ierr = MatDiagonalScale(pcbddc->ChangeOfBasisMatrix,pcis->vec1_global,NULL);CHKERRQ(ierr);
6664 
6665       /* check */
6666       if (pcbddc->dbg_flag) {
6667         PetscReal error;
6668         Vec       x,x_change;
6669 
6670         ierr = VecDuplicate(pcis->vec1_global,&x);CHKERRQ(ierr);
6671         ierr = VecDuplicate(pcis->vec1_global,&x_change);CHKERRQ(ierr);
6672         ierr = VecSetRandom(x,NULL);CHKERRQ(ierr);
6673         ierr = VecCopy(x,pcis->vec1_global);CHKERRQ(ierr);
6674         ierr = VecScatterBegin(matis->rctx,x,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6675         ierr = VecScatterEnd(matis->rctx,x,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6676         ierr = MatMult(localChangeOfBasisMatrix,pcis->vec1_N,pcis->vec2_N);CHKERRQ(ierr);
6677         ierr = VecScatterBegin(matis->rctx,pcis->vec2_N,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6678         ierr = VecScatterEnd(matis->rctx,pcis->vec2_N,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6679         ierr = MatMult(pcbddc->ChangeOfBasisMatrix,pcis->vec1_global,x_change);CHKERRQ(ierr);
6680         ierr = VecAXPY(x,-1.0,x_change);CHKERRQ(ierr);
6681         ierr = VecNorm(x,NORM_INFINITY,&error);CHKERRQ(ierr);
6682         if (error > PETSC_SMALL) {
6683           SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Error global vs local change on N: %1.6e\n",error);
6684         }
6685         ierr = VecDestroy(&x);CHKERRQ(ierr);
6686         ierr = VecDestroy(&x_change);CHKERRQ(ierr);
6687       }
6688       /* adapt sub_schurs computed (if any) */
6689       if (pcbddc->use_deluxe_scaling) {
6690         PCBDDCSubSchurs sub_schurs=pcbddc->sub_schurs;
6691 
6692         if (pcbddc->use_change_of_basis && pcbddc->adaptive_userdefined) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot mix automatic change of basis, adaptive selection and user-defined constraints");
6693         if (sub_schurs && sub_schurs->S_Ej_all) {
6694           Mat                    S_new,tmat;
6695           IS                     is_all_N,is_V_Sall = NULL;
6696 
6697           ierr = ISLocalToGlobalMappingApplyIS(pcis->BtoNmap,sub_schurs->is_Ej_all,&is_all_N);CHKERRQ(ierr);
6698           ierr = MatCreateSubMatrix(localChangeOfBasisMatrix,is_all_N,is_all_N,MAT_INITIAL_MATRIX,&tmat);CHKERRQ(ierr);
6699           if (pcbddc->deluxe_zerorows) {
6700             ISLocalToGlobalMapping NtoSall;
6701             IS                     is_V;
6702             ierr = ISCreateGeneral(PETSC_COMM_SELF,pcbddc->n_vertices,pcbddc->local_primal_ref_node,PETSC_COPY_VALUES,&is_V);CHKERRQ(ierr);
6703             ierr = ISLocalToGlobalMappingCreateIS(is_all_N,&NtoSall);CHKERRQ(ierr);
6704             ierr = ISGlobalToLocalMappingApplyIS(NtoSall,IS_GTOLM_DROP,is_V,&is_V_Sall);CHKERRQ(ierr);
6705             ierr = ISLocalToGlobalMappingDestroy(&NtoSall);CHKERRQ(ierr);
6706             ierr = ISDestroy(&is_V);CHKERRQ(ierr);
6707           }
6708           ierr = ISDestroy(&is_all_N);CHKERRQ(ierr);
6709           ierr = MatPtAP(sub_schurs->S_Ej_all,tmat,MAT_INITIAL_MATRIX,1.0,&S_new);CHKERRQ(ierr);
6710           ierr = MatDestroy(&sub_schurs->S_Ej_all);CHKERRQ(ierr);
6711           ierr = PetscObjectReference((PetscObject)S_new);CHKERRQ(ierr);
6712           if (pcbddc->deluxe_zerorows) {
6713             const PetscScalar *array;
6714             const PetscInt    *idxs_V,*idxs_all;
6715             PetscInt          i,n_V;
6716 
6717             ierr = MatZeroRowsColumnsIS(S_new,is_V_Sall,1.,NULL,NULL);CHKERRQ(ierr);
6718             ierr = ISGetLocalSize(is_V_Sall,&n_V);CHKERRQ(ierr);
6719             ierr = ISGetIndices(is_V_Sall,&idxs_V);CHKERRQ(ierr);
6720             ierr = ISGetIndices(sub_schurs->is_Ej_all,&idxs_all);CHKERRQ(ierr);
6721             ierr = VecGetArrayRead(pcis->D,&array);CHKERRQ(ierr);
6722             for (i=0;i<n_V;i++) {
6723               PetscScalar val;
6724               PetscInt    idx;
6725 
6726               idx = idxs_V[i];
6727               val = array[idxs_all[idxs_V[i]]];
6728               ierr = MatSetValue(S_new,idx,idx,val,INSERT_VALUES);CHKERRQ(ierr);
6729             }
6730             ierr = MatAssemblyBegin(S_new,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6731             ierr = MatAssemblyEnd(S_new,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6732             ierr = VecRestoreArrayRead(pcis->D,&array);CHKERRQ(ierr);
6733             ierr = ISRestoreIndices(sub_schurs->is_Ej_all,&idxs_all);CHKERRQ(ierr);
6734             ierr = ISRestoreIndices(is_V_Sall,&idxs_V);CHKERRQ(ierr);
6735           }
6736           sub_schurs->S_Ej_all = S_new;
6737           ierr = MatDestroy(&S_new);CHKERRQ(ierr);
6738           if (sub_schurs->sum_S_Ej_all) {
6739             ierr = MatPtAP(sub_schurs->sum_S_Ej_all,tmat,MAT_INITIAL_MATRIX,1.0,&S_new);CHKERRQ(ierr);
6740             ierr = MatDestroy(&sub_schurs->sum_S_Ej_all);CHKERRQ(ierr);
6741             ierr = PetscObjectReference((PetscObject)S_new);CHKERRQ(ierr);
6742             if (pcbddc->deluxe_zerorows) {
6743               ierr = MatZeroRowsColumnsIS(S_new,is_V_Sall,1.,NULL,NULL);CHKERRQ(ierr);
6744             }
6745             sub_schurs->sum_S_Ej_all = S_new;
6746             ierr = MatDestroy(&S_new);CHKERRQ(ierr);
6747           }
6748           ierr = ISDestroy(&is_V_Sall);CHKERRQ(ierr);
6749           ierr = MatDestroy(&tmat);CHKERRQ(ierr);
6750         }
6751         /* destroy any change of basis context in sub_schurs */
6752         if (sub_schurs && sub_schurs->change) {
6753           PetscInt i;
6754 
6755           for (i=0;i<sub_schurs->n_subs;i++) {
6756             ierr = KSPDestroy(&sub_schurs->change[i]);CHKERRQ(ierr);
6757           }
6758           ierr = PetscFree(sub_schurs->change);CHKERRQ(ierr);
6759         }
6760       }
6761       if (pcbddc->switch_static) { /* need to save the local change */
6762         pcbddc->switch_static_change = localChangeOfBasisMatrix;
6763       } else {
6764         ierr = MatDestroy(&localChangeOfBasisMatrix);CHKERRQ(ierr);
6765       }
6766       /* determine if any process has changed the pressures locally */
6767       pcbddc->change_interior = pcbddc->benign_have_null;
6768     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
6769       ierr = MatDestroy(&pcbddc->ConstraintMatrix);CHKERRQ(ierr);
6770       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
6771       pcbddc->use_qr_single = qr_needed;
6772     }
6773   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
6774     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
6775       ierr = PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix);CHKERRQ(ierr);
6776       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
6777     } else {
6778       Mat benign_global = NULL;
6779       if (pcbddc->benign_have_null) {
6780         Mat tmat;
6781 
6782         pcbddc->change_interior = PETSC_TRUE;
6783         ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr);
6784         ierr = VecSet(pcis->vec1_N,1.0);CHKERRQ(ierr);
6785         ierr = VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6786         ierr = VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6787         ierr = VecReciprocal(pcis->vec1_global);CHKERRQ(ierr);
6788         ierr = VecScatterBegin(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6789         ierr = VecScatterEnd(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6790         ierr = MatDuplicate(pc->pmat,MAT_DO_NOT_COPY_VALUES,&tmat);CHKERRQ(ierr);
6791         if (pcbddc->benign_change) {
6792           Mat M;
6793 
6794           ierr = MatDuplicate(pcbddc->benign_change,MAT_COPY_VALUES,&M);CHKERRQ(ierr);
6795           ierr = MatDiagonalScale(M,pcis->vec1_N,NULL);CHKERRQ(ierr);
6796           ierr = MatISSetLocalMat(tmat,M);CHKERRQ(ierr);
6797           ierr = MatDestroy(&M);CHKERRQ(ierr);
6798         } else {
6799           Mat         eye;
6800           PetscScalar *array;
6801 
6802           ierr = VecGetArray(pcis->vec1_N,&array);CHKERRQ(ierr);
6803           ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,pcis->n,pcis->n,1,NULL,&eye);CHKERRQ(ierr);
6804           for (i=0;i<pcis->n;i++) {
6805             ierr = MatSetValue(eye,i,i,array[i],INSERT_VALUES);CHKERRQ(ierr);
6806           }
6807           ierr = VecRestoreArray(pcis->vec1_N,&array);CHKERRQ(ierr);
6808           ierr = MatAssemblyBegin(eye,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6809           ierr = MatAssemblyEnd(eye,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6810           ierr = MatISSetLocalMat(tmat,eye);CHKERRQ(ierr);
6811           ierr = MatDestroy(&eye);CHKERRQ(ierr);
6812         }
6813         ierr = MatAssemblyBegin(tmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6814         ierr = MatAssemblyEnd(tmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
6815         ierr = MatConvert(tmat,MATAIJ,MAT_INITIAL_MATRIX,&benign_global);CHKERRQ(ierr);
6816         ierr = MatDestroy(&tmat);CHKERRQ(ierr);
6817       }
6818       if (pcbddc->user_ChangeOfBasisMatrix) {
6819         ierr = MatMatMult(pcbddc->user_ChangeOfBasisMatrix,benign_global,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&pcbddc->ChangeOfBasisMatrix);CHKERRQ(ierr);
6820         ierr = MatDestroy(&benign_global);CHKERRQ(ierr);
6821       } else if (pcbddc->benign_have_null) {
6822         pcbddc->ChangeOfBasisMatrix = benign_global;
6823       }
6824     }
6825     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
6826       IS             is_global;
6827       const PetscInt *gidxs;
6828 
6829       ierr = ISLocalToGlobalMappingGetIndices(pc->pmat->rmap->mapping,&gidxs);CHKERRQ(ierr);
6830       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),pcis->n,gidxs,PETSC_COPY_VALUES,&is_global);CHKERRQ(ierr);
6831       ierr = ISLocalToGlobalMappingRestoreIndices(pc->pmat->rmap->mapping,&gidxs);CHKERRQ(ierr);
6832       ierr = MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix,is_global,is_global,&pcbddc->switch_static_change);CHKERRQ(ierr);
6833       ierr = ISDestroy(&is_global);CHKERRQ(ierr);
6834     }
6835   }
6836   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) {
6837     ierr = VecDuplicate(pcis->vec1_global,&pcbddc->work_change);CHKERRQ(ierr);
6838   }
6839 
6840   if (!pcbddc->fake_change) {
6841     /* add pressure dofs to set of primal nodes for numbering purposes */
6842     for (i=0;i<pcbddc->benign_n;i++) {
6843       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc] = pcbddc->benign_p0_lidx[i];
6844       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
6845       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc] = 1;
6846       pcbddc->local_primal_size_cc++;
6847       pcbddc->local_primal_size++;
6848     }
6849 
6850     /* check if a new primal space has been introduced (also take into account benign trick) */
6851     pcbddc->new_primal_space_local = PETSC_TRUE;
6852     if (olocal_primal_size == pcbddc->local_primal_size) {
6853       ierr = PetscMemcmp(pcbddc->local_primal_ref_node,olocal_primal_ref_node,olocal_primal_size_cc*sizeof(PetscInt),&pcbddc->new_primal_space_local);CHKERRQ(ierr);
6854       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
6855       if (!pcbddc->new_primal_space_local) {
6856         ierr = PetscMemcmp(pcbddc->local_primal_ref_mult,olocal_primal_ref_mult,olocal_primal_size_cc*sizeof(PetscInt),&pcbddc->new_primal_space_local);CHKERRQ(ierr);
6857         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
6858       }
6859     }
6860     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
6861     ierr = MPIU_Allreduce(&pcbddc->new_primal_space_local,&pcbddc->new_primal_space,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
6862   }
6863   ierr = PetscFree2(olocal_primal_ref_node,olocal_primal_ref_mult);CHKERRQ(ierr);
6864 
6865   /* flush dbg viewer */
6866   if (pcbddc->dbg_flag) {
6867     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
6868   }
6869 
6870   /* free workspace */
6871   ierr = PetscBTDestroy(&qr_needed_idx);CHKERRQ(ierr);
6872   ierr = PetscBTDestroy(&change_basis);CHKERRQ(ierr);
6873   if (!pcbddc->adaptive_selection) {
6874     ierr = PetscFree3(constraints_idxs_ptr,constraints_data_ptr,constraints_n);CHKERRQ(ierr);
6875     ierr = PetscFree3(constraints_data,constraints_idxs,constraints_idxs_B);CHKERRQ(ierr);
6876   } else {
6877     ierr = PetscFree5(pcbddc->adaptive_constraints_n,
6878                       pcbddc->adaptive_constraints_idxs_ptr,
6879                       pcbddc->adaptive_constraints_data_ptr,
6880                       pcbddc->adaptive_constraints_idxs,
6881                       pcbddc->adaptive_constraints_data);CHKERRQ(ierr);
6882     ierr = PetscFree(constraints_n);CHKERRQ(ierr);
6883     ierr = PetscFree(constraints_idxs_B);CHKERRQ(ierr);
6884   }
6885   PetscFunctionReturn(0);
6886 }
6887 /* #undef PETSC_MISSING_LAPACK_GESVD */
6888 
6889 PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
6890 {
6891   ISLocalToGlobalMapping map;
6892   PC_BDDC                *pcbddc = (PC_BDDC*)pc->data;
6893   Mat_IS                 *matis  = (Mat_IS*)pc->pmat->data;
6894   PetscInt               i,N;
6895   PetscBool              rcsr = PETSC_FALSE;
6896   PetscErrorCode         ierr;
6897 
6898   PetscFunctionBegin;
6899   if (pcbddc->recompute_topography) {
6900     pcbddc->graphanalyzed = PETSC_FALSE;
6901     /* Reset previously computed graph */
6902     ierr = PCBDDCGraphReset(pcbddc->mat_graph);CHKERRQ(ierr);
6903     /* Init local Graph struct */
6904     ierr = MatGetSize(pc->pmat,&N,NULL);CHKERRQ(ierr);
6905     ierr = MatGetLocalToGlobalMapping(pc->pmat,&map,NULL);CHKERRQ(ierr);
6906     ierr = PCBDDCGraphInit(pcbddc->mat_graph,map,N,pcbddc->graphmaxcount);CHKERRQ(ierr);
6907 
6908     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) {
6909       ierr = PCBDDCConsistencyCheckIS(pc,MPI_LOR,&pcbddc->user_primal_vertices_local);CHKERRQ(ierr);
6910     }
6911     /* Check validity of the csr graph passed in by the user */
6912     if (pcbddc->mat_graph->nvtxs_csr && pcbddc->mat_graph->nvtxs_csr != pcbddc->mat_graph->nvtxs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid size of local CSR graph! Found %D, expected %D\n",pcbddc->mat_graph->nvtxs_csr,pcbddc->mat_graph->nvtxs);
6913 
6914     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
6915     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
6916       PetscInt  *xadj,*adjncy;
6917       PetscInt  nvtxs;
6918       PetscBool flg_row=PETSC_FALSE;
6919 
6920       ierr = MatGetRowIJ(matis->A,0,PETSC_TRUE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&flg_row);CHKERRQ(ierr);
6921       if (flg_row) {
6922         ierr = PCBDDCSetLocalAdjacencyGraph(pc,nvtxs,xadj,adjncy,PETSC_COPY_VALUES);CHKERRQ(ierr);
6923         pcbddc->computed_rowadj = PETSC_TRUE;
6924       }
6925       ierr = MatRestoreRowIJ(matis->A,0,PETSC_TRUE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&flg_row);CHKERRQ(ierr);
6926       rcsr = PETSC_TRUE;
6927     }
6928     if (pcbddc->dbg_flag) {
6929       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
6930     }
6931 
6932     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
6933       PetscReal    *lcoords;
6934       PetscInt     n;
6935       MPI_Datatype dimrealtype;
6936 
6937       if (pcbddc->mat_graph->cnloc != pc->pmat->rmap->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local coordinates! Got %D, expected %D",pcbddc->mat_graph->cnloc,pc->pmat->rmap->n);
6938       ierr = MatGetLocalSize(matis->A,&n,NULL);CHKERRQ(ierr);
6939       ierr = MatISSetUpSF(pc->pmat);CHKERRQ(ierr);
6940       ierr = PetscMalloc1(pcbddc->mat_graph->cdim*n,&lcoords);CHKERRQ(ierr);
6941       ierr = MPI_Type_contiguous(pcbddc->mat_graph->cdim,MPIU_REAL,&dimrealtype);CHKERRQ(ierr);
6942       ierr = MPI_Type_commit(&dimrealtype);CHKERRQ(ierr);
6943       ierr = PetscSFBcastBegin(matis->sf,dimrealtype,pcbddc->mat_graph->coords,lcoords);CHKERRQ(ierr);
6944       ierr = PetscSFBcastEnd(matis->sf,dimrealtype,pcbddc->mat_graph->coords,lcoords);CHKERRQ(ierr);
6945       ierr = MPI_Type_free(&dimrealtype);CHKERRQ(ierr);
6946       ierr = PetscFree(pcbddc->mat_graph->coords);CHKERRQ(ierr);
6947 
6948       pcbddc->mat_graph->coords = lcoords;
6949       pcbddc->mat_graph->cloc   = PETSC_TRUE;
6950       pcbddc->mat_graph->cnloc  = n;
6951     }
6952     if (pcbddc->mat_graph->cnloc && pcbddc->mat_graph->cnloc != pcbddc->mat_graph->nvtxs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local subdomain coordinates! Got %D, expected %D",pcbddc->mat_graph->cnloc,pcbddc->mat_graph->nvtxs);
6953     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && !pcbddc->corner_selected);
6954 
6955     /* Setup of Graph */
6956     pcbddc->mat_graph->commsizelimit = 0; /* don't use the COMM_SELF variant of the graph */
6957     ierr = PCBDDCGraphSetUp(pcbddc->mat_graph,pcbddc->vertex_size,pcbddc->NeumannBoundariesLocal,pcbddc->DirichletBoundariesLocal,pcbddc->n_ISForDofsLocal,pcbddc->ISForDofsLocal,pcbddc->user_primal_vertices_local);CHKERRQ(ierr);
6958 
6959     /* attach info on disconnected subdomains if present */
6960     if (pcbddc->n_local_subs) {
6961       PetscInt *local_subs;
6962 
6963       ierr = PetscMalloc1(N,&local_subs);CHKERRQ(ierr);
6964       for (i=0;i<pcbddc->n_local_subs;i++) {
6965         const PetscInt *idxs;
6966         PetscInt       nl,j;
6967 
6968         ierr = ISGetLocalSize(pcbddc->local_subs[i],&nl);CHKERRQ(ierr);
6969         ierr = ISGetIndices(pcbddc->local_subs[i],&idxs);CHKERRQ(ierr);
6970         for (j=0;j<nl;j++) local_subs[idxs[j]] = i;
6971         ierr = ISRestoreIndices(pcbddc->local_subs[i],&idxs);CHKERRQ(ierr);
6972       }
6973       pcbddc->mat_graph->n_local_subs = pcbddc->n_local_subs;
6974       pcbddc->mat_graph->local_subs = local_subs;
6975     }
6976   }
6977 
6978   if (!pcbddc->graphanalyzed) {
6979     /* Graph's connected components analysis */
6980     ierr = PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph);CHKERRQ(ierr);
6981     pcbddc->graphanalyzed = PETSC_TRUE;
6982   }
6983   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
6984   PetscFunctionReturn(0);
6985 }
6986 
6987 PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt n, Vec vecs[])
6988 {
6989   PetscInt       i,j;
6990   PetscScalar    *alphas;
6991   PetscErrorCode ierr;
6992 
6993   PetscFunctionBegin;
6994   if (!n) PetscFunctionReturn(0);
6995   ierr = PetscMalloc1(n,&alphas);CHKERRQ(ierr);
6996   ierr = VecNormalize(vecs[0],NULL);CHKERRQ(ierr);
6997   for (i=1;i<n;i++) {
6998     ierr = VecMDot(vecs[i],i,vecs,alphas);CHKERRQ(ierr);
6999     for (j=0;j<i;j++) alphas[j] = PetscConj(-alphas[j]);
7000     ierr = VecMAXPY(vecs[i],i,alphas,vecs);CHKERRQ(ierr);
7001     ierr = VecNormalize(vecs[i],NULL);CHKERRQ(ierr);
7002   }
7003   ierr = PetscFree(alphas);CHKERRQ(ierr);
7004   PetscFunctionReturn(0);
7005 }
7006 
7007 PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS* is_sends, PetscBool *have_void)
7008 {
7009   Mat            A;
7010   PetscInt       n_neighs,*neighs,*n_shared,**shared;
7011   PetscMPIInt    size,rank,color;
7012   PetscInt       *xadj,*adjncy;
7013   PetscInt       *adjncy_wgt,*v_wgt,*ranks_send_to_idx;
7014   PetscInt       im_active,active_procs,N,n,i,j,threshold = 2;
7015   PetscInt       void_procs,*procs_candidates = NULL;
7016   PetscInt       xadj_count,*count;
7017   PetscBool      ismatis,use_vwgt=PETSC_FALSE;
7018   PetscSubcomm   psubcomm;
7019   MPI_Comm       subcomm;
7020   PetscErrorCode ierr;
7021 
7022   PetscFunctionBegin;
7023   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
7024   ierr = PetscObjectTypeCompare((PetscObject)mat,MATIS,&ismatis);CHKERRQ(ierr);
7025   if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot use %s on a matrix object which is not of type MATIS",PETSC_FUNCTION_NAME);
7026   PetscValidLogicalCollectiveInt(mat,*n_subdomains,2);
7027   PetscValidLogicalCollectiveInt(mat,redprocs,3);
7028   if (*n_subdomains <=0) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONG,"Invalid number of subdomains requested %d\n",*n_subdomains);
7029 
7030   if (have_void) *have_void = PETSC_FALSE;
7031   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)mat),&size);CHKERRQ(ierr);
7032   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)mat),&rank);CHKERRQ(ierr);
7033   ierr = MatISGetLocalMat(mat,&A);CHKERRQ(ierr);
7034   ierr = MatGetLocalSize(A,&n,NULL);CHKERRQ(ierr);
7035   im_active = !!n;
7036   ierr = MPIU_Allreduce(&im_active,&active_procs,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr);
7037   void_procs = size - active_procs;
7038   /* get ranks of of non-active processes in mat communicator */
7039   if (void_procs) {
7040     PetscInt ncand;
7041 
7042     if (have_void) *have_void = PETSC_TRUE;
7043     ierr = PetscMalloc1(size,&procs_candidates);CHKERRQ(ierr);
7044     ierr = MPI_Allgather(&im_active,1,MPIU_INT,procs_candidates,1,MPIU_INT,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr);
7045     for (i=0,ncand=0;i<size;i++) {
7046       if (!procs_candidates[i]) {
7047         procs_candidates[ncand++] = i;
7048       }
7049     }
7050     /* force n_subdomains to be not greater that the number of non-active processes */
7051     *n_subdomains = PetscMin(void_procs,*n_subdomains);
7052   }
7053 
7054   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
7055      number of subdomains requested 1 -> send to master or first candidate in voids  */
7056   ierr = MatGetSize(mat,&N,NULL);CHKERRQ(ierr);
7057   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
7058     PetscInt issize,isidx,dest;
7059     if (*n_subdomains == 1) dest = 0;
7060     else dest = rank;
7061     if (im_active) {
7062       issize = 1;
7063       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
7064         isidx = procs_candidates[dest];
7065       } else {
7066         isidx = dest;
7067       }
7068     } else {
7069       issize = 0;
7070       isidx = -1;
7071     }
7072     if (*n_subdomains != 1) *n_subdomains = active_procs;
7073     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),issize,&isidx,PETSC_COPY_VALUES,is_sends);CHKERRQ(ierr);
7074     ierr = PetscFree(procs_candidates);CHKERRQ(ierr);
7075     PetscFunctionReturn(0);
7076   }
7077   ierr = PetscOptionsGetBool(NULL,NULL,"-matis_partitioning_use_vwgt",&use_vwgt,NULL);CHKERRQ(ierr);
7078   ierr = PetscOptionsGetInt(NULL,NULL,"-matis_partitioning_threshold",&threshold,NULL);CHKERRQ(ierr);
7079   threshold = PetscMax(threshold,2);
7080 
7081   /* Get info on mapping */
7082   ierr = ISLocalToGlobalMappingGetInfo(mat->rmap->mapping,&n_neighs,&neighs,&n_shared,&shared);CHKERRQ(ierr);
7083 
7084   /* build local CSR graph of subdomains' connectivity */
7085   ierr = PetscMalloc1(2,&xadj);CHKERRQ(ierr);
7086   xadj[0] = 0;
7087   xadj[1] = PetscMax(n_neighs-1,0);
7088   ierr = PetscMalloc1(xadj[1],&adjncy);CHKERRQ(ierr);
7089   ierr = PetscMalloc1(xadj[1],&adjncy_wgt);CHKERRQ(ierr);
7090   ierr = PetscCalloc1(n,&count);CHKERRQ(ierr);
7091   for (i=1;i<n_neighs;i++)
7092     for (j=0;j<n_shared[i];j++)
7093       count[shared[i][j]] += 1;
7094 
7095   xadj_count = 0;
7096   for (i=1;i<n_neighs;i++) {
7097     for (j=0;j<n_shared[i];j++) {
7098       if (count[shared[i][j]] < threshold) {
7099         adjncy[xadj_count] = neighs[i];
7100         adjncy_wgt[xadj_count] = n_shared[i];
7101         xadj_count++;
7102         break;
7103       }
7104     }
7105   }
7106   xadj[1] = xadj_count;
7107   ierr = PetscFree(count);CHKERRQ(ierr);
7108   ierr = ISLocalToGlobalMappingRestoreInfo(mat->rmap->mapping,&n_neighs,&neighs,&n_shared,&shared);CHKERRQ(ierr);
7109   ierr = PetscSortIntWithArray(xadj[1],adjncy,adjncy_wgt);CHKERRQ(ierr);
7110 
7111   ierr = PetscMalloc1(1,&ranks_send_to_idx);CHKERRQ(ierr);
7112 
7113   /* Restrict work on active processes only */
7114   ierr = PetscMPIIntCast(im_active,&color);CHKERRQ(ierr);
7115   if (void_procs) {
7116     ierr = PetscSubcommCreate(PetscObjectComm((PetscObject)mat),&psubcomm);CHKERRQ(ierr);
7117     ierr = PetscSubcommSetNumber(psubcomm,2);CHKERRQ(ierr); /* 2 groups, active process and not active processes */
7118     ierr = PetscSubcommSetTypeGeneral(psubcomm,color,rank);CHKERRQ(ierr);
7119     subcomm = PetscSubcommChild(psubcomm);
7120   } else {
7121     psubcomm = NULL;
7122     subcomm = PetscObjectComm((PetscObject)mat);
7123   }
7124 
7125   v_wgt = NULL;
7126   if (!color) {
7127     ierr = PetscFree(xadj);CHKERRQ(ierr);
7128     ierr = PetscFree(adjncy);CHKERRQ(ierr);
7129     ierr = PetscFree(adjncy_wgt);CHKERRQ(ierr);
7130   } else {
7131     Mat             subdomain_adj;
7132     IS              new_ranks,new_ranks_contig;
7133     MatPartitioning partitioner;
7134     PetscInt        rstart=0,rend=0;
7135     PetscInt        *is_indices,*oldranks;
7136     PetscMPIInt     size;
7137     PetscBool       aggregate;
7138 
7139     ierr = MPI_Comm_size(subcomm,&size);CHKERRQ(ierr);
7140     if (void_procs) {
7141       PetscInt prank = rank;
7142       ierr = PetscMalloc1(size,&oldranks);CHKERRQ(ierr);
7143       ierr = MPI_Allgather(&prank,1,MPIU_INT,oldranks,1,MPIU_INT,subcomm);CHKERRQ(ierr);
7144       for (i=0;i<xadj[1];i++) {
7145         ierr = PetscFindInt(adjncy[i],size,oldranks,&adjncy[i]);CHKERRQ(ierr);
7146       }
7147       ierr = PetscSortIntWithArray(xadj[1],adjncy,adjncy_wgt);CHKERRQ(ierr);
7148     } else {
7149       oldranks = NULL;
7150     }
7151     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
7152     if (aggregate) { /* TODO: all this part could be made more efficient */
7153       PetscInt    lrows,row,ncols,*cols;
7154       PetscMPIInt nrank;
7155       PetscScalar *vals;
7156 
7157       ierr = MPI_Comm_rank(subcomm,&nrank);CHKERRQ(ierr);
7158       lrows = 0;
7159       if (nrank<redprocs) {
7160         lrows = size/redprocs;
7161         if (nrank<size%redprocs) lrows++;
7162       }
7163       ierr = MatCreateAIJ(subcomm,lrows,lrows,size,size,50,NULL,50,NULL,&subdomain_adj);CHKERRQ(ierr);
7164       ierr = MatGetOwnershipRange(subdomain_adj,&rstart,&rend);CHKERRQ(ierr);
7165       ierr = MatSetOption(subdomain_adj,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
7166       ierr = MatSetOption(subdomain_adj,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
7167       row = nrank;
7168       ncols = xadj[1]-xadj[0];
7169       cols = adjncy;
7170       ierr = PetscMalloc1(ncols,&vals);CHKERRQ(ierr);
7171       for (i=0;i<ncols;i++) vals[i] = adjncy_wgt[i];
7172       ierr = MatSetValues(subdomain_adj,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
7173       ierr = MatAssemblyBegin(subdomain_adj,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7174       ierr = MatAssemblyEnd(subdomain_adj,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7175       ierr = PetscFree(xadj);CHKERRQ(ierr);
7176       ierr = PetscFree(adjncy);CHKERRQ(ierr);
7177       ierr = PetscFree(adjncy_wgt);CHKERRQ(ierr);
7178       ierr = PetscFree(vals);CHKERRQ(ierr);
7179       if (use_vwgt) {
7180         Vec               v;
7181         const PetscScalar *array;
7182         PetscInt          nl;
7183 
7184         ierr = MatCreateVecs(subdomain_adj,&v,NULL);CHKERRQ(ierr);
7185         ierr = VecSetValue(v,row,(PetscScalar)n,INSERT_VALUES);CHKERRQ(ierr);
7186         ierr = VecAssemblyBegin(v);CHKERRQ(ierr);
7187         ierr = VecAssemblyEnd(v);CHKERRQ(ierr);
7188         ierr = VecGetLocalSize(v,&nl);CHKERRQ(ierr);
7189         ierr = VecGetArrayRead(v,&array);CHKERRQ(ierr);
7190         ierr = PetscMalloc1(nl,&v_wgt);CHKERRQ(ierr);
7191         for (i=0;i<nl;i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
7192         ierr = VecRestoreArrayRead(v,&array);CHKERRQ(ierr);
7193         ierr = VecDestroy(&v);CHKERRQ(ierr);
7194       }
7195     } else {
7196       ierr = MatCreateMPIAdj(subcomm,1,(PetscInt)size,xadj,adjncy,adjncy_wgt,&subdomain_adj);CHKERRQ(ierr);
7197       if (use_vwgt) {
7198         ierr = PetscMalloc1(1,&v_wgt);CHKERRQ(ierr);
7199         v_wgt[0] = n;
7200       }
7201     }
7202     /* ierr = MatView(subdomain_adj,0);CHKERRQ(ierr); */
7203 
7204     /* Partition */
7205     ierr = MatPartitioningCreate(subcomm,&partitioner);CHKERRQ(ierr);
7206     ierr = MatPartitioningSetAdjacency(partitioner,subdomain_adj);CHKERRQ(ierr);
7207     if (v_wgt) {
7208       ierr = MatPartitioningSetVertexWeights(partitioner,v_wgt);CHKERRQ(ierr);
7209     }
7210     *n_subdomains = PetscMin((PetscInt)size,*n_subdomains);
7211     ierr = MatPartitioningSetNParts(partitioner,*n_subdomains);CHKERRQ(ierr);
7212     ierr = MatPartitioningSetFromOptions(partitioner);CHKERRQ(ierr);
7213     ierr = MatPartitioningApply(partitioner,&new_ranks);CHKERRQ(ierr);
7214     /* ierr = MatPartitioningView(partitioner,0);CHKERRQ(ierr); */
7215 
7216     /* renumber new_ranks to avoid "holes" in new set of processors */
7217     ierr = ISRenumber(new_ranks,NULL,NULL,&new_ranks_contig);CHKERRQ(ierr);
7218     ierr = ISDestroy(&new_ranks);CHKERRQ(ierr);
7219     ierr = ISGetIndices(new_ranks_contig,(const PetscInt**)&is_indices);CHKERRQ(ierr);
7220     if (!aggregate) {
7221       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
7222 #if defined(PETSC_USE_DEBUG)
7223         if (!oldranks) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"This should not happen");
7224 #endif
7225         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
7226       } else if (oldranks) {
7227         ranks_send_to_idx[0] = oldranks[is_indices[0]];
7228       } else {
7229         ranks_send_to_idx[0] = is_indices[0];
7230       }
7231     } else {
7232       PetscInt    idx = 0;
7233       PetscMPIInt tag;
7234       MPI_Request *reqs;
7235 
7236       ierr = PetscObjectGetNewTag((PetscObject)subdomain_adj,&tag);CHKERRQ(ierr);
7237       ierr = PetscMalloc1(rend-rstart,&reqs);CHKERRQ(ierr);
7238       for (i=rstart;i<rend;i++) {
7239         ierr = MPI_Isend(is_indices+i-rstart,1,MPIU_INT,i,tag,subcomm,&reqs[i-rstart]);CHKERRQ(ierr);
7240       }
7241       ierr = MPI_Recv(&idx,1,MPIU_INT,MPI_ANY_SOURCE,tag,subcomm,MPI_STATUS_IGNORE);CHKERRQ(ierr);
7242       ierr = MPI_Waitall(rend-rstart,reqs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7243       ierr = PetscFree(reqs);CHKERRQ(ierr);
7244       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
7245 #if defined(PETSC_USE_DEBUG)
7246         if (!oldranks) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"This should not happen");
7247 #endif
7248         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
7249       } else if (oldranks) {
7250         ranks_send_to_idx[0] = oldranks[idx];
7251       } else {
7252         ranks_send_to_idx[0] = idx;
7253       }
7254     }
7255     ierr = ISRestoreIndices(new_ranks_contig,(const PetscInt**)&is_indices);CHKERRQ(ierr);
7256     /* clean up */
7257     ierr = PetscFree(oldranks);CHKERRQ(ierr);
7258     ierr = ISDestroy(&new_ranks_contig);CHKERRQ(ierr);
7259     ierr = MatDestroy(&subdomain_adj);CHKERRQ(ierr);
7260     ierr = MatPartitioningDestroy(&partitioner);CHKERRQ(ierr);
7261   }
7262   ierr = PetscSubcommDestroy(&psubcomm);CHKERRQ(ierr);
7263   ierr = PetscFree(procs_candidates);CHKERRQ(ierr);
7264 
7265   /* assemble parallel IS for sends */
7266   i = 1;
7267   if (!color) i=0;
7268   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),i,ranks_send_to_idx,PETSC_OWN_POINTER,is_sends);CHKERRQ(ierr);
7269   PetscFunctionReturn(0);
7270 }
7271 
7272 typedef enum {MATDENSE_PRIVATE=0,MATAIJ_PRIVATE,MATBAIJ_PRIVATE,MATSBAIJ_PRIVATE}MatTypePrivate;
7273 
7274 PetscErrorCode PCBDDCMatISSubassemble(Mat mat, IS is_sends, PetscInt n_subdomains, PetscBool restrict_comm, PetscBool restrict_full, PetscBool reuse, Mat *mat_n, PetscInt nis, IS isarray[], PetscInt nvecs, Vec nnsp_vec[])
7275 {
7276   Mat                    local_mat;
7277   IS                     is_sends_internal;
7278   PetscInt               rows,cols,new_local_rows;
7279   PetscInt               i,bs,buf_size_idxs,buf_size_idxs_is,buf_size_vals,buf_size_vecs;
7280   PetscBool              ismatis,isdense,newisdense,destroy_mat;
7281   ISLocalToGlobalMapping l2gmap;
7282   PetscInt*              l2gmap_indices;
7283   const PetscInt*        is_indices;
7284   MatType                new_local_type;
7285   /* buffers */
7286   PetscInt               *ptr_idxs,*send_buffer_idxs,*recv_buffer_idxs;
7287   PetscInt               *ptr_idxs_is,*send_buffer_idxs_is,*recv_buffer_idxs_is;
7288   PetscInt               *recv_buffer_idxs_local;
7289   PetscScalar            *ptr_vals,*send_buffer_vals,*recv_buffer_vals;
7290   PetscScalar            *ptr_vecs,*send_buffer_vecs,*recv_buffer_vecs;
7291   /* MPI */
7292   MPI_Comm               comm,comm_n;
7293   PetscSubcomm           subcomm;
7294   PetscMPIInt            n_sends,n_recvs,commsize;
7295   PetscMPIInt            *iflags,*ilengths_idxs,*ilengths_vals,*ilengths_idxs_is;
7296   PetscMPIInt            *onodes,*onodes_is,*olengths_idxs,*olengths_idxs_is,*olengths_vals;
7297   PetscMPIInt            len,tag_idxs,tag_idxs_is,tag_vals,tag_vecs,source_dest;
7298   MPI_Request            *send_req_idxs,*send_req_idxs_is,*send_req_vals,*send_req_vecs;
7299   MPI_Request            *recv_req_idxs,*recv_req_idxs_is,*recv_req_vals,*recv_req_vecs;
7300   PetscErrorCode         ierr;
7301 
7302   PetscFunctionBegin;
7303   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
7304   ierr = PetscObjectTypeCompare((PetscObject)mat,MATIS,&ismatis);CHKERRQ(ierr);
7305   if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot use %s on a matrix object which is not of type MATIS",PETSC_FUNCTION_NAME);
7306   PetscValidLogicalCollectiveInt(mat,n_subdomains,3);
7307   PetscValidLogicalCollectiveBool(mat,restrict_comm,4);
7308   PetscValidLogicalCollectiveBool(mat,restrict_full,5);
7309   PetscValidLogicalCollectiveBool(mat,reuse,6);
7310   PetscValidLogicalCollectiveInt(mat,nis,8);
7311   PetscValidLogicalCollectiveInt(mat,nvecs,10);
7312   if (nvecs) {
7313     if (nvecs > 1) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Just 1 vector supported");
7314     PetscValidHeaderSpecific(nnsp_vec[0],VEC_CLASSID,11);
7315   }
7316   /* further checks */
7317   ierr = MatISGetLocalMat(mat,&local_mat);CHKERRQ(ierr);
7318   ierr = PetscObjectTypeCompare((PetscObject)local_mat,MATSEQDENSE,&isdense);CHKERRQ(ierr);
7319   if (!isdense) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
7320   ierr = MatGetSize(local_mat,&rows,&cols);CHKERRQ(ierr);
7321   if (rows != cols) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Local MATIS matrices should be square");
7322   if (reuse && *mat_n) {
7323     PetscInt mrows,mcols,mnrows,mncols;
7324     PetscValidHeaderSpecific(*mat_n,MAT_CLASSID,7);
7325     ierr = PetscObjectTypeCompare((PetscObject)*mat_n,MATIS,&ismatis);CHKERRQ(ierr);
7326     if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)*mat_n),PETSC_ERR_SUP,"Cannot reuse a matrix which is not of type MATIS");
7327     ierr = MatGetSize(mat,&mrows,&mcols);CHKERRQ(ierr);
7328     ierr = MatGetSize(*mat_n,&mnrows,&mncols);CHKERRQ(ierr);
7329     if (mrows != mnrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix! Wrong number of rows %D != %D",mrows,mnrows);
7330     if (mcols != mncols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix! Wrong number of cols %D != %D",mcols,mncols);
7331   }
7332   ierr = MatGetBlockSize(local_mat,&bs);CHKERRQ(ierr);
7333   PetscValidLogicalCollectiveInt(mat,bs,0);
7334 
7335   /* prepare IS for sending if not provided */
7336   if (!is_sends) {
7337     if (!n_subdomains) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"You should specify either an IS or a target number of subdomains");
7338     ierr = PCBDDCMatISGetSubassemblingPattern(mat,&n_subdomains,0,&is_sends_internal,NULL);CHKERRQ(ierr);
7339   } else {
7340     ierr = PetscObjectReference((PetscObject)is_sends);CHKERRQ(ierr);
7341     is_sends_internal = is_sends;
7342   }
7343 
7344   /* get comm */
7345   ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
7346 
7347   /* compute number of sends */
7348   ierr = ISGetLocalSize(is_sends_internal,&i);CHKERRQ(ierr);
7349   ierr = PetscMPIIntCast(i,&n_sends);CHKERRQ(ierr);
7350 
7351   /* compute number of receives */
7352   ierr = MPI_Comm_size(comm,&commsize);CHKERRQ(ierr);
7353   ierr = PetscMalloc1(commsize,&iflags);CHKERRQ(ierr);
7354   ierr = PetscMemzero(iflags,commsize*sizeof(*iflags));CHKERRQ(ierr);
7355   ierr = ISGetIndices(is_sends_internal,&is_indices);CHKERRQ(ierr);
7356   for (i=0;i<n_sends;i++) iflags[is_indices[i]] = 1;
7357   ierr = PetscGatherNumberOfMessages(comm,iflags,NULL,&n_recvs);CHKERRQ(ierr);
7358   ierr = PetscFree(iflags);CHKERRQ(ierr);
7359 
7360   /* restrict comm if requested */
7361   subcomm = 0;
7362   destroy_mat = PETSC_FALSE;
7363   if (restrict_comm) {
7364     PetscMPIInt color,subcommsize;
7365 
7366     color = 0;
7367     if (restrict_full) {
7368       if (!n_recvs) color = 1; /* processes not receiving anything will not partecipate in new comm (full restriction) */
7369     } else {
7370       if (!n_recvs && n_sends) color = 1; /* just those processes that are sending but not receiving anything will not partecipate in new comm */
7371     }
7372     ierr = MPIU_Allreduce(&color,&subcommsize,1,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
7373     subcommsize = commsize - subcommsize;
7374     /* check if reuse has been requested */
7375     if (reuse) {
7376       if (*mat_n) {
7377         PetscMPIInt subcommsize2;
7378         ierr = MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n),&subcommsize2);CHKERRQ(ierr);
7379         if (subcommsize != subcommsize2) SETERRQ2(PetscObjectComm((PetscObject)*mat_n),PETSC_ERR_PLIB,"Cannot reuse matrix! wrong subcomm size %d != %d",subcommsize,subcommsize2);
7380         comm_n = PetscObjectComm((PetscObject)*mat_n);
7381       } else {
7382         comm_n = PETSC_COMM_SELF;
7383       }
7384     } else { /* MAT_INITIAL_MATRIX */
7385       PetscMPIInt rank;
7386 
7387       ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
7388       ierr = PetscSubcommCreate(comm,&subcomm);CHKERRQ(ierr);
7389       ierr = PetscSubcommSetNumber(subcomm,2);CHKERRQ(ierr);
7390       ierr = PetscSubcommSetTypeGeneral(subcomm,color,rank);CHKERRQ(ierr);
7391       comm_n = PetscSubcommChild(subcomm);
7392     }
7393     /* flag to destroy *mat_n if not significative */
7394     if (color) destroy_mat = PETSC_TRUE;
7395   } else {
7396     comm_n = comm;
7397   }
7398 
7399   /* prepare send/receive buffers */
7400   ierr = PetscMalloc1(commsize,&ilengths_idxs);CHKERRQ(ierr);
7401   ierr = PetscMemzero(ilengths_idxs,commsize*sizeof(*ilengths_idxs));CHKERRQ(ierr);
7402   ierr = PetscMalloc1(commsize,&ilengths_vals);CHKERRQ(ierr);
7403   ierr = PetscMemzero(ilengths_vals,commsize*sizeof(*ilengths_vals));CHKERRQ(ierr);
7404   if (nis) {
7405     ierr = PetscCalloc1(commsize,&ilengths_idxs_is);CHKERRQ(ierr);
7406   }
7407 
7408   /* Get data from local matrices */
7409   if (!isdense) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Subassembling of AIJ local matrices not yet implemented");
7410     /* TODO: See below some guidelines on how to prepare the local buffers */
7411     /*
7412        send_buffer_vals should contain the raw values of the local matrix
7413        send_buffer_idxs should contain:
7414        - MatType_PRIVATE type
7415        - PetscInt        size_of_l2gmap
7416        - PetscInt        global_row_indices[size_of_l2gmap]
7417        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
7418     */
7419   else {
7420     ierr = MatDenseGetArray(local_mat,&send_buffer_vals);CHKERRQ(ierr);
7421     ierr = ISLocalToGlobalMappingGetSize(mat->rmap->mapping,&i);CHKERRQ(ierr);
7422     ierr = PetscMalloc1(i+2,&send_buffer_idxs);CHKERRQ(ierr);
7423     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
7424     send_buffer_idxs[1] = i;
7425     ierr = ISLocalToGlobalMappingGetIndices(mat->rmap->mapping,(const PetscInt**)&ptr_idxs);CHKERRQ(ierr);
7426     ierr = PetscMemcpy(&send_buffer_idxs[2],ptr_idxs,i*sizeof(PetscInt));CHKERRQ(ierr);
7427     ierr = ISLocalToGlobalMappingRestoreIndices(mat->rmap->mapping,(const PetscInt**)&ptr_idxs);CHKERRQ(ierr);
7428     ierr = PetscMPIIntCast(i,&len);CHKERRQ(ierr);
7429     for (i=0;i<n_sends;i++) {
7430       ilengths_vals[is_indices[i]] = len*len;
7431       ilengths_idxs[is_indices[i]] = len+2;
7432     }
7433   }
7434   ierr = PetscGatherMessageLengths2(comm,n_sends,n_recvs,ilengths_idxs,ilengths_vals,&onodes,&olengths_idxs,&olengths_vals);CHKERRQ(ierr);
7435   /* additional is (if any) */
7436   if (nis) {
7437     PetscMPIInt psum;
7438     PetscInt j;
7439     for (j=0,psum=0;j<nis;j++) {
7440       PetscInt plen;
7441       ierr = ISGetLocalSize(isarray[j],&plen);CHKERRQ(ierr);
7442       ierr = PetscMPIIntCast(plen,&len);CHKERRQ(ierr);
7443       psum += len+1; /* indices + lenght */
7444     }
7445     ierr = PetscMalloc1(psum,&send_buffer_idxs_is);CHKERRQ(ierr);
7446     for (j=0,psum=0;j<nis;j++) {
7447       PetscInt plen;
7448       const PetscInt *is_array_idxs;
7449       ierr = ISGetLocalSize(isarray[j],&plen);CHKERRQ(ierr);
7450       send_buffer_idxs_is[psum] = plen;
7451       ierr = ISGetIndices(isarray[j],&is_array_idxs);CHKERRQ(ierr);
7452       ierr = PetscMemcpy(&send_buffer_idxs_is[psum+1],is_array_idxs,plen*sizeof(PetscInt));CHKERRQ(ierr);
7453       ierr = ISRestoreIndices(isarray[j],&is_array_idxs);CHKERRQ(ierr);
7454       psum += plen+1; /* indices + lenght */
7455     }
7456     for (i=0;i<n_sends;i++) {
7457       ilengths_idxs_is[is_indices[i]] = psum;
7458     }
7459     ierr = PetscGatherMessageLengths(comm,n_sends,n_recvs,ilengths_idxs_is,&onodes_is,&olengths_idxs_is);CHKERRQ(ierr);
7460   }
7461   ierr = MatISRestoreLocalMat(mat,&local_mat);CHKERRQ(ierr);
7462 
7463   buf_size_idxs = 0;
7464   buf_size_vals = 0;
7465   buf_size_idxs_is = 0;
7466   buf_size_vecs = 0;
7467   for (i=0;i<n_recvs;i++) {
7468     buf_size_idxs += (PetscInt)olengths_idxs[i];
7469     buf_size_vals += (PetscInt)olengths_vals[i];
7470     if (nis) buf_size_idxs_is += (PetscInt)olengths_idxs_is[i];
7471     if (nvecs) buf_size_vecs += (PetscInt)olengths_idxs[i];
7472   }
7473   ierr = PetscMalloc1(buf_size_idxs,&recv_buffer_idxs);CHKERRQ(ierr);
7474   ierr = PetscMalloc1(buf_size_vals,&recv_buffer_vals);CHKERRQ(ierr);
7475   ierr = PetscMalloc1(buf_size_idxs_is,&recv_buffer_idxs_is);CHKERRQ(ierr);
7476   ierr = PetscMalloc1(buf_size_vecs,&recv_buffer_vecs);CHKERRQ(ierr);
7477 
7478   /* get new tags for clean communications */
7479   ierr = PetscObjectGetNewTag((PetscObject)mat,&tag_idxs);CHKERRQ(ierr);
7480   ierr = PetscObjectGetNewTag((PetscObject)mat,&tag_vals);CHKERRQ(ierr);
7481   ierr = PetscObjectGetNewTag((PetscObject)mat,&tag_idxs_is);CHKERRQ(ierr);
7482   ierr = PetscObjectGetNewTag((PetscObject)mat,&tag_vecs);CHKERRQ(ierr);
7483 
7484   /* allocate for requests */
7485   ierr = PetscMalloc1(n_sends,&send_req_idxs);CHKERRQ(ierr);
7486   ierr = PetscMalloc1(n_sends,&send_req_vals);CHKERRQ(ierr);
7487   ierr = PetscMalloc1(n_sends,&send_req_idxs_is);CHKERRQ(ierr);
7488   ierr = PetscMalloc1(n_sends,&send_req_vecs);CHKERRQ(ierr);
7489   ierr = PetscMalloc1(n_recvs,&recv_req_idxs);CHKERRQ(ierr);
7490   ierr = PetscMalloc1(n_recvs,&recv_req_vals);CHKERRQ(ierr);
7491   ierr = PetscMalloc1(n_recvs,&recv_req_idxs_is);CHKERRQ(ierr);
7492   ierr = PetscMalloc1(n_recvs,&recv_req_vecs);CHKERRQ(ierr);
7493 
7494   /* communications */
7495   ptr_idxs = recv_buffer_idxs;
7496   ptr_vals = recv_buffer_vals;
7497   ptr_idxs_is = recv_buffer_idxs_is;
7498   ptr_vecs = recv_buffer_vecs;
7499   for (i=0;i<n_recvs;i++) {
7500     source_dest = onodes[i];
7501     ierr = MPI_Irecv(ptr_idxs,olengths_idxs[i],MPIU_INT,source_dest,tag_idxs,comm,&recv_req_idxs[i]);CHKERRQ(ierr);
7502     ierr = MPI_Irecv(ptr_vals,olengths_vals[i],MPIU_SCALAR,source_dest,tag_vals,comm,&recv_req_vals[i]);CHKERRQ(ierr);
7503     ptr_idxs += olengths_idxs[i];
7504     ptr_vals += olengths_vals[i];
7505     if (nis) {
7506       source_dest = onodes_is[i];
7507       ierr = MPI_Irecv(ptr_idxs_is,olengths_idxs_is[i],MPIU_INT,source_dest,tag_idxs_is,comm,&recv_req_idxs_is[i]);CHKERRQ(ierr);
7508       ptr_idxs_is += olengths_idxs_is[i];
7509     }
7510     if (nvecs) {
7511       source_dest = onodes[i];
7512       ierr = MPI_Irecv(ptr_vecs,olengths_idxs[i]-2,MPIU_SCALAR,source_dest,tag_vecs,comm,&recv_req_vecs[i]);CHKERRQ(ierr);
7513       ptr_vecs += olengths_idxs[i]-2;
7514     }
7515   }
7516   for (i=0;i<n_sends;i++) {
7517     ierr = PetscMPIIntCast(is_indices[i],&source_dest);CHKERRQ(ierr);
7518     ierr = MPI_Isend(send_buffer_idxs,ilengths_idxs[source_dest],MPIU_INT,source_dest,tag_idxs,comm,&send_req_idxs[i]);CHKERRQ(ierr);
7519     ierr = MPI_Isend(send_buffer_vals,ilengths_vals[source_dest],MPIU_SCALAR,source_dest,tag_vals,comm,&send_req_vals[i]);CHKERRQ(ierr);
7520     if (nis) {
7521       ierr = MPI_Isend(send_buffer_idxs_is,ilengths_idxs_is[source_dest],MPIU_INT,source_dest,tag_idxs_is,comm,&send_req_idxs_is[i]);CHKERRQ(ierr);
7522     }
7523     if (nvecs) {
7524       ierr = VecGetArray(nnsp_vec[0],&send_buffer_vecs);CHKERRQ(ierr);
7525       ierr = MPI_Isend(send_buffer_vecs,ilengths_idxs[source_dest]-2,MPIU_SCALAR,source_dest,tag_vecs,comm,&send_req_vecs[i]);CHKERRQ(ierr);
7526     }
7527   }
7528   ierr = ISRestoreIndices(is_sends_internal,&is_indices);CHKERRQ(ierr);
7529   ierr = ISDestroy(&is_sends_internal);CHKERRQ(ierr);
7530 
7531   /* assemble new l2g map */
7532   ierr = MPI_Waitall(n_recvs,recv_req_idxs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7533   ptr_idxs = recv_buffer_idxs;
7534   new_local_rows = 0;
7535   for (i=0;i<n_recvs;i++) {
7536     new_local_rows += *(ptr_idxs+1); /* second element is the local size of the l2gmap */
7537     ptr_idxs += olengths_idxs[i];
7538   }
7539   ierr = PetscMalloc1(new_local_rows,&l2gmap_indices);CHKERRQ(ierr);
7540   ptr_idxs = recv_buffer_idxs;
7541   new_local_rows = 0;
7542   for (i=0;i<n_recvs;i++) {
7543     ierr = PetscMemcpy(&l2gmap_indices[new_local_rows],ptr_idxs+2,(*(ptr_idxs+1))*sizeof(PetscInt));CHKERRQ(ierr);
7544     new_local_rows += *(ptr_idxs+1); /* second element is the local size of the l2gmap */
7545     ptr_idxs += olengths_idxs[i];
7546   }
7547   ierr = PetscSortRemoveDupsInt(&new_local_rows,l2gmap_indices);CHKERRQ(ierr);
7548   ierr = ISLocalToGlobalMappingCreate(comm_n,1,new_local_rows,l2gmap_indices,PETSC_COPY_VALUES,&l2gmap);CHKERRQ(ierr);
7549   ierr = PetscFree(l2gmap_indices);CHKERRQ(ierr);
7550 
7551   /* infer new local matrix type from received local matrices type */
7552   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
7553   /* it also assumes that if the block size is set, than it is the same among all local matrices (see checks at the beginning of the function) */
7554   if (n_recvs) {
7555     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
7556     ptr_idxs = recv_buffer_idxs;
7557     for (i=0;i<n_recvs;i++) {
7558       if ((PetscInt)new_local_type_private != *ptr_idxs) {
7559         new_local_type_private = MATAIJ_PRIVATE;
7560         break;
7561       }
7562       ptr_idxs += olengths_idxs[i];
7563     }
7564     switch (new_local_type_private) {
7565       case MATDENSE_PRIVATE:
7566         new_local_type = MATSEQAIJ;
7567         bs = 1;
7568         break;
7569       case MATAIJ_PRIVATE:
7570         new_local_type = MATSEQAIJ;
7571         bs = 1;
7572         break;
7573       case MATBAIJ_PRIVATE:
7574         new_local_type = MATSEQBAIJ;
7575         break;
7576       case MATSBAIJ_PRIVATE:
7577         new_local_type = MATSEQSBAIJ;
7578         break;
7579       default:
7580         SETERRQ2(comm,PETSC_ERR_SUP,"Unsupported private type %d in %s",new_local_type_private,PETSC_FUNCTION_NAME);
7581         break;
7582     }
7583   } else { /* by default, new_local_type is seqaij */
7584     new_local_type = MATSEQAIJ;
7585     bs = 1;
7586   }
7587 
7588   /* create MATIS object if needed */
7589   if (!reuse) {
7590     ierr = MatGetSize(mat,&rows,&cols);CHKERRQ(ierr);
7591     ierr = MatCreateIS(comm_n,bs,PETSC_DECIDE,PETSC_DECIDE,rows,cols,l2gmap,NULL,mat_n);CHKERRQ(ierr);
7592   } else {
7593     /* it also destroys the local matrices */
7594     if (*mat_n) {
7595       ierr = MatSetLocalToGlobalMapping(*mat_n,l2gmap,l2gmap);CHKERRQ(ierr);
7596     } else { /* this is a fake object */
7597       ierr = MatCreateIS(comm_n,bs,PETSC_DECIDE,PETSC_DECIDE,rows,cols,l2gmap,NULL,mat_n);CHKERRQ(ierr);
7598     }
7599   }
7600   ierr = MatISGetLocalMat(*mat_n,&local_mat);CHKERRQ(ierr);
7601   ierr = MatSetType(local_mat,new_local_type);CHKERRQ(ierr);
7602 
7603   ierr = MPI_Waitall(n_recvs,recv_req_vals,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7604 
7605   /* Global to local map of received indices */
7606   ierr = PetscMalloc1(buf_size_idxs,&recv_buffer_idxs_local);CHKERRQ(ierr); /* needed for values insertion */
7607   ierr = ISGlobalToLocalMappingApply(l2gmap,IS_GTOLM_MASK,buf_size_idxs,recv_buffer_idxs,&i,recv_buffer_idxs_local);CHKERRQ(ierr);
7608   ierr = ISLocalToGlobalMappingDestroy(&l2gmap);CHKERRQ(ierr);
7609 
7610   /* restore attributes -> type of incoming data and its size */
7611   buf_size_idxs = 0;
7612   for (i=0;i<n_recvs;i++) {
7613     recv_buffer_idxs_local[buf_size_idxs] = recv_buffer_idxs[buf_size_idxs];
7614     recv_buffer_idxs_local[buf_size_idxs+1] = recv_buffer_idxs[buf_size_idxs+1];
7615     buf_size_idxs += (PetscInt)olengths_idxs[i];
7616   }
7617   ierr = PetscFree(recv_buffer_idxs);CHKERRQ(ierr);
7618 
7619   /* set preallocation */
7620   ierr = PetscObjectTypeCompare((PetscObject)local_mat,MATSEQDENSE,&newisdense);CHKERRQ(ierr);
7621   if (!newisdense) {
7622     PetscInt *new_local_nnz=0;
7623 
7624     ptr_idxs = recv_buffer_idxs_local;
7625     if (n_recvs) {
7626       ierr = PetscCalloc1(new_local_rows,&new_local_nnz);CHKERRQ(ierr);
7627     }
7628     for (i=0;i<n_recvs;i++) {
7629       PetscInt j;
7630       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
7631         for (j=0;j<*(ptr_idxs+1);j++) {
7632           new_local_nnz[*(ptr_idxs+2+j)] += *(ptr_idxs+1);
7633         }
7634       } else {
7635         /* TODO */
7636       }
7637       ptr_idxs += olengths_idxs[i];
7638     }
7639     if (new_local_nnz) {
7640       for (i=0;i<new_local_rows;i++) new_local_nnz[i] = PetscMin(new_local_nnz[i],new_local_rows);
7641       ierr = MatSeqAIJSetPreallocation(local_mat,0,new_local_nnz);CHKERRQ(ierr);
7642       for (i=0;i<new_local_rows;i++) new_local_nnz[i] /= bs;
7643       ierr = MatSeqBAIJSetPreallocation(local_mat,bs,0,new_local_nnz);CHKERRQ(ierr);
7644       for (i=0;i<new_local_rows;i++) new_local_nnz[i] = PetscMax(new_local_nnz[i]-i,0);
7645       ierr = MatSeqSBAIJSetPreallocation(local_mat,bs,0,new_local_nnz);CHKERRQ(ierr);
7646     } else {
7647       ierr = MatSetUp(local_mat);CHKERRQ(ierr);
7648     }
7649     ierr = PetscFree(new_local_nnz);CHKERRQ(ierr);
7650   } else {
7651     ierr = MatSetUp(local_mat);CHKERRQ(ierr);
7652   }
7653 
7654   /* set values */
7655   ptr_vals = recv_buffer_vals;
7656   ptr_idxs = recv_buffer_idxs_local;
7657   for (i=0;i<n_recvs;i++) {
7658     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
7659       ierr = MatSetOption(local_mat,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
7660       ierr = MatSetValues(local_mat,*(ptr_idxs+1),ptr_idxs+2,*(ptr_idxs+1),ptr_idxs+2,ptr_vals,ADD_VALUES);CHKERRQ(ierr);
7661       ierr = MatAssemblyBegin(local_mat,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr);
7662       ierr = MatAssemblyEnd(local_mat,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr);
7663       ierr = MatSetOption(local_mat,MAT_ROW_ORIENTED,PETSC_TRUE);CHKERRQ(ierr);
7664     } else {
7665       /* TODO */
7666     }
7667     ptr_idxs += olengths_idxs[i];
7668     ptr_vals += olengths_vals[i];
7669   }
7670   ierr = MatAssemblyBegin(local_mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7671   ierr = MatAssemblyEnd(local_mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7672   ierr = MatISRestoreLocalMat(*mat_n,&local_mat);CHKERRQ(ierr);
7673   ierr = MatAssemblyBegin(*mat_n,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7674   ierr = MatAssemblyEnd(*mat_n,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7675   ierr = PetscFree(recv_buffer_vals);CHKERRQ(ierr);
7676 
7677 #if 0
7678   if (!restrict_comm) { /* check */
7679     Vec       lvec,rvec;
7680     PetscReal infty_error;
7681 
7682     ierr = MatCreateVecs(mat,&rvec,&lvec);CHKERRQ(ierr);
7683     ierr = VecSetRandom(rvec,NULL);CHKERRQ(ierr);
7684     ierr = MatMult(mat,rvec,lvec);CHKERRQ(ierr);
7685     ierr = VecScale(lvec,-1.0);CHKERRQ(ierr);
7686     ierr = MatMultAdd(*mat_n,rvec,lvec,lvec);CHKERRQ(ierr);
7687     ierr = VecNorm(lvec,NORM_INFINITY,&infty_error);CHKERRQ(ierr);
7688     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error);
7689     ierr = VecDestroy(&rvec);CHKERRQ(ierr);
7690     ierr = VecDestroy(&lvec);CHKERRQ(ierr);
7691   }
7692 #endif
7693 
7694   /* assemble new additional is (if any) */
7695   if (nis) {
7696     PetscInt **temp_idxs,*count_is,j,psum;
7697 
7698     ierr = MPI_Waitall(n_recvs,recv_req_idxs_is,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7699     ierr = PetscCalloc1(nis,&count_is);CHKERRQ(ierr);
7700     ptr_idxs = recv_buffer_idxs_is;
7701     psum = 0;
7702     for (i=0;i<n_recvs;i++) {
7703       for (j=0;j<nis;j++) {
7704         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
7705         count_is[j] += plen; /* increment counting of buffer for j-th IS */
7706         psum += plen;
7707         ptr_idxs += plen+1; /* shift pointer to received data */
7708       }
7709     }
7710     ierr = PetscMalloc1(nis,&temp_idxs);CHKERRQ(ierr);
7711     ierr = PetscMalloc1(psum,&temp_idxs[0]);CHKERRQ(ierr);
7712     for (i=1;i<nis;i++) {
7713       temp_idxs[i] = temp_idxs[i-1]+count_is[i-1];
7714     }
7715     ierr = PetscMemzero(count_is,nis*sizeof(PetscInt));CHKERRQ(ierr);
7716     ptr_idxs = recv_buffer_idxs_is;
7717     for (i=0;i<n_recvs;i++) {
7718       for (j=0;j<nis;j++) {
7719         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
7720         ierr = PetscMemcpy(&temp_idxs[j][count_is[j]],ptr_idxs+1,plen*sizeof(PetscInt));CHKERRQ(ierr);
7721         count_is[j] += plen; /* increment starting point of buffer for j-th IS */
7722         ptr_idxs += plen+1; /* shift pointer to received data */
7723       }
7724     }
7725     for (i=0;i<nis;i++) {
7726       ierr = ISDestroy(&isarray[i]);CHKERRQ(ierr);
7727       ierr = PetscSortRemoveDupsInt(&count_is[i],temp_idxs[i]);CHKERRQ(ierr);CHKERRQ(ierr);
7728       ierr = ISCreateGeneral(comm_n,count_is[i],temp_idxs[i],PETSC_COPY_VALUES,&isarray[i]);CHKERRQ(ierr);
7729     }
7730     ierr = PetscFree(count_is);CHKERRQ(ierr);
7731     ierr = PetscFree(temp_idxs[0]);CHKERRQ(ierr);
7732     ierr = PetscFree(temp_idxs);CHKERRQ(ierr);
7733   }
7734   /* free workspace */
7735   ierr = PetscFree(recv_buffer_idxs_is);CHKERRQ(ierr);
7736   ierr = MPI_Waitall(n_sends,send_req_idxs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7737   ierr = PetscFree(send_buffer_idxs);CHKERRQ(ierr);
7738   ierr = MPI_Waitall(n_sends,send_req_vals,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7739   if (isdense) {
7740     ierr = MatISGetLocalMat(mat,&local_mat);CHKERRQ(ierr);
7741     ierr = MatDenseRestoreArray(local_mat,&send_buffer_vals);CHKERRQ(ierr);
7742     ierr = MatISRestoreLocalMat(mat,&local_mat);CHKERRQ(ierr);
7743   } else {
7744     /* ierr = PetscFree(send_buffer_vals);CHKERRQ(ierr); */
7745   }
7746   if (nis) {
7747     ierr = MPI_Waitall(n_sends,send_req_idxs_is,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7748     ierr = PetscFree(send_buffer_idxs_is);CHKERRQ(ierr);
7749   }
7750 
7751   if (nvecs) {
7752     ierr = MPI_Waitall(n_recvs,recv_req_vecs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7753     ierr = MPI_Waitall(n_sends,send_req_vecs,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
7754     ierr = VecRestoreArray(nnsp_vec[0],&send_buffer_vecs);CHKERRQ(ierr);
7755     ierr = VecDestroy(&nnsp_vec[0]);CHKERRQ(ierr);
7756     ierr = VecCreate(comm_n,&nnsp_vec[0]);CHKERRQ(ierr);
7757     ierr = VecSetSizes(nnsp_vec[0],new_local_rows,PETSC_DECIDE);CHKERRQ(ierr);
7758     ierr = VecSetType(nnsp_vec[0],VECSTANDARD);CHKERRQ(ierr);
7759     /* set values */
7760     ptr_vals = recv_buffer_vecs;
7761     ptr_idxs = recv_buffer_idxs_local;
7762     ierr = VecGetArray(nnsp_vec[0],&send_buffer_vecs);CHKERRQ(ierr);
7763     for (i=0;i<n_recvs;i++) {
7764       PetscInt j;
7765       for (j=0;j<*(ptr_idxs+1);j++) {
7766         send_buffer_vecs[*(ptr_idxs+2+j)] += *(ptr_vals + j);
7767       }
7768       ptr_idxs += olengths_idxs[i];
7769       ptr_vals += olengths_idxs[i]-2;
7770     }
7771     ierr = VecRestoreArray(nnsp_vec[0],&send_buffer_vecs);CHKERRQ(ierr);
7772     ierr = VecAssemblyBegin(nnsp_vec[0]);CHKERRQ(ierr);
7773     ierr = VecAssemblyEnd(nnsp_vec[0]);CHKERRQ(ierr);
7774   }
7775 
7776   ierr = PetscFree(recv_buffer_vecs);CHKERRQ(ierr);
7777   ierr = PetscFree(recv_buffer_idxs_local);CHKERRQ(ierr);
7778   ierr = PetscFree(recv_req_idxs);CHKERRQ(ierr);
7779   ierr = PetscFree(recv_req_vals);CHKERRQ(ierr);
7780   ierr = PetscFree(recv_req_vecs);CHKERRQ(ierr);
7781   ierr = PetscFree(recv_req_idxs_is);CHKERRQ(ierr);
7782   ierr = PetscFree(send_req_idxs);CHKERRQ(ierr);
7783   ierr = PetscFree(send_req_vals);CHKERRQ(ierr);
7784   ierr = PetscFree(send_req_vecs);CHKERRQ(ierr);
7785   ierr = PetscFree(send_req_idxs_is);CHKERRQ(ierr);
7786   ierr = PetscFree(ilengths_vals);CHKERRQ(ierr);
7787   ierr = PetscFree(ilengths_idxs);CHKERRQ(ierr);
7788   ierr = PetscFree(olengths_vals);CHKERRQ(ierr);
7789   ierr = PetscFree(olengths_idxs);CHKERRQ(ierr);
7790   ierr = PetscFree(onodes);CHKERRQ(ierr);
7791   if (nis) {
7792     ierr = PetscFree(ilengths_idxs_is);CHKERRQ(ierr);
7793     ierr = PetscFree(olengths_idxs_is);CHKERRQ(ierr);
7794     ierr = PetscFree(onodes_is);CHKERRQ(ierr);
7795   }
7796   ierr = PetscSubcommDestroy(&subcomm);CHKERRQ(ierr);
7797   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not partecipate */
7798     ierr = MatDestroy(mat_n);CHKERRQ(ierr);
7799     for (i=0;i<nis;i++) {
7800       ierr = ISDestroy(&isarray[i]);CHKERRQ(ierr);
7801     }
7802     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
7803       ierr = VecDestroy(&nnsp_vec[0]);CHKERRQ(ierr);
7804     }
7805     *mat_n = NULL;
7806   }
7807   PetscFunctionReturn(0);
7808 }
7809 
7810 /* temporary hack into ksp private data structure */
7811 #include <petsc/private/kspimpl.h>
7812 
7813 PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc,PetscScalar* coarse_submat_vals)
7814 {
7815   PC_BDDC                *pcbddc = (PC_BDDC*)pc->data;
7816   PC_IS                  *pcis = (PC_IS*)pc->data;
7817   Mat                    coarse_mat,coarse_mat_is,coarse_submat_dense;
7818   Mat                    coarsedivudotp = NULL;
7819   Mat                    coarseG,t_coarse_mat_is;
7820   MatNullSpace           CoarseNullSpace = NULL;
7821   ISLocalToGlobalMapping coarse_islg;
7822   IS                     coarse_is,*isarray;
7823   PetscInt               i,im_active=-1,active_procs=-1;
7824   PetscInt               nis,nisdofs,nisneu,nisvert;
7825   PC                     pc_temp;
7826   PCType                 coarse_pc_type;
7827   KSPType                coarse_ksp_type;
7828   PetscBool              multilevel_requested,multilevel_allowed;
7829   PetscBool              coarse_reuse;
7830   PetscInt               ncoarse,nedcfield;
7831   PetscBool              compute_vecs = PETSC_FALSE;
7832   PetscScalar            *array;
7833   MatReuse               coarse_mat_reuse;
7834   PetscBool              restr, full_restr, have_void;
7835   PetscMPIInt            commsize;
7836   PetscErrorCode         ierr;
7837 
7838   PetscFunctionBegin;
7839   ierr = PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
7840   /* Assign global numbering to coarse dofs */
7841   if (pcbddc->new_primal_space || pcbddc->coarse_size == -1) { /* a new primal space is present or it is the first initialization, so recompute global numbering */
7842     PetscInt ocoarse_size;
7843     compute_vecs = PETSC_TRUE;
7844 
7845     pcbddc->new_primal_space = PETSC_TRUE;
7846     ocoarse_size = pcbddc->coarse_size;
7847     ierr = PetscFree(pcbddc->global_primal_indices);CHKERRQ(ierr);
7848     ierr = PCBDDCComputePrimalNumbering(pc,&pcbddc->coarse_size,&pcbddc->global_primal_indices);CHKERRQ(ierr);
7849     /* see if we can avoid some work */
7850     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
7851       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
7852       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
7853         ierr = KSPReset(pcbddc->coarse_ksp);CHKERRQ(ierr);
7854         coarse_reuse = PETSC_FALSE;
7855       } else { /* we can safely reuse already computed coarse matrix */
7856         coarse_reuse = PETSC_TRUE;
7857       }
7858     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
7859       coarse_reuse = PETSC_FALSE;
7860     }
7861     /* reset any subassembling information */
7862     if (!coarse_reuse || pcbddc->recompute_topography) {
7863       ierr = ISDestroy(&pcbddc->coarse_subassembling);CHKERRQ(ierr);
7864     }
7865   } else { /* primal space is unchanged, so we can reuse coarse matrix */
7866     coarse_reuse = PETSC_TRUE;
7867   }
7868   /* assemble coarse matrix */
7869   if (coarse_reuse && pcbddc->coarse_ksp) {
7870     ierr = KSPGetOperators(pcbddc->coarse_ksp,&coarse_mat,NULL);CHKERRQ(ierr);
7871     ierr = PetscObjectReference((PetscObject)coarse_mat);CHKERRQ(ierr);
7872     coarse_mat_reuse = MAT_REUSE_MATRIX;
7873   } else {
7874     coarse_mat = NULL;
7875     coarse_mat_reuse = MAT_INITIAL_MATRIX;
7876   }
7877 
7878   /* creates temporary l2gmap and IS for coarse indexes */
7879   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),pcbddc->local_primal_size,pcbddc->global_primal_indices,PETSC_COPY_VALUES,&coarse_is);CHKERRQ(ierr);
7880   ierr = ISLocalToGlobalMappingCreateIS(coarse_is,&coarse_islg);CHKERRQ(ierr);
7881 
7882   /* creates temporary MATIS object for coarse matrix */
7883   ierr = MatCreateSeqDense(PETSC_COMM_SELF,pcbddc->local_primal_size,pcbddc->local_primal_size,NULL,&coarse_submat_dense);CHKERRQ(ierr);
7884   ierr = MatDenseGetArray(coarse_submat_dense,&array);CHKERRQ(ierr);
7885   ierr = PetscMemcpy(array,coarse_submat_vals,sizeof(*coarse_submat_vals)*pcbddc->local_primal_size*pcbddc->local_primal_size);CHKERRQ(ierr);
7886   ierr = MatDenseRestoreArray(coarse_submat_dense,&array);CHKERRQ(ierr);
7887   ierr = MatCreateIS(PetscObjectComm((PetscObject)pc),1,PETSC_DECIDE,PETSC_DECIDE,pcbddc->coarse_size,pcbddc->coarse_size,coarse_islg,NULL,&t_coarse_mat_is);CHKERRQ(ierr);
7888   ierr = MatISSetLocalMat(t_coarse_mat_is,coarse_submat_dense);CHKERRQ(ierr);
7889   ierr = MatAssemblyBegin(t_coarse_mat_is,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7890   ierr = MatAssemblyEnd(t_coarse_mat_is,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7891   ierr = MatDestroy(&coarse_submat_dense);CHKERRQ(ierr);
7892 
7893   /* count "active" (i.e. with positive local size) and "void" processes */
7894   im_active = !!(pcis->n);
7895   ierr = MPIU_Allreduce(&im_active,&active_procs,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
7896 
7897   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
7898   /* restr : whether if we want to exclude senders (which are not receivers) from the subassembling pattern */
7899   /* full_restr : just use the receivers from the subassembling pattern */
7900   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)pc),&commsize);CHKERRQ(ierr);
7901   coarse_mat_is = NULL;
7902   multilevel_allowed = PETSC_FALSE;
7903   multilevel_requested = PETSC_FALSE;
7904   pcbddc->coarse_eqs_per_proc = PetscMin(PetscMax(pcbddc->coarse_size,1),pcbddc->coarse_eqs_per_proc);
7905   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
7906   if (multilevel_requested) {
7907     ncoarse = active_procs/pcbddc->coarsening_ratio;
7908     restr = PETSC_FALSE;
7909     full_restr = PETSC_FALSE;
7910   } else {
7911     ncoarse = pcbddc->coarse_size/pcbddc->coarse_eqs_per_proc;
7912     restr = PETSC_TRUE;
7913     full_restr = PETSC_TRUE;
7914   }
7915   if (!pcbddc->coarse_size || commsize == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
7916   ncoarse = PetscMax(1,ncoarse);
7917   if (!pcbddc->coarse_subassembling) {
7918     if (pcbddc->coarsening_ratio > 1) {
7919       if (multilevel_requested) {
7920         ierr = PCBDDCMatISGetSubassemblingPattern(pc->pmat,&ncoarse,pcbddc->coarse_adj_red,&pcbddc->coarse_subassembling,&have_void);CHKERRQ(ierr);
7921       } else {
7922         ierr = PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is,&ncoarse,pcbddc->coarse_adj_red,&pcbddc->coarse_subassembling,&have_void);CHKERRQ(ierr);
7923       }
7924     } else {
7925       PetscMPIInt rank;
7926       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank);CHKERRQ(ierr);
7927       have_void = (active_procs == (PetscInt)commsize) ? PETSC_FALSE : PETSC_TRUE;
7928       ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),1,rank,1,&pcbddc->coarse_subassembling);CHKERRQ(ierr);
7929     }
7930   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
7931     PetscInt    psum;
7932     if (pcbddc->coarse_ksp) psum = 1;
7933     else psum = 0;
7934     ierr = MPIU_Allreduce(&psum,&ncoarse,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
7935     if (ncoarse < commsize) have_void = PETSC_TRUE;
7936   }
7937   /* determine if we can go multilevel */
7938   if (multilevel_requested) {
7939     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
7940     else restr = full_restr = PETSC_TRUE; /* 1 subdomain, use a direct solver */
7941   }
7942   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
7943 
7944   /* dump subassembling pattern */
7945   if (pcbddc->dbg_flag && multilevel_allowed) {
7946     ierr = ISView(pcbddc->coarse_subassembling,pcbddc->dbg_viewer);CHKERRQ(ierr);
7947   }
7948 
7949   /* compute dofs splitting and neumann boundaries for coarse dofs */
7950   nedcfield = -1;
7951   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal)) { /* protects from unneded computations */
7952     PetscInt               *tidxs,*tidxs2,nout,tsize,i;
7953     const PetscInt         *idxs;
7954     ISLocalToGlobalMapping tmap;
7955 
7956     /* create map between primal indices (in local representative ordering) and local primal numbering */
7957     ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF,1,pcbddc->local_primal_size,pcbddc->primal_indices_local_idxs,PETSC_COPY_VALUES,&tmap);CHKERRQ(ierr);
7958     /* allocate space for temporary storage */
7959     ierr = PetscMalloc1(pcbddc->local_primal_size,&tidxs);CHKERRQ(ierr);
7960     ierr = PetscMalloc1(pcbddc->local_primal_size,&tidxs2);CHKERRQ(ierr);
7961     /* allocate for IS array */
7962     nisdofs = pcbddc->n_ISForDofsLocal;
7963     if (pcbddc->nedclocal) {
7964       if (pcbddc->nedfield > -1) {
7965         nedcfield = pcbddc->nedfield;
7966       } else {
7967         nedcfield = 0;
7968         if (nisdofs) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"This should not happen (%d)",nisdofs);
7969         nisdofs = 1;
7970       }
7971     }
7972     nisneu = !!pcbddc->NeumannBoundariesLocal;
7973     nisvert = 0; /* nisvert is not used */
7974     nis = nisdofs + nisneu + nisvert;
7975     ierr = PetscMalloc1(nis,&isarray);CHKERRQ(ierr);
7976     /* dofs splitting */
7977     for (i=0;i<nisdofs;i++) {
7978       /* ierr = ISView(pcbddc->ISForDofsLocal[i],0);CHKERRQ(ierr); */
7979       if (nedcfield != i) {
7980         ierr = ISGetLocalSize(pcbddc->ISForDofsLocal[i],&tsize);CHKERRQ(ierr);
7981         ierr = ISGetIndices(pcbddc->ISForDofsLocal[i],&idxs);CHKERRQ(ierr);
7982         ierr = ISGlobalToLocalMappingApply(tmap,IS_GTOLM_DROP,tsize,idxs,&nout,tidxs);CHKERRQ(ierr);
7983         ierr = ISRestoreIndices(pcbddc->ISForDofsLocal[i],&idxs);CHKERRQ(ierr);
7984       } else {
7985         ierr = ISGetLocalSize(pcbddc->nedclocal,&tsize);CHKERRQ(ierr);
7986         ierr = ISGetIndices(pcbddc->nedclocal,&idxs);CHKERRQ(ierr);
7987         ierr = ISGlobalToLocalMappingApply(tmap,IS_GTOLM_DROP,tsize,idxs,&nout,tidxs);CHKERRQ(ierr);
7988         if (tsize != nout) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Failed when mapping coarse nedelec field! %d != %d\n",tsize,nout);
7989         ierr = ISRestoreIndices(pcbddc->nedclocal,&idxs);CHKERRQ(ierr);
7990       }
7991       ierr = ISLocalToGlobalMappingApply(coarse_islg,nout,tidxs,tidxs2);CHKERRQ(ierr);
7992       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nout,tidxs2,PETSC_COPY_VALUES,&isarray[i]);CHKERRQ(ierr);
7993       /* ierr = ISView(isarray[i],0);CHKERRQ(ierr); */
7994     }
7995     /* neumann boundaries */
7996     if (pcbddc->NeumannBoundariesLocal) {
7997       /* ierr = ISView(pcbddc->NeumannBoundariesLocal,0);CHKERRQ(ierr); */
7998       ierr = ISGetLocalSize(pcbddc->NeumannBoundariesLocal,&tsize);CHKERRQ(ierr);
7999       ierr = ISGetIndices(pcbddc->NeumannBoundariesLocal,&idxs);CHKERRQ(ierr);
8000       ierr = ISGlobalToLocalMappingApply(tmap,IS_GTOLM_DROP,tsize,idxs,&nout,tidxs);CHKERRQ(ierr);
8001       ierr = ISRestoreIndices(pcbddc->NeumannBoundariesLocal,&idxs);CHKERRQ(ierr);
8002       ierr = ISLocalToGlobalMappingApply(coarse_islg,nout,tidxs,tidxs2);CHKERRQ(ierr);
8003       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nout,tidxs2,PETSC_COPY_VALUES,&isarray[nisdofs]);CHKERRQ(ierr);
8004       /* ierr = ISView(isarray[nisdofs],0);CHKERRQ(ierr); */
8005     }
8006     /* free memory */
8007     ierr = PetscFree(tidxs);CHKERRQ(ierr);
8008     ierr = PetscFree(tidxs2);CHKERRQ(ierr);
8009     ierr = ISLocalToGlobalMappingDestroy(&tmap);CHKERRQ(ierr);
8010   } else {
8011     nis = 0;
8012     nisdofs = 0;
8013     nisneu = 0;
8014     nisvert = 0;
8015     isarray = NULL;
8016   }
8017   /* destroy no longer needed map */
8018   ierr = ISLocalToGlobalMappingDestroy(&coarse_islg);CHKERRQ(ierr);
8019 
8020   /* subassemble */
8021   if (multilevel_allowed) {
8022     Vec       vp[1];
8023     PetscInt  nvecs = 0;
8024     PetscBool reuse,reuser;
8025 
8026     if (coarse_mat) reuse = PETSC_TRUE;
8027     else reuse = PETSC_FALSE;
8028     ierr = MPIU_Allreduce(&reuse,&reuser,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
8029     vp[0] = NULL;
8030     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
8031       ierr = VecCreate(PetscObjectComm((PetscObject)pc),&vp[0]);CHKERRQ(ierr);
8032       ierr = VecSetSizes(vp[0],pcbddc->local_primal_size,PETSC_DECIDE);CHKERRQ(ierr);
8033       ierr = VecSetType(vp[0],VECSTANDARD);CHKERRQ(ierr);
8034       nvecs = 1;
8035 
8036       if (pcbddc->divudotp) {
8037         Mat      B,loc_divudotp;
8038         Vec      v,p;
8039         IS       dummy;
8040         PetscInt np;
8041 
8042         ierr = MatISGetLocalMat(pcbddc->divudotp,&loc_divudotp);CHKERRQ(ierr);
8043         ierr = MatGetSize(loc_divudotp,&np,NULL);CHKERRQ(ierr);
8044         ierr = ISCreateStride(PETSC_COMM_SELF,np,0,1,&dummy);CHKERRQ(ierr);
8045         ierr = MatCreateSubMatrix(loc_divudotp,dummy,pcis->is_B_local,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
8046         ierr = MatCreateVecs(B,&v,&p);CHKERRQ(ierr);
8047         ierr = VecSet(p,1.);CHKERRQ(ierr);
8048         ierr = MatMultTranspose(B,p,v);CHKERRQ(ierr);
8049         ierr = VecDestroy(&p);CHKERRQ(ierr);
8050         ierr = MatDestroy(&B);CHKERRQ(ierr);
8051         ierr = VecGetArray(vp[0],&array);CHKERRQ(ierr);
8052         ierr = VecPlaceArray(pcbddc->vec1_P,array);CHKERRQ(ierr);
8053         ierr = VecRestoreArray(vp[0],&array);CHKERRQ(ierr);
8054         ierr = MatMultTranspose(pcbddc->coarse_phi_B,v,pcbddc->vec1_P);CHKERRQ(ierr);
8055         ierr = VecResetArray(pcbddc->vec1_P);CHKERRQ(ierr);
8056         ierr = ISDestroy(&dummy);CHKERRQ(ierr);
8057         ierr = VecDestroy(&v);CHKERRQ(ierr);
8058       }
8059     }
8060     if (reuser) {
8061       ierr = PCBDDCMatISSubassemble(t_coarse_mat_is,pcbddc->coarse_subassembling,0,restr,full_restr,PETSC_TRUE,&coarse_mat,nis,isarray,nvecs,vp);CHKERRQ(ierr);
8062     } else {
8063       ierr = PCBDDCMatISSubassemble(t_coarse_mat_is,pcbddc->coarse_subassembling,0,restr,full_restr,PETSC_FALSE,&coarse_mat_is,nis,isarray,nvecs,vp);CHKERRQ(ierr);
8064     }
8065     if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
8066       PetscScalar *arraym,*arrayv;
8067       PetscInt    nl;
8068       ierr = VecGetLocalSize(vp[0],&nl);CHKERRQ(ierr);
8069       ierr = MatCreateSeqDense(PETSC_COMM_SELF,1,nl,NULL,&coarsedivudotp);CHKERRQ(ierr);
8070       ierr = MatDenseGetArray(coarsedivudotp,&arraym);CHKERRQ(ierr);
8071       ierr = VecGetArray(vp[0],&arrayv);CHKERRQ(ierr);
8072       ierr = PetscMemcpy(arraym,arrayv,nl*sizeof(PetscScalar));CHKERRQ(ierr);
8073       ierr = VecRestoreArray(vp[0],&arrayv);CHKERRQ(ierr);
8074       ierr = MatDenseRestoreArray(coarsedivudotp,&arraym);CHKERRQ(ierr);
8075       ierr = VecDestroy(&vp[0]);CHKERRQ(ierr);
8076     } else {
8077       ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,0,0,1,NULL,&coarsedivudotp);CHKERRQ(ierr);
8078     }
8079   } else {
8080     ierr = PCBDDCMatISSubassemble(t_coarse_mat_is,pcbddc->coarse_subassembling,0,restr,full_restr,PETSC_FALSE,&coarse_mat_is,0,NULL,0,NULL);CHKERRQ(ierr);
8081   }
8082   if (coarse_mat_is || coarse_mat) {
8083     PetscMPIInt size;
8084     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)coarse_mat_is),&size);CHKERRQ(ierr);
8085     if (!multilevel_allowed) {
8086       ierr = MatConvert(coarse_mat_is,MATAIJ,coarse_mat_reuse,&coarse_mat);CHKERRQ(ierr);
8087     } else {
8088       Mat A;
8089 
8090       /* if this matrix is present, it means we are not reusing the coarse matrix */
8091       if (coarse_mat_is) {
8092         if (coarse_mat) SETERRQ(PetscObjectComm((PetscObject)coarse_mat_is),PETSC_ERR_PLIB,"This should not happen");
8093         ierr = PetscObjectReference((PetscObject)coarse_mat_is);CHKERRQ(ierr);
8094         coarse_mat = coarse_mat_is;
8095       }
8096       /* be sure we don't have MatSeqDENSE as local mat */
8097       ierr = MatISGetLocalMat(coarse_mat,&A);CHKERRQ(ierr);
8098       ierr = MatConvert(A,MATSEQAIJ,MAT_INPLACE_MATRIX,&A);CHKERRQ(ierr);
8099     }
8100   }
8101   ierr = MatDestroy(&t_coarse_mat_is);CHKERRQ(ierr);
8102   ierr = MatDestroy(&coarse_mat_is);CHKERRQ(ierr);
8103 
8104   /* create local to global scatters for coarse problem */
8105   if (compute_vecs) {
8106     PetscInt lrows;
8107     ierr = VecDestroy(&pcbddc->coarse_vec);CHKERRQ(ierr);
8108     if (coarse_mat) {
8109       ierr = MatGetLocalSize(coarse_mat,&lrows,NULL);CHKERRQ(ierr);
8110     } else {
8111       lrows = 0;
8112     }
8113     ierr = VecCreate(PetscObjectComm((PetscObject)pc),&pcbddc->coarse_vec);CHKERRQ(ierr);
8114     ierr = VecSetSizes(pcbddc->coarse_vec,lrows,PETSC_DECIDE);CHKERRQ(ierr);
8115     ierr = VecSetType(pcbddc->coarse_vec,VECSTANDARD);CHKERRQ(ierr);
8116     ierr = VecScatterDestroy(&pcbddc->coarse_loc_to_glob);CHKERRQ(ierr);
8117     ierr = VecScatterCreate(pcbddc->vec1_P,NULL,pcbddc->coarse_vec,coarse_is,&pcbddc->coarse_loc_to_glob);CHKERRQ(ierr);
8118   }
8119   ierr = ISDestroy(&coarse_is);CHKERRQ(ierr);
8120 
8121   /* set defaults for coarse KSP and PC */
8122   if (multilevel_allowed) {
8123     coarse_ksp_type = KSPRICHARDSON;
8124     coarse_pc_type = PCBDDC;
8125   } else {
8126     coarse_ksp_type = KSPPREONLY;
8127     coarse_pc_type = PCREDUNDANT;
8128   }
8129 
8130   /* print some info if requested */
8131   if (pcbddc->dbg_flag) {
8132     if (!multilevel_allowed) {
8133       ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
8134       if (multilevel_requested) {
8135         ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Not enough active processes on level %d (active processes %d, coarsening ratio %d)\n",pcbddc->current_level,active_procs,pcbddc->coarsening_ratio);CHKERRQ(ierr);
8136       } else if (pcbddc->max_levels) {
8137         ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Maximum number of requested levels reached (%d)\n",pcbddc->max_levels);CHKERRQ(ierr);
8138       }
8139       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8140     }
8141   }
8142 
8143   /* communicate coarse discrete gradient */
8144   coarseG = NULL;
8145   if (pcbddc->nedcG && multilevel_allowed) {
8146     MPI_Comm ccomm;
8147     if (coarse_mat) {
8148       ccomm = PetscObjectComm((PetscObject)coarse_mat);
8149     } else {
8150       ccomm = MPI_COMM_NULL;
8151     }
8152     ierr = MatMPIAIJRestrict(pcbddc->nedcG,ccomm,&coarseG);CHKERRQ(ierr);
8153   }
8154 
8155   /* create the coarse KSP object only once with defaults */
8156   if (coarse_mat) {
8157     PetscBool   isredundant,isnn,isbddc;
8158     PetscViewer dbg_viewer = NULL;
8159 
8160     if (pcbddc->dbg_flag) {
8161       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
8162       ierr = PetscViewerASCIIAddTab(dbg_viewer,2*pcbddc->current_level);CHKERRQ(ierr);
8163     }
8164     if (!pcbddc->coarse_ksp) {
8165       char   prefix[256],str_level[16];
8166       size_t len;
8167 
8168       ierr = KSPCreate(PetscObjectComm((PetscObject)coarse_mat),&pcbddc->coarse_ksp);CHKERRQ(ierr);
8169       ierr = KSPSetErrorIfNotConverged(pcbddc->coarse_ksp,pc->erroriffailure);CHKERRQ(ierr);
8170       ierr = PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp,(PetscObject)pc,1);CHKERRQ(ierr);
8171       ierr = KSPSetTolerances(pcbddc->coarse_ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,1);CHKERRQ(ierr);
8172       ierr = KSPSetOperators(pcbddc->coarse_ksp,coarse_mat,coarse_mat);CHKERRQ(ierr);
8173       ierr = KSPSetType(pcbddc->coarse_ksp,coarse_ksp_type);CHKERRQ(ierr);
8174       ierr = KSPSetNormType(pcbddc->coarse_ksp,KSP_NORM_NONE);CHKERRQ(ierr);
8175       ierr = KSPGetPC(pcbddc->coarse_ksp,&pc_temp);CHKERRQ(ierr);
8176       /* TODO is this logic correct? should check for coarse_mat type */
8177       ierr = PCSetType(pc_temp,coarse_pc_type);CHKERRQ(ierr);
8178       /* prefix */
8179       ierr = PetscStrcpy(prefix,"");CHKERRQ(ierr);
8180       ierr = PetscStrcpy(str_level,"");CHKERRQ(ierr);
8181       if (!pcbddc->current_level) {
8182         ierr = PetscStrncpy(prefix,((PetscObject)pc)->prefix,sizeof(prefix));CHKERRQ(ierr);
8183         ierr = PetscStrlcat(prefix,"pc_bddc_coarse_",sizeof(prefix));CHKERRQ(ierr);
8184       } else {
8185         ierr = PetscStrlen(((PetscObject)pc)->prefix,&len);CHKERRQ(ierr);
8186         if (pcbddc->current_level>1) len -= 3; /* remove "lX_" with X level number */
8187         if (pcbddc->current_level>10) len -= 1; /* remove another char from level number */
8188         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
8189         ierr = PetscStrncpy(prefix,((PetscObject)pc)->prefix,len+1);CHKERRQ(ierr);
8190         ierr = PetscSNPrintf(str_level,sizeof(str_level),"l%d_",(int)(pcbddc->current_level));CHKERRQ(ierr);
8191         ierr = PetscStrlcat(prefix,str_level,sizeof(prefix));CHKERRQ(ierr);
8192       }
8193       ierr = KSPSetOptionsPrefix(pcbddc->coarse_ksp,prefix);CHKERRQ(ierr);
8194       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
8195       ierr = PCBDDCSetLevel(pc_temp,pcbddc->current_level+1);CHKERRQ(ierr);
8196       ierr = PCBDDCSetCoarseningRatio(pc_temp,pcbddc->coarsening_ratio);CHKERRQ(ierr);
8197       ierr = PCBDDCSetLevels(pc_temp,pcbddc->max_levels);CHKERRQ(ierr);
8198       /* allow user customization */
8199       ierr = KSPSetFromOptions(pcbddc->coarse_ksp);CHKERRQ(ierr);
8200     }
8201     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
8202     ierr = KSPGetPC(pcbddc->coarse_ksp,&pc_temp);CHKERRQ(ierr);
8203     if (nisdofs) {
8204       ierr = PCBDDCSetDofsSplitting(pc_temp,nisdofs,isarray);CHKERRQ(ierr);
8205       for (i=0;i<nisdofs;i++) {
8206         ierr = ISDestroy(&isarray[i]);CHKERRQ(ierr);
8207       }
8208     }
8209     if (nisneu) {
8210       ierr = PCBDDCSetNeumannBoundaries(pc_temp,isarray[nisdofs]);CHKERRQ(ierr);
8211       ierr = ISDestroy(&isarray[nisdofs]);CHKERRQ(ierr);
8212     }
8213     if (nisvert) {
8214       ierr = PCBDDCSetPrimalVerticesIS(pc_temp,isarray[nis-1]);CHKERRQ(ierr);
8215       ierr = ISDestroy(&isarray[nis-1]);CHKERRQ(ierr);
8216     }
8217     if (coarseG) {
8218       ierr = PCBDDCSetDiscreteGradient(pc_temp,coarseG,1,nedcfield,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
8219     }
8220 
8221     /* get some info after set from options */
8222     ierr = PetscObjectTypeCompare((PetscObject)pc_temp,PCBDDC,&isbddc);CHKERRQ(ierr);
8223     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
8224     if (isbddc && !multilevel_allowed) {
8225       ierr   = PCSetType(pc_temp,coarse_pc_type);CHKERRQ(ierr);
8226       isbddc = PETSC_FALSE;
8227     }
8228     /* multilevel cannot be done with coarse PCs different from BDDC or NN */
8229     ierr = PetscObjectTypeCompare((PetscObject)pc_temp,PCNN,&isnn);CHKERRQ(ierr);
8230     if (multilevel_requested && multilevel_allowed && !isbddc && !isnn) {
8231       ierr   = PCSetType(pc_temp,PCBDDC);CHKERRQ(ierr);
8232       isbddc = PETSC_TRUE;
8233     }
8234     ierr = PetscObjectTypeCompare((PetscObject)pc_temp,PCREDUNDANT,&isredundant);CHKERRQ(ierr);
8235     if (isredundant) {
8236       KSP inner_ksp;
8237       PC  inner_pc;
8238 
8239       ierr = PCRedundantGetKSP(pc_temp,&inner_ksp);CHKERRQ(ierr);
8240       ierr = KSPGetPC(inner_ksp,&inner_pc);CHKERRQ(ierr);
8241     }
8242 
8243     /* parameters which miss an API */
8244     ierr = PetscObjectTypeCompare((PetscObject)pc_temp,PCBDDC,&isbddc);CHKERRQ(ierr);
8245     if (isbddc) {
8246       PC_BDDC* pcbddc_coarse = (PC_BDDC*)pc_temp->data;
8247 
8248       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
8249       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8250       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
8251       if (pcbddc_coarse->benign_saddle_point) {
8252         Mat                    coarsedivudotp_is;
8253         ISLocalToGlobalMapping l2gmap,rl2g,cl2g;
8254         IS                     row,col;
8255         const PetscInt         *gidxs;
8256         PetscInt               n,st,M,N;
8257 
8258         ierr = MatGetSize(coarsedivudotp,&n,NULL);CHKERRQ(ierr);
8259         ierr = MPI_Scan(&n,&st,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)coarse_mat));CHKERRQ(ierr);
8260         st   = st-n;
8261         ierr = ISCreateStride(PetscObjectComm((PetscObject)coarse_mat),1,st,1,&row);CHKERRQ(ierr);
8262         ierr = MatGetLocalToGlobalMapping(coarse_mat,&l2gmap,NULL);CHKERRQ(ierr);
8263         ierr = ISLocalToGlobalMappingGetSize(l2gmap,&n);CHKERRQ(ierr);
8264         ierr = ISLocalToGlobalMappingGetIndices(l2gmap,&gidxs);CHKERRQ(ierr);
8265         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat),n,gidxs,PETSC_COPY_VALUES,&col);CHKERRQ(ierr);
8266         ierr = ISLocalToGlobalMappingRestoreIndices(l2gmap,&gidxs);CHKERRQ(ierr);
8267         ierr = ISLocalToGlobalMappingCreateIS(row,&rl2g);CHKERRQ(ierr);
8268         ierr = ISLocalToGlobalMappingCreateIS(col,&cl2g);CHKERRQ(ierr);
8269         ierr = ISGetSize(row,&M);CHKERRQ(ierr);
8270         ierr = MatGetSize(coarse_mat,&N,NULL);CHKERRQ(ierr);
8271         ierr = ISDestroy(&row);CHKERRQ(ierr);
8272         ierr = ISDestroy(&col);CHKERRQ(ierr);
8273         ierr = MatCreate(PetscObjectComm((PetscObject)coarse_mat),&coarsedivudotp_is);CHKERRQ(ierr);
8274         ierr = MatSetType(coarsedivudotp_is,MATIS);CHKERRQ(ierr);
8275         ierr = MatSetSizes(coarsedivudotp_is,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
8276         ierr = MatSetLocalToGlobalMapping(coarsedivudotp_is,rl2g,cl2g);CHKERRQ(ierr);
8277         ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
8278         ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
8279         ierr = MatISSetLocalMat(coarsedivudotp_is,coarsedivudotp);CHKERRQ(ierr);
8280         ierr = MatDestroy(&coarsedivudotp);CHKERRQ(ierr);
8281         ierr = PCBDDCSetDivergenceMat(pc_temp,coarsedivudotp_is,PETSC_FALSE,NULL);CHKERRQ(ierr);
8282         ierr = MatDestroy(&coarsedivudotp_is);CHKERRQ(ierr);
8283         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8284         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8285       }
8286     }
8287 
8288     /* propagate symmetry info of coarse matrix */
8289     ierr = MatSetOption(coarse_mat,MAT_STRUCTURALLY_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
8290     if (pc->pmat->symmetric_set) {
8291       ierr = MatSetOption(coarse_mat,MAT_SYMMETRIC,pc->pmat->symmetric);CHKERRQ(ierr);
8292     }
8293     if (pc->pmat->hermitian_set) {
8294       ierr = MatSetOption(coarse_mat,MAT_HERMITIAN,pc->pmat->hermitian);CHKERRQ(ierr);
8295     }
8296     if (pc->pmat->spd_set) {
8297       ierr = MatSetOption(coarse_mat,MAT_SPD,pc->pmat->spd);CHKERRQ(ierr);
8298     }
8299     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) {
8300       ierr = MatSetOption(coarse_mat,MAT_SPD,PETSC_TRUE);CHKERRQ(ierr);
8301     }
8302     /* set operators */
8303     ierr = MatViewFromOptions(coarse_mat,(PetscObject)pc,"-pc_bddc_coarse_mat_view");CHKERRQ(ierr);
8304     ierr = KSPSetOperators(pcbddc->coarse_ksp,coarse_mat,coarse_mat);CHKERRQ(ierr);
8305     if (pcbddc->dbg_flag) {
8306       ierr = PetscViewerASCIISubtractTab(dbg_viewer,2*pcbddc->current_level);CHKERRQ(ierr);
8307     }
8308   }
8309   ierr = MatDestroy(&coarseG);CHKERRQ(ierr);
8310   ierr = PetscFree(isarray);CHKERRQ(ierr);
8311 #if 0
8312   {
8313     PetscViewer viewer;
8314     char filename[256];
8315     sprintf(filename,"coarse_mat_level%d.m",pcbddc->current_level);
8316     ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer);CHKERRQ(ierr);
8317     ierr = PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr);
8318     ierr = MatView(coarse_mat,viewer);CHKERRQ(ierr);
8319     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
8320     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
8321   }
8322 #endif
8323 
8324   if (pcbddc->coarse_ksp) {
8325     Vec crhs,csol;
8326 
8327     ierr = KSPGetSolution(pcbddc->coarse_ksp,&csol);CHKERRQ(ierr);
8328     ierr = KSPGetRhs(pcbddc->coarse_ksp,&crhs);CHKERRQ(ierr);
8329     if (!csol) {
8330       ierr = MatCreateVecs(coarse_mat,&((pcbddc->coarse_ksp)->vec_sol),NULL);CHKERRQ(ierr);
8331     }
8332     if (!crhs) {
8333       ierr = MatCreateVecs(coarse_mat,NULL,&((pcbddc->coarse_ksp)->vec_rhs));CHKERRQ(ierr);
8334     }
8335   }
8336   ierr = MatDestroy(&coarsedivudotp);CHKERRQ(ierr);
8337 
8338   /* compute null space for coarse solver if the benign trick has been requested */
8339   if (pcbddc->benign_null) {
8340 
8341     ierr = VecSet(pcbddc->vec1_P,0.);CHKERRQ(ierr);
8342     for (i=0;i<pcbddc->benign_n;i++) {
8343       ierr = VecSetValue(pcbddc->vec1_P,pcbddc->local_primal_size-pcbddc->benign_n+i,1.0,INSERT_VALUES);CHKERRQ(ierr);
8344     }
8345     ierr = VecAssemblyBegin(pcbddc->vec1_P);CHKERRQ(ierr);
8346     ierr = VecAssemblyEnd(pcbddc->vec1_P);CHKERRQ(ierr);
8347     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8348     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8349     if (coarse_mat) {
8350       Vec         nullv;
8351       PetscScalar *array,*array2;
8352       PetscInt    nl;
8353 
8354       ierr = MatCreateVecs(coarse_mat,&nullv,NULL);CHKERRQ(ierr);
8355       ierr = VecGetLocalSize(nullv,&nl);CHKERRQ(ierr);
8356       ierr = VecGetArrayRead(pcbddc->coarse_vec,(const PetscScalar**)&array);CHKERRQ(ierr);
8357       ierr = VecGetArray(nullv,&array2);CHKERRQ(ierr);
8358       ierr = PetscMemcpy(array2,array,nl*sizeof(*array));CHKERRQ(ierr);
8359       ierr = VecRestoreArray(nullv,&array2);CHKERRQ(ierr);
8360       ierr = VecRestoreArrayRead(pcbddc->coarse_vec,(const PetscScalar**)&array);CHKERRQ(ierr);
8361       ierr = VecNormalize(nullv,NULL);CHKERRQ(ierr);
8362       ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat),PETSC_FALSE,1,&nullv,&CoarseNullSpace);CHKERRQ(ierr);
8363       ierr = VecDestroy(&nullv);CHKERRQ(ierr);
8364     }
8365   }
8366   ierr = PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
8367 
8368   ierr = PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
8369   if (pcbddc->coarse_ksp) {
8370     PetscBool ispreonly;
8371 
8372     if (CoarseNullSpace) {
8373       PetscBool isnull;
8374       ierr = MatNullSpaceTest(CoarseNullSpace,coarse_mat,&isnull);CHKERRQ(ierr);
8375       if (isnull) {
8376         ierr = MatSetNullSpace(coarse_mat,CoarseNullSpace);CHKERRQ(ierr);
8377       }
8378       /* TODO: add local nullspaces (if any) */
8379     }
8380     /* setup coarse ksp */
8381     ierr = KSPSetUp(pcbddc->coarse_ksp);CHKERRQ(ierr);
8382     /* Check coarse problem if in debug mode or if solving with an iterative method */
8383     ierr = PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp,KSPPREONLY,&ispreonly);CHKERRQ(ierr);
8384     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates) ) {
8385       KSP       check_ksp;
8386       KSPType   check_ksp_type;
8387       PC        check_pc;
8388       Vec       check_vec,coarse_vec;
8389       PetscReal abs_infty_error,infty_error,lambda_min=1.0,lambda_max=1.0;
8390       PetscInt  its;
8391       PetscBool compute_eigs;
8392       PetscReal *eigs_r,*eigs_c;
8393       PetscInt  neigs;
8394       const char *prefix;
8395 
8396       /* Create ksp object suitable for estimation of extreme eigenvalues */
8397       ierr = KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp),&check_ksp);CHKERRQ(ierr);
8398       ierr = KSPSetErrorIfNotConverged(pcbddc->coarse_ksp,pc->erroriffailure);CHKERRQ(ierr);
8399       ierr = KSPSetOperators(check_ksp,coarse_mat,coarse_mat);CHKERRQ(ierr);
8400       ierr = KSPSetTolerances(check_ksp,1.e-12,1.e-12,PETSC_DEFAULT,pcbddc->coarse_size);CHKERRQ(ierr);
8401       /* prevent from setup unneeded object */
8402       ierr = KSPGetPC(check_ksp,&check_pc);CHKERRQ(ierr);
8403       ierr = PCSetType(check_pc,PCNONE);CHKERRQ(ierr);
8404       if (ispreonly) {
8405         check_ksp_type = KSPPREONLY;
8406         compute_eigs = PETSC_FALSE;
8407       } else {
8408         check_ksp_type = KSPGMRES;
8409         compute_eigs = PETSC_TRUE;
8410       }
8411       ierr = KSPSetType(check_ksp,check_ksp_type);CHKERRQ(ierr);
8412       ierr = KSPSetComputeSingularValues(check_ksp,compute_eigs);CHKERRQ(ierr);
8413       ierr = KSPSetComputeEigenvalues(check_ksp,compute_eigs);CHKERRQ(ierr);
8414       ierr = KSPGMRESSetRestart(check_ksp,pcbddc->coarse_size+1);CHKERRQ(ierr);
8415       ierr = KSPGetOptionsPrefix(pcbddc->coarse_ksp,&prefix);CHKERRQ(ierr);
8416       ierr = KSPSetOptionsPrefix(check_ksp,prefix);CHKERRQ(ierr);
8417       ierr = KSPAppendOptionsPrefix(check_ksp,"check_");CHKERRQ(ierr);
8418       ierr = KSPSetFromOptions(check_ksp);CHKERRQ(ierr);
8419       ierr = KSPSetUp(check_ksp);CHKERRQ(ierr);
8420       ierr = KSPGetPC(pcbddc->coarse_ksp,&check_pc);CHKERRQ(ierr);
8421       ierr = KSPSetPC(check_ksp,check_pc);CHKERRQ(ierr);
8422       /* create random vec */
8423       ierr = MatCreateVecs(coarse_mat,&coarse_vec,&check_vec);CHKERRQ(ierr);
8424       ierr = VecSetRandom(check_vec,NULL);CHKERRQ(ierr);
8425       ierr = MatMult(coarse_mat,check_vec,coarse_vec);CHKERRQ(ierr);
8426       /* solve coarse problem */
8427       ierr = KSPSolve(check_ksp,coarse_vec,coarse_vec);CHKERRQ(ierr);
8428       /* set eigenvalue estimation if preonly has not been requested */
8429       if (compute_eigs) {
8430         ierr = PetscMalloc1(pcbddc->coarse_size+1,&eigs_r);CHKERRQ(ierr);
8431         ierr = PetscMalloc1(pcbddc->coarse_size+1,&eigs_c);CHKERRQ(ierr);
8432         ierr = KSPComputeEigenvalues(check_ksp,pcbddc->coarse_size+1,eigs_r,eigs_c,&neigs);CHKERRQ(ierr);
8433         if (neigs) {
8434           lambda_max = eigs_r[neigs-1];
8435           lambda_min = eigs_r[0];
8436           if (pcbddc->use_coarse_estimates) {
8437             if (lambda_max>=lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
8438               ierr = KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp,lambda_max+PETSC_SMALL,lambda_min);CHKERRQ(ierr);
8439               ierr = KSPRichardsonSetScale(pcbddc->coarse_ksp,2.0/(lambda_max+lambda_min));CHKERRQ(ierr);
8440             }
8441           }
8442         }
8443       }
8444 
8445       /* check coarse problem residual error */
8446       if (pcbddc->dbg_flag) {
8447         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
8448         ierr = PetscViewerASCIIAddTab(dbg_viewer,2*(pcbddc->current_level+1));CHKERRQ(ierr);
8449         ierr = VecAXPY(check_vec,-1.0,coarse_vec);CHKERRQ(ierr);
8450         ierr = VecNorm(check_vec,NORM_INFINITY,&infty_error);CHKERRQ(ierr);
8451         ierr = MatMult(coarse_mat,check_vec,coarse_vec);CHKERRQ(ierr);
8452         ierr = VecNorm(coarse_vec,NORM_INFINITY,&abs_infty_error);CHKERRQ(ierr);
8453         ierr = PetscViewerASCIIPrintf(dbg_viewer,"Coarse problem details (use estimates %d)\n",pcbddc->use_coarse_estimates);CHKERRQ(ierr);
8454         ierr = PetscObjectPrintClassNamePrefixType((PetscObject)(pcbddc->coarse_ksp),dbg_viewer);CHKERRQ(ierr);
8455         ierr = PetscObjectPrintClassNamePrefixType((PetscObject)(check_pc),dbg_viewer);CHKERRQ(ierr);
8456         ierr = PetscViewerASCIIPrintf(dbg_viewer,"Coarse problem exact infty_error   : %1.6e\n",infty_error);CHKERRQ(ierr);
8457         ierr = PetscViewerASCIIPrintf(dbg_viewer,"Coarse problem residual infty_error: %1.6e\n",abs_infty_error);CHKERRQ(ierr);
8458         if (CoarseNullSpace) {
8459           ierr = PetscViewerASCIIPrintf(dbg_viewer,"Coarse problem is singular\n");CHKERRQ(ierr);
8460         }
8461         if (compute_eigs) {
8462           PetscReal          lambda_max_s,lambda_min_s;
8463           KSPConvergedReason reason;
8464           ierr = KSPGetType(check_ksp,&check_ksp_type);CHKERRQ(ierr);
8465           ierr = KSPGetIterationNumber(check_ksp,&its);CHKERRQ(ierr);
8466           ierr = KSPGetConvergedReason(check_ksp,&reason);CHKERRQ(ierr);
8467           ierr = KSPComputeExtremeSingularValues(check_ksp,&lambda_max_s,&lambda_min_s);CHKERRQ(ierr);
8468           ierr = PetscViewerASCIIPrintf(dbg_viewer,"Coarse problem eigenvalues (estimated with %d iterations of %s, conv reason %d): %1.6e %1.6e (%1.6e %1.6e)\n",its,check_ksp_type,reason,lambda_min,lambda_max,lambda_min_s,lambda_max_s);CHKERRQ(ierr);
8469           for (i=0;i<neigs;i++) {
8470             ierr = PetscViewerASCIIPrintf(dbg_viewer,"%1.6e %1.6ei\n",eigs_r[i],eigs_c[i]);CHKERRQ(ierr);
8471           }
8472         }
8473         ierr = PetscViewerFlush(dbg_viewer);CHKERRQ(ierr);
8474         ierr = PetscViewerASCIISubtractTab(dbg_viewer,2*(pcbddc->current_level+1));CHKERRQ(ierr);
8475       }
8476       ierr = VecDestroy(&check_vec);CHKERRQ(ierr);
8477       ierr = VecDestroy(&coarse_vec);CHKERRQ(ierr);
8478       ierr = KSPDestroy(&check_ksp);CHKERRQ(ierr);
8479       if (compute_eigs) {
8480         ierr = PetscFree(eigs_r);CHKERRQ(ierr);
8481         ierr = PetscFree(eigs_c);CHKERRQ(ierr);
8482       }
8483     }
8484   }
8485   ierr = MatNullSpaceDestroy(&CoarseNullSpace);CHKERRQ(ierr);
8486   /* print additional info */
8487   if (pcbddc->dbg_flag) {
8488     /* waits until all processes reaches this point */
8489     ierr = PetscBarrier((PetscObject)pc);CHKERRQ(ierr);
8490     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Coarse solver setup completed at level %d\n",pcbddc->current_level);CHKERRQ(ierr);
8491     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8492   }
8493 
8494   /* free memory */
8495   ierr = MatDestroy(&coarse_mat);CHKERRQ(ierr);
8496   ierr = PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
8497   PetscFunctionReturn(0);
8498 }
8499 
8500 PetscErrorCode PCBDDCComputePrimalNumbering(PC pc,PetscInt* coarse_size_n,PetscInt** local_primal_indices_n)
8501 {
8502   PC_BDDC*       pcbddc = (PC_BDDC*)pc->data;
8503   PC_IS*         pcis = (PC_IS*)pc->data;
8504   Mat_IS*        matis = (Mat_IS*)pc->pmat->data;
8505   IS             subset,subset_mult,subset_n;
8506   PetscInt       local_size,coarse_size=0;
8507   PetscInt       *local_primal_indices=NULL;
8508   const PetscInt *t_local_primal_indices;
8509   PetscErrorCode ierr;
8510 
8511   PetscFunctionBegin;
8512   /* Compute global number of coarse dofs */
8513   if (pcbddc->local_primal_size && !pcbddc->local_primal_ref_node) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"BDDC ConstraintsSetUp should be called first");
8514   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)),pcbddc->local_primal_size_cc,pcbddc->local_primal_ref_node,PETSC_COPY_VALUES,&subset_n);CHKERRQ(ierr);
8515   ierr = ISLocalToGlobalMappingApplyIS(pcis->mapping,subset_n,&subset);CHKERRQ(ierr);
8516   ierr = ISDestroy(&subset_n);CHKERRQ(ierr);
8517   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)),pcbddc->local_primal_size_cc,pcbddc->local_primal_ref_mult,PETSC_COPY_VALUES,&subset_mult);CHKERRQ(ierr);
8518   ierr = ISRenumber(subset,subset_mult,&coarse_size,&subset_n);CHKERRQ(ierr);
8519   ierr = ISDestroy(&subset);CHKERRQ(ierr);
8520   ierr = ISDestroy(&subset_mult);CHKERRQ(ierr);
8521   ierr = ISGetLocalSize(subset_n,&local_size);CHKERRQ(ierr);
8522   if (local_size != pcbddc->local_primal_size) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Invalid number of local primal indices computed %D != %D",local_size,pcbddc->local_primal_size);
8523   ierr = PetscMalloc1(local_size,&local_primal_indices);CHKERRQ(ierr);
8524   ierr = ISGetIndices(subset_n,&t_local_primal_indices);CHKERRQ(ierr);
8525   ierr = PetscMemcpy(local_primal_indices,t_local_primal_indices,local_size*sizeof(PetscInt));CHKERRQ(ierr);
8526   ierr = ISRestoreIndices(subset_n,&t_local_primal_indices);CHKERRQ(ierr);
8527   ierr = ISDestroy(&subset_n);CHKERRQ(ierr);
8528 
8529   /* check numbering */
8530   if (pcbddc->dbg_flag) {
8531     PetscScalar coarsesum,*array,*array2;
8532     PetscInt    i;
8533     PetscBool   set_error = PETSC_FALSE,set_error_reduced = PETSC_FALSE;
8534 
8535     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8536     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
8537     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Check coarse indices\n");CHKERRQ(ierr);
8538     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
8539     /* counter */
8540     ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr);
8541     ierr = VecSet(pcis->vec1_N,1.0);CHKERRQ(ierr);
8542     ierr = VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8543     ierr = VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8544     ierr = VecScatterBegin(matis->rctx,pcis->vec1_global,pcis->vec2_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8545     ierr = VecScatterEnd(matis->rctx,pcis->vec1_global,pcis->vec2_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8546     ierr = VecSet(pcis->vec1_N,0.0);CHKERRQ(ierr);
8547     for (i=0;i<pcbddc->local_primal_size;i++) {
8548       ierr = VecSetValue(pcis->vec1_N,pcbddc->primal_indices_local_idxs[i],1.0,INSERT_VALUES);CHKERRQ(ierr);
8549     }
8550     ierr = VecAssemblyBegin(pcis->vec1_N);CHKERRQ(ierr);
8551     ierr = VecAssemblyEnd(pcis->vec1_N);CHKERRQ(ierr);
8552     ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr);
8553     ierr = VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8554     ierr = VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8555     ierr = VecScatterBegin(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8556     ierr = VecScatterEnd(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8557     ierr = VecGetArray(pcis->vec1_N,&array);CHKERRQ(ierr);
8558     ierr = VecGetArray(pcis->vec2_N,&array2);CHKERRQ(ierr);
8559     for (i=0;i<pcis->n;i++) {
8560       if (array[i] != 0.0 && array[i] != array2[i]) {
8561         PetscInt owned = (PetscInt)PetscRealPart(array[i]),gi;
8562         PetscInt neigh = (PetscInt)PetscRealPart(array2[i]);
8563         set_error = PETSC_TRUE;
8564         ierr = ISLocalToGlobalMappingApply(pcis->mapping,1,&i,&gi);CHKERRQ(ierr);
8565         ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d: local index %d (gid %d) owned by %d processes instead of %d!\n",PetscGlobalRank,i,gi,owned,neigh);CHKERRQ(ierr);
8566       }
8567     }
8568     ierr = VecRestoreArray(pcis->vec2_N,&array2);CHKERRQ(ierr);
8569     ierr = MPIU_Allreduce(&set_error,&set_error_reduced,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
8570     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8571     for (i=0;i<pcis->n;i++) {
8572       if (PetscRealPart(array[i]) > 0.0) array[i] = 1.0/PetscRealPart(array[i]);
8573     }
8574     ierr = VecRestoreArray(pcis->vec1_N,&array);CHKERRQ(ierr);
8575     ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr);
8576     ierr = VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8577     ierr = VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8578     ierr = VecSum(pcis->vec1_global,&coarsesum);CHKERRQ(ierr);
8579     ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Size of coarse problem is %d (%lf)\n",coarse_size,PetscRealPart(coarsesum));CHKERRQ(ierr);
8580     if (pcbddc->dbg_flag > 1 || set_error_reduced) {
8581       PetscInt *gidxs;
8582 
8583       ierr = PetscMalloc1(pcbddc->local_primal_size,&gidxs);CHKERRQ(ierr);
8584       ierr = ISLocalToGlobalMappingApply(pcis->mapping,pcbddc->local_primal_size,pcbddc->primal_indices_local_idxs,gidxs);CHKERRQ(ierr);
8585       ierr = PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"Distribution of local primal indices\n");CHKERRQ(ierr);
8586       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8587       ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d\n",PetscGlobalRank);CHKERRQ(ierr);
8588       for (i=0;i<pcbddc->local_primal_size;i++) {
8589         ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"local_primal_indices[%d]=%d (%d,%d)\n",i,local_primal_indices[i],pcbddc->primal_indices_local_idxs[i],gidxs[i]);CHKERRQ(ierr);
8590       }
8591       ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8592       ierr = PetscFree(gidxs);CHKERRQ(ierr);
8593     }
8594     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8595     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
8596     if (set_error_reduced) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"BDDC Numbering of coarse dofs failed");
8597   }
8598   /* ierr = PetscPrintf(PetscObjectComm((PetscObject)pc),"Size of coarse problem is %d\n",coarse_size);CHKERRQ(ierr); */
8599   /* get back data */
8600   *coarse_size_n = coarse_size;
8601   *local_primal_indices_n = local_primal_indices;
8602   PetscFunctionReturn(0);
8603 }
8604 
8605 PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx,Vec gwork, Vec lwork, IS globalis, IS* localis)
8606 {
8607   IS             localis_t;
8608   PetscInt       i,lsize,*idxs,n;
8609   PetscScalar    *vals;
8610   PetscErrorCode ierr;
8611 
8612   PetscFunctionBegin;
8613   /* get indices in local ordering exploiting local to global map */
8614   ierr = ISGetLocalSize(globalis,&lsize);CHKERRQ(ierr);
8615   ierr = PetscMalloc1(lsize,&vals);CHKERRQ(ierr);
8616   for (i=0;i<lsize;i++) vals[i] = 1.0;
8617   ierr = ISGetIndices(globalis,(const PetscInt**)&idxs);CHKERRQ(ierr);
8618   ierr = VecSet(gwork,0.0);CHKERRQ(ierr);
8619   ierr = VecSet(lwork,0.0);CHKERRQ(ierr);
8620   if (idxs) { /* multilevel guard */
8621     ierr = VecSetOption(gwork,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
8622     ierr = VecSetValues(gwork,lsize,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
8623   }
8624   ierr = VecAssemblyBegin(gwork);CHKERRQ(ierr);
8625   ierr = ISRestoreIndices(globalis,(const PetscInt**)&idxs);CHKERRQ(ierr);
8626   ierr = PetscFree(vals);CHKERRQ(ierr);
8627   ierr = VecAssemblyEnd(gwork);CHKERRQ(ierr);
8628   /* now compute set in local ordering */
8629   ierr = VecScatterBegin(g2l_ctx,gwork,lwork,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8630   ierr = VecScatterEnd(g2l_ctx,gwork,lwork,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8631   ierr = VecGetArrayRead(lwork,(const PetscScalar**)&vals);CHKERRQ(ierr);
8632   ierr = VecGetSize(lwork,&n);CHKERRQ(ierr);
8633   for (i=0,lsize=0;i<n;i++) {
8634     if (PetscRealPart(vals[i]) > 0.5) {
8635       lsize++;
8636     }
8637   }
8638   ierr = PetscMalloc1(lsize,&idxs);CHKERRQ(ierr);
8639   for (i=0,lsize=0;i<n;i++) {
8640     if (PetscRealPart(vals[i]) > 0.5) {
8641       idxs[lsize++] = i;
8642     }
8643   }
8644   ierr = VecRestoreArrayRead(lwork,(const PetscScalar**)&vals);CHKERRQ(ierr);
8645   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)gwork),lsize,idxs,PETSC_OWN_POINTER,&localis_t);CHKERRQ(ierr);
8646   *localis = localis_t;
8647   PetscFunctionReturn(0);
8648 }
8649 
8650 PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
8651 {
8652   PC_IS               *pcis=(PC_IS*)pc->data;
8653   PC_BDDC             *pcbddc=(PC_BDDC*)pc->data;
8654   PCBDDCSubSchurs     sub_schurs=pcbddc->sub_schurs;
8655   Mat                 S_j;
8656   PetscInt            *used_xadj,*used_adjncy;
8657   PetscBool           free_used_adj;
8658   PetscErrorCode      ierr;
8659 
8660   PetscFunctionBegin;
8661   ierr = PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
8662   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
8663   free_used_adj = PETSC_FALSE;
8664   if (pcbddc->sub_schurs_layers == -1) {
8665     used_xadj = NULL;
8666     used_adjncy = NULL;
8667   } else {
8668     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
8669       used_xadj = pcbddc->mat_graph->xadj;
8670       used_adjncy = pcbddc->mat_graph->adjncy;
8671     } else if (pcbddc->computed_rowadj) {
8672       used_xadj = pcbddc->mat_graph->xadj;
8673       used_adjncy = pcbddc->mat_graph->adjncy;
8674     } else {
8675       PetscBool      flg_row=PETSC_FALSE;
8676       const PetscInt *xadj,*adjncy;
8677       PetscInt       nvtxs;
8678 
8679       ierr = MatGetRowIJ(pcbddc->local_mat,0,PETSC_TRUE,PETSC_FALSE,&nvtxs,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
8680       if (flg_row) {
8681         ierr = PetscMalloc2(nvtxs+1,&used_xadj,xadj[nvtxs],&used_adjncy);CHKERRQ(ierr);
8682         ierr = PetscMemcpy(used_xadj,xadj,(nvtxs+1)*sizeof(*xadj));CHKERRQ(ierr);
8683         ierr = PetscMemcpy(used_adjncy,adjncy,(xadj[nvtxs])*sizeof(*adjncy));CHKERRQ(ierr);
8684         free_used_adj = PETSC_TRUE;
8685       } else {
8686         pcbddc->sub_schurs_layers = -1;
8687         used_xadj = NULL;
8688         used_adjncy = NULL;
8689       }
8690       ierr = MatRestoreRowIJ(pcbddc->local_mat,0,PETSC_TRUE,PETSC_FALSE,&nvtxs,&xadj,&adjncy,&flg_row);CHKERRQ(ierr);
8691     }
8692   }
8693 
8694   /* setup sub_schurs data */
8695   ierr = MatCreateSchurComplement(pcis->A_II,pcis->A_II,pcis->A_IB,pcis->A_BI,pcis->A_BB,&S_j);CHKERRQ(ierr);
8696   if (!sub_schurs->schur_explicit) {
8697     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
8698     ierr = MatSchurComplementSetKSP(S_j,pcbddc->ksp_D);CHKERRQ(ierr);
8699     ierr = PCBDDCSubSchursSetUp(sub_schurs,NULL,S_j,PETSC_FALSE,used_xadj,used_adjncy,pcbddc->sub_schurs_layers,NULL,pcbddc->adaptive_selection,PETSC_FALSE,PETSC_FALSE,0,NULL,NULL,NULL,NULL);CHKERRQ(ierr);
8700   } else {
8701     Mat       change = NULL;
8702     Vec       scaling = NULL;
8703     IS        change_primal = NULL, iP;
8704     PetscInt  benign_n;
8705     PetscBool reuse_solvers = (PetscBool)!pcbddc->use_change_of_basis;
8706     PetscBool isseqaij,need_change = PETSC_FALSE;
8707     PetscBool discrete_harmonic = PETSC_FALSE;
8708 
8709     if (!pcbddc->use_vertices && reuse_solvers) {
8710       PetscInt n_vertices;
8711 
8712       ierr = ISGetLocalSize(sub_schurs->is_vertices,&n_vertices);CHKERRQ(ierr);
8713       reuse_solvers = (PetscBool)!n_vertices;
8714     }
8715     ierr = PetscObjectTypeCompare((PetscObject)pcbddc->local_mat,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
8716     if (!isseqaij) {
8717       Mat_IS* matis = (Mat_IS*)pc->pmat->data;
8718       if (matis->A == pcbddc->local_mat) {
8719         ierr = MatDestroy(&pcbddc->local_mat);CHKERRQ(ierr);
8720         ierr = MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
8721       } else {
8722         ierr = MatConvert(pcbddc->local_mat,MATSEQAIJ,MAT_INPLACE_MATRIX,&pcbddc->local_mat);CHKERRQ(ierr);
8723       }
8724     }
8725     if (!pcbddc->benign_change_explicit) {
8726       benign_n = pcbddc->benign_n;
8727     } else {
8728       benign_n = 0;
8729     }
8730     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
8731        We need a global reduction to avoid possible deadlocks.
8732        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
8733     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
8734       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
8735       ierr = MPIU_Allreduce(&have_loc_change,&need_change,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
8736       need_change = (PetscBool)(!need_change);
8737     }
8738     /* If the user defines additional constraints, we import them here.
8739        We need to compute the change of basis according to the quadrature weights attached to pmat via MatSetNearNullSpace, and this could not be done (at the moment) without some hacking */
8740     if (need_change) {
8741       PC_IS   *pcisf;
8742       PC_BDDC *pcbddcf;
8743       PC      pcf;
8744 
8745       if (pcbddc->sub_schurs_rebuild) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot compute change of basis with a different graph");
8746       ierr = PCCreate(PetscObjectComm((PetscObject)pc),&pcf);CHKERRQ(ierr);
8747       ierr = PCSetOperators(pcf,pc->mat,pc->pmat);CHKERRQ(ierr);
8748       ierr = PCSetType(pcf,PCBDDC);CHKERRQ(ierr);
8749 
8750       /* hacks */
8751       pcisf                        = (PC_IS*)pcf->data;
8752       pcisf->is_B_local            = pcis->is_B_local;
8753       pcisf->vec1_N                = pcis->vec1_N;
8754       pcisf->BtoNmap               = pcis->BtoNmap;
8755       pcisf->n                     = pcis->n;
8756       pcisf->n_B                   = pcis->n_B;
8757       pcbddcf                      = (PC_BDDC*)pcf->data;
8758       ierr                         = PetscFree(pcbddcf->mat_graph);CHKERRQ(ierr);
8759       pcbddcf->mat_graph           = pcbddc->mat_graph;
8760       pcbddcf->use_faces           = PETSC_TRUE;
8761       pcbddcf->use_change_of_basis = PETSC_TRUE;
8762       pcbddcf->use_change_on_faces = PETSC_TRUE;
8763       pcbddcf->use_qr_single       = PETSC_TRUE;
8764       pcbddcf->fake_change         = PETSC_TRUE;
8765 
8766       /* setup constraints so that we can get information on primal vertices and change of basis (in local numbering) */
8767       ierr = PCBDDCConstraintsSetUp(pcf);CHKERRQ(ierr);
8768       sub_schurs->change_with_qr = pcbddcf->use_qr_single;
8769       ierr = ISCreateGeneral(PETSC_COMM_SELF,pcbddcf->n_vertices,pcbddcf->local_primal_ref_node,PETSC_COPY_VALUES,&change_primal);CHKERRQ(ierr);
8770       change = pcbddcf->ConstraintMatrix;
8771       pcbddcf->ConstraintMatrix = NULL;
8772 
8773       /* free unneeded memory allocated in PCBDDCConstraintsSetUp */
8774       ierr = PetscFree(pcbddcf->sub_schurs);CHKERRQ(ierr);
8775       ierr = MatNullSpaceDestroy(&pcbddcf->onearnullspace);CHKERRQ(ierr);
8776       ierr = PetscFree2(pcbddcf->local_primal_ref_node,pcbddcf->local_primal_ref_mult);CHKERRQ(ierr);
8777       ierr = PetscFree(pcbddcf->primal_indices_local_idxs);CHKERRQ(ierr);
8778       ierr = PetscFree(pcbddcf->onearnullvecs_state);CHKERRQ(ierr);
8779       ierr = PetscFree(pcf->data);CHKERRQ(ierr);
8780       pcf->ops->destroy = NULL;
8781       pcf->ops->reset   = NULL;
8782       ierr = PCDestroy(&pcf);CHKERRQ(ierr);
8783     }
8784     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
8785 
8786     ierr = PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_iP",(PetscObject*)&iP);CHKERRQ(ierr);
8787     if (iP) {
8788       ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)iP),sub_schurs->prefix,"BDDC sub_schurs options","PC");CHKERRQ(ierr);
8789       ierr = PetscOptionsBool("-sub_schurs_discrete_harmonic",NULL,NULL,discrete_harmonic,&discrete_harmonic,NULL);CHKERRQ(ierr);
8790       ierr = PetscOptionsEnd();CHKERRQ(ierr);
8791     }
8792     if (discrete_harmonic) {
8793       Mat A;
8794       ierr = MatDuplicate(pcbddc->local_mat,MAT_COPY_VALUES,&A);CHKERRQ(ierr);
8795       ierr = MatZeroRowsColumnsIS(A,iP,1.0,NULL,NULL);CHKERRQ(ierr);
8796       ierr = PetscObjectCompose((PetscObject)A,"__KSPFETIDP_iP",(PetscObject)iP);CHKERRQ(ierr);
8797       ierr = PCBDDCSubSchursSetUp(sub_schurs,A,S_j,pcbddc->sub_schurs_exact_schur,used_xadj,used_adjncy,pcbddc->sub_schurs_layers,scaling,pcbddc->adaptive_selection,reuse_solvers,pcbddc->benign_saddle_point,benign_n,pcbddc->benign_p0_lidx,pcbddc->benign_zerodiag_subs,change,change_primal);CHKERRQ(ierr);
8798       ierr = MatDestroy(&A);CHKERRQ(ierr);
8799     } else {
8800       ierr = PCBDDCSubSchursSetUp(sub_schurs,pcbddc->local_mat,S_j,pcbddc->sub_schurs_exact_schur,used_xadj,used_adjncy,pcbddc->sub_schurs_layers,scaling,pcbddc->adaptive_selection,reuse_solvers,pcbddc->benign_saddle_point,benign_n,pcbddc->benign_p0_lidx,pcbddc->benign_zerodiag_subs,change,change_primal);CHKERRQ(ierr);
8801     }
8802     ierr = MatDestroy(&change);CHKERRQ(ierr);
8803     ierr = ISDestroy(&change_primal);CHKERRQ(ierr);
8804   }
8805   ierr = MatDestroy(&S_j);CHKERRQ(ierr);
8806 
8807   /* free adjacency */
8808   if (free_used_adj) {
8809     ierr = PetscFree2(used_xadj,used_adjncy);CHKERRQ(ierr);
8810   }
8811   ierr = PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level],pc,0,0,0);CHKERRQ(ierr);
8812   PetscFunctionReturn(0);
8813 }
8814 
8815 PetscErrorCode PCBDDCInitSubSchurs(PC pc)
8816 {
8817   PC_IS               *pcis=(PC_IS*)pc->data;
8818   PC_BDDC             *pcbddc=(PC_BDDC*)pc->data;
8819   PCBDDCGraph         graph;
8820   PetscErrorCode      ierr;
8821 
8822   PetscFunctionBegin;
8823   /* attach interface graph for determining subsets */
8824   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
8825     IS       verticesIS,verticescomm;
8826     PetscInt vsize,*idxs;
8827 
8828     ierr = PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&verticesIS);CHKERRQ(ierr);
8829     ierr = ISGetSize(verticesIS,&vsize);CHKERRQ(ierr);
8830     ierr = ISGetIndices(verticesIS,(const PetscInt**)&idxs);CHKERRQ(ierr);
8831     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),vsize,idxs,PETSC_COPY_VALUES,&verticescomm);CHKERRQ(ierr);
8832     ierr = ISRestoreIndices(verticesIS,(const PetscInt**)&idxs);CHKERRQ(ierr);
8833     ierr = PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&verticesIS);CHKERRQ(ierr);
8834     ierr = PCBDDCGraphCreate(&graph);CHKERRQ(ierr);
8835     ierr = PCBDDCGraphInit(graph,pcbddc->mat_graph->l2gmap,pcbddc->mat_graph->nvtxs_global,pcbddc->graphmaxcount);CHKERRQ(ierr);
8836     ierr = PCBDDCGraphSetUp(graph,pcbddc->mat_graph->custom_minimal_size,NULL,pcbddc->DirichletBoundariesLocal,0,NULL,verticescomm);CHKERRQ(ierr);
8837     ierr = ISDestroy(&verticescomm);CHKERRQ(ierr);
8838     ierr = PCBDDCGraphComputeConnectedComponents(graph);CHKERRQ(ierr);
8839   } else {
8840     graph = pcbddc->mat_graph;
8841   }
8842   /* print some info */
8843   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
8844     IS       vertices;
8845     PetscInt nv,nedges,nfaces;
8846     ierr = PCBDDCGraphASCIIView(graph,pcbddc->dbg_flag,pcbddc->dbg_viewer);CHKERRQ(ierr);
8847     ierr = PCBDDCGraphGetCandidatesIS(graph,&nfaces,NULL,&nedges,NULL,&vertices);CHKERRQ(ierr);
8848     ierr = ISGetSize(vertices,&nv);CHKERRQ(ierr);
8849     ierr = PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
8850     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"--------------------------------------------------------------\n");CHKERRQ(ierr);
8851     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate vertices (%d)\n",PetscGlobalRank,nv,pcbddc->use_vertices);CHKERRQ(ierr);
8852     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate edges    (%d)\n",PetscGlobalRank,nedges,pcbddc->use_edges);CHKERRQ(ierr);
8853     ierr = PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer,"Subdomain %04d got %02d local candidate faces    (%d)\n",PetscGlobalRank,nfaces,pcbddc->use_faces);CHKERRQ(ierr);
8854     ierr = PetscViewerFlush(pcbddc->dbg_viewer);CHKERRQ(ierr);
8855     ierr = PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer);CHKERRQ(ierr);
8856     ierr = PCBDDCGraphRestoreCandidatesIS(graph,&nfaces,NULL,&nedges,NULL,&vertices);CHKERRQ(ierr);
8857   }
8858 
8859   /* sub_schurs init */
8860   if (!pcbddc->sub_schurs) {
8861     ierr = PCBDDCSubSchursCreate(&pcbddc->sub_schurs);CHKERRQ(ierr);
8862   }
8863   ierr = PCBDDCSubSchursInit(pcbddc->sub_schurs,((PetscObject)pc)->prefix,pcis->is_I_local,pcis->is_B_local,graph,pcis->BtoNmap,pcbddc->sub_schurs_rebuild);CHKERRQ(ierr);
8864 
8865   /* free graph struct */
8866   if (pcbddc->sub_schurs_rebuild) {
8867     ierr = PCBDDCGraphDestroy(&graph);CHKERRQ(ierr);
8868   }
8869   PetscFunctionReturn(0);
8870 }
8871 
8872 PetscErrorCode PCBDDCCheckOperator(PC pc)
8873 {
8874   PC_IS               *pcis=(PC_IS*)pc->data;
8875   PC_BDDC             *pcbddc=(PC_BDDC*)pc->data;
8876   PetscErrorCode      ierr;
8877 
8878   PetscFunctionBegin;
8879   if (pcbddc->n_vertices == pcbddc->local_primal_size) {
8880     IS             zerodiag = NULL;
8881     Mat            S_j,B0_B=NULL;
8882     Vec            dummy_vec=NULL,vec_check_B,vec_scale_P;
8883     PetscScalar    *p0_check,*array,*array2;
8884     PetscReal      norm;
8885     PetscInt       i;
8886 
8887     /* B0 and B0_B */
8888     if (zerodiag) {
8889       IS       dummy;
8890 
8891       ierr = ISCreateStride(PETSC_COMM_SELF,pcbddc->benign_n,0,1,&dummy);CHKERRQ(ierr);
8892       ierr = MatCreateSubMatrix(pcbddc->benign_B0,dummy,pcis->is_B_local,MAT_INITIAL_MATRIX,&B0_B);CHKERRQ(ierr);
8893       ierr = MatCreateVecs(B0_B,NULL,&dummy_vec);CHKERRQ(ierr);
8894       ierr = ISDestroy(&dummy);CHKERRQ(ierr);
8895     }
8896     /* I need a primal vector to scale primal nodes since BDDC sums contibutions */
8897     ierr = VecDuplicate(pcbddc->vec1_P,&vec_scale_P);CHKERRQ(ierr);
8898     ierr = VecSet(pcbddc->vec1_P,1.0);CHKERRQ(ierr);
8899     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8900     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8901     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,vec_scale_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8902     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,vec_scale_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8903     ierr = VecReciprocal(vec_scale_P);CHKERRQ(ierr);
8904     /* S_j */
8905     ierr = MatCreateSchurComplement(pcis->A_II,pcis->A_II,pcis->A_IB,pcis->A_BI,pcis->A_BB,&S_j);CHKERRQ(ierr);
8906     ierr = MatSchurComplementSetKSP(S_j,pcbddc->ksp_D);CHKERRQ(ierr);
8907 
8908     /* mimic vector in \widetilde{W}_\Gamma */
8909     ierr = VecSetRandom(pcis->vec1_N,NULL);CHKERRQ(ierr);
8910     /* continuous in primal space */
8911     ierr = VecSetRandom(pcbddc->coarse_vec,NULL);CHKERRQ(ierr);
8912     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,pcbddc->vec1_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8913     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,pcbddc->vec1_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8914     ierr = VecGetArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
8915     ierr = PetscCalloc1(pcbddc->benign_n,&p0_check);CHKERRQ(ierr);
8916     for (i=0;i<pcbddc->benign_n;i++) p0_check[i] = array[pcbddc->local_primal_size-pcbddc->benign_n+i];
8917     ierr = VecSetValues(pcis->vec1_N,pcbddc->local_primal_size,pcbddc->local_primal_ref_node,array,INSERT_VALUES);CHKERRQ(ierr);
8918     ierr = VecRestoreArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
8919     ierr = VecAssemblyBegin(pcis->vec1_N);CHKERRQ(ierr);
8920     ierr = VecAssemblyEnd(pcis->vec1_N);CHKERRQ(ierr);
8921     ierr = VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8922     ierr = VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8923     ierr = VecDuplicate(pcis->vec2_B,&vec_check_B);CHKERRQ(ierr);
8924     ierr = VecCopy(pcis->vec2_B,vec_check_B);CHKERRQ(ierr);
8925 
8926     /* assemble rhs for coarse problem */
8927     /* widetilde{S}_\Gamma w_\Gamma + \widetilde{B0}^T_B p0 */
8928     /* local with Schur */
8929     ierr = MatMult(S_j,pcis->vec2_B,pcis->vec1_B);CHKERRQ(ierr);
8930     if (zerodiag) {
8931       ierr = VecGetArray(dummy_vec,&array);CHKERRQ(ierr);
8932       for (i=0;i<pcbddc->benign_n;i++) array[i] = p0_check[i];
8933       ierr = VecRestoreArray(dummy_vec,&array);CHKERRQ(ierr);
8934       ierr = MatMultTransposeAdd(B0_B,dummy_vec,pcis->vec1_B,pcis->vec1_B);CHKERRQ(ierr);
8935     }
8936     /* sum on primal nodes the local contributions */
8937     ierr = VecScatterBegin(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8938     ierr = VecScatterEnd(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8939     ierr = VecGetArray(pcis->vec1_N,&array);CHKERRQ(ierr);
8940     ierr = VecGetArray(pcbddc->vec1_P,&array2);CHKERRQ(ierr);
8941     for (i=0;i<pcbddc->local_primal_size;i++) array2[i] = array[pcbddc->local_primal_ref_node[i]];
8942     ierr = VecRestoreArray(pcbddc->vec1_P,&array2);CHKERRQ(ierr);
8943     ierr = VecRestoreArray(pcis->vec1_N,&array);CHKERRQ(ierr);
8944     ierr = VecSet(pcbddc->coarse_vec,0.);CHKERRQ(ierr);
8945     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8946     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->vec1_P,pcbddc->coarse_vec,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8947     ierr = VecScatterBegin(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,pcbddc->vec1_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8948     ierr = VecScatterEnd(pcbddc->coarse_loc_to_glob,pcbddc->coarse_vec,pcbddc->vec1_P,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
8949     ierr = VecGetArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
8950     /* scale primal nodes (BDDC sums contibutions) */
8951     ierr = VecPointwiseMult(pcbddc->vec1_P,vec_scale_P,pcbddc->vec1_P);CHKERRQ(ierr);
8952     ierr = VecSetValues(pcis->vec1_N,pcbddc->local_primal_size,pcbddc->local_primal_ref_node,array,INSERT_VALUES);CHKERRQ(ierr);
8953     ierr = VecRestoreArray(pcbddc->vec1_P,&array);CHKERRQ(ierr);
8954     ierr = VecAssemblyBegin(pcis->vec1_N);CHKERRQ(ierr);
8955     ierr = VecAssemblyEnd(pcis->vec1_N);CHKERRQ(ierr);
8956     ierr = VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8957     ierr = VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8958     /* global: \widetilde{B0}_B w_\Gamma */
8959     if (zerodiag) {
8960       ierr = MatMult(B0_B,pcis->vec2_B,dummy_vec);CHKERRQ(ierr);
8961       ierr = VecGetArray(dummy_vec,&array);CHKERRQ(ierr);
8962       for (i=0;i<pcbddc->benign_n;i++) pcbddc->benign_p0[i] = array[i];
8963       ierr = VecRestoreArray(dummy_vec,&array);CHKERRQ(ierr);
8964     }
8965     /* BDDC */
8966     ierr = VecSet(pcis->vec1_D,0.);CHKERRQ(ierr);
8967     ierr = PCBDDCApplyInterfacePreconditioner(pc,PETSC_FALSE);CHKERRQ(ierr);
8968 
8969     ierr = VecCopy(pcis->vec1_B,pcis->vec2_B);CHKERRQ(ierr);
8970     ierr = VecAXPY(pcis->vec1_B,-1.0,vec_check_B);CHKERRQ(ierr);
8971     ierr = VecNorm(pcis->vec1_B,NORM_INFINITY,&norm);CHKERRQ(ierr);
8972     PetscPrintf(PETSC_COMM_SELF,"[%d] BDDC local error is %1.4e\n",PetscGlobalRank,norm);
8973     for (i=0;i<pcbddc->benign_n;i++) {
8974       PetscPrintf(PETSC_COMM_SELF,"[%d] BDDC p0[%d] error is %1.4e\n",PetscGlobalRank,i,PetscAbsScalar(pcbddc->benign_p0[i]-p0_check[i]));
8975     }
8976     ierr = PetscFree(p0_check);CHKERRQ(ierr);
8977     ierr = VecDestroy(&vec_scale_P);CHKERRQ(ierr);
8978     ierr = VecDestroy(&vec_check_B);CHKERRQ(ierr);
8979     ierr = VecDestroy(&dummy_vec);CHKERRQ(ierr);
8980     ierr = MatDestroy(&S_j);CHKERRQ(ierr);
8981     ierr = MatDestroy(&B0_B);CHKERRQ(ierr);
8982   }
8983   PetscFunctionReturn(0);
8984 }
8985 
8986 #include <../src/mat/impls/aij/mpi/mpiaij.h>
8987 PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
8988 {
8989   Mat            At;
8990   IS             rows;
8991   PetscInt       rst,ren;
8992   PetscErrorCode ierr;
8993   PetscLayout    rmap;
8994 
8995   PetscFunctionBegin;
8996   rst = ren = 0;
8997   if (ccomm != MPI_COMM_NULL) {
8998     ierr = PetscLayoutCreate(ccomm,&rmap);CHKERRQ(ierr);
8999     ierr = PetscLayoutSetSize(rmap,A->rmap->N);CHKERRQ(ierr);
9000     ierr = PetscLayoutSetBlockSize(rmap,1);CHKERRQ(ierr);
9001     ierr = PetscLayoutSetUp(rmap);CHKERRQ(ierr);
9002     ierr = PetscLayoutGetRange(rmap,&rst,&ren);CHKERRQ(ierr);
9003   }
9004   ierr = ISCreateStride(PetscObjectComm((PetscObject)A),ren-rst,rst,1,&rows);CHKERRQ(ierr);
9005   ierr = MatCreateSubMatrix(A,rows,NULL,MAT_INITIAL_MATRIX,&At);CHKERRQ(ierr);
9006   ierr = ISDestroy(&rows);CHKERRQ(ierr);
9007 
9008   if (ccomm != MPI_COMM_NULL) {
9009     Mat_MPIAIJ *a,*b;
9010     IS         from,to;
9011     Vec        gvec;
9012     PetscInt   lsize;
9013 
9014     ierr = MatCreate(ccomm,B);CHKERRQ(ierr);
9015     ierr = MatSetSizes(*B,ren-rst,PETSC_DECIDE,PETSC_DECIDE,At->cmap->N);CHKERRQ(ierr);
9016     ierr = MatSetType(*B,MATAIJ);CHKERRQ(ierr);
9017     ierr = PetscLayoutDestroy(&((*B)->rmap));CHKERRQ(ierr);
9018     ierr = PetscLayoutSetUp((*B)->cmap);CHKERRQ(ierr);
9019     a    = (Mat_MPIAIJ*)At->data;
9020     b    = (Mat_MPIAIJ*)(*B)->data;
9021     ierr = MPI_Comm_size(ccomm,&b->size);CHKERRQ(ierr);
9022     ierr = MPI_Comm_rank(ccomm,&b->rank);CHKERRQ(ierr);
9023     ierr = PetscObjectReference((PetscObject)a->A);CHKERRQ(ierr);
9024     ierr = PetscObjectReference((PetscObject)a->B);CHKERRQ(ierr);
9025     b->A = a->A;
9026     b->B = a->B;
9027 
9028     b->donotstash      = a->donotstash;
9029     b->roworiented     = a->roworiented;
9030     b->rowindices      = 0;
9031     b->rowvalues       = 0;
9032     b->getrowactive    = PETSC_FALSE;
9033 
9034     (*B)->rmap         = rmap;
9035     (*B)->factortype   = A->factortype;
9036     (*B)->assembled    = PETSC_TRUE;
9037     (*B)->insertmode   = NOT_SET_VALUES;
9038     (*B)->preallocated = PETSC_TRUE;
9039 
9040     if (a->colmap) {
9041 #if defined(PETSC_USE_CTABLE)
9042       ierr = PetscTableCreateCopy(a->colmap,&b->colmap);CHKERRQ(ierr);
9043 #else
9044       ierr = PetscMalloc1(At->cmap->N,&b->colmap);CHKERRQ(ierr);
9045       ierr = PetscLogObjectMemory((PetscObject)*B,At->cmap->N*sizeof(PetscInt));CHKERRQ(ierr);
9046       ierr = PetscMemcpy(b->colmap,a->colmap,At->cmap->N*sizeof(PetscInt));CHKERRQ(ierr);
9047 #endif
9048     } else b->colmap = 0;
9049     if (a->garray) {
9050       PetscInt len;
9051       len  = a->B->cmap->n;
9052       ierr = PetscMalloc1(len+1,&b->garray);CHKERRQ(ierr);
9053       ierr = PetscLogObjectMemory((PetscObject)(*B),len*sizeof(PetscInt));CHKERRQ(ierr);
9054       if (len) { ierr = PetscMemcpy(b->garray,a->garray,len*sizeof(PetscInt));CHKERRQ(ierr); }
9055     } else b->garray = 0;
9056 
9057     ierr    = PetscObjectReference((PetscObject)a->lvec);CHKERRQ(ierr);
9058     b->lvec = a->lvec;
9059     ierr    = PetscLogObjectParent((PetscObject)*B,(PetscObject)b->lvec);CHKERRQ(ierr);
9060 
9061     /* cannot use VecScatterCopy */
9062     ierr = VecGetLocalSize(b->lvec,&lsize);CHKERRQ(ierr);
9063     ierr = ISCreateGeneral(ccomm,lsize,b->garray,PETSC_USE_POINTER,&from);CHKERRQ(ierr);
9064     ierr = ISCreateStride(PETSC_COMM_SELF,lsize,0,1,&to);CHKERRQ(ierr);
9065     ierr = MatCreateVecs(*B,&gvec,NULL);CHKERRQ(ierr);
9066     ierr = VecScatterCreate(gvec,from,b->lvec,to,&b->Mvctx);CHKERRQ(ierr);
9067     ierr = PetscLogObjectParent((PetscObject)*B,(PetscObject)b->Mvctx);CHKERRQ(ierr);
9068     ierr = ISDestroy(&from);CHKERRQ(ierr);
9069     ierr = ISDestroy(&to);CHKERRQ(ierr);
9070     ierr = VecDestroy(&gvec);CHKERRQ(ierr);
9071   }
9072   ierr = MatDestroy(&At);CHKERRQ(ierr);
9073   PetscFunctionReturn(0);
9074 }
9075