xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
11cf9b237SStefano Zampini #include <../src/mat/impls/aij/seq/aij.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
4837cedc9SStefano Zampini #include <../src/mat/impls/dense/seq/dense.h>
5c80a6c00SStefano Zampini #include <petscdmplex.h>
6674ae819SStefano Zampini #include <petscblaslapack.h>
7daf8a457SStefano Zampini #include <petsc/private/sfimpl.h>
8c80a6c00SStefano Zampini #include <petsc/private/dmpleximpl.h>
97620a527SStefano Zampini #include <petscdmda.h>
10674ae819SStefano Zampini 
111e0482f5SStefano Zampini static PetscErrorCode MatMPIAIJRestrict(Mat, MPI_Comm, Mat *);
121e0482f5SStefano Zampini 
13f498cd09SStefano Zampini /* if range is true,  it returns B s.t. span{B} = range(A)
14f498cd09SStefano Zampini    if range is false, it returns B s.t. range(B) _|_ range(A) */
15ba38deedSJacob Faibussowitsch static PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B)
16d71ae5a4SJacob Faibussowitsch {
17a13144ffSStefano Zampini   PetscScalar *uwork, *data, *U, ds = 0.;
18a13144ffSStefano Zampini   PetscReal   *sing;
19a13144ffSStefano Zampini   PetscBLASInt bM, bN, lwork, lierr, di = 1;
20a13144ffSStefano Zampini   PetscInt     ulw, i, nr, nc, n;
21abee2b68SSebastian Grimberg #if defined(PETSC_USE_COMPLEX)
22abee2b68SSebastian Grimberg   PetscReal *rwork2;
23abee2b68SSebastian Grimberg #endif
24a13144ffSStefano Zampini 
25a13144ffSStefano Zampini   PetscFunctionBegin;
269566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
273ba16761SJacob Faibussowitsch   if (!nr || !nc) PetscFunctionReturn(PETSC_SUCCESS);
28a13144ffSStefano Zampini 
29a13144ffSStefano Zampini   /* workspace */
30a13144ffSStefano Zampini   if (!work) {
31a13144ffSStefano Zampini     ulw = PetscMax(PetscMax(1, 5 * PetscMin(nr, nc)), 3 * PetscMin(nr, nc) + PetscMax(nr, nc));
329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ulw, &uwork));
33a13144ffSStefano Zampini   } else {
34a13144ffSStefano Zampini     ulw   = lw;
35a13144ffSStefano Zampini     uwork = work;
36a13144ffSStefano Zampini   }
37a13144ffSStefano Zampini   n = PetscMin(nr, nc);
38a13144ffSStefano Zampini   if (!rwork) {
399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &sing));
40a13144ffSStefano Zampini   } else {
41a13144ffSStefano Zampini     sing = rwork;
42a13144ffSStefano Zampini   }
43a13144ffSStefano Zampini 
44a13144ffSStefano Zampini   /* SVD */
459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nr, &U));
469566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nr, &bM));
479566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nc, &bN));
489566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(ulw, &lwork));
499566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(A, &data));
509566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
51abee2b68SSebastian Grimberg #if !defined(PETSC_USE_COMPLEX)
52792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, &lierr));
53abee2b68SSebastian Grimberg #else
549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(5 * n, &rwork2));
55792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, rwork2, &lierr));
569566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork2));
57abee2b68SSebastian Grimberg #endif
589566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPop());
5928b400f6SJacob Faibussowitsch   PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
609566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(A, &data));
619371c9d4SSatish Balay   for (i = 0; i < n; i++)
629371c9d4SSatish Balay     if (sing[i] < PETSC_SMALL) break;
6348a46eb9SPierre Jolivet   if (!rwork) PetscCall(PetscFree(sing));
6448a46eb9SPierre Jolivet   if (!work) PetscCall(PetscFree(uwork));
65a13144ffSStefano Zampini   /* create B */
66f498cd09SStefano Zampini   if (!range) {
679566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, nr - i, NULL, B));
689566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
699566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U + nr * i, (nr - i) * nr));
70f498cd09SStefano Zampini   } else {
719566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, i, NULL, B));
729566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
739566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U, i * nr));
74f498cd09SStefano Zampini   }
759566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(*B, &data));
769566063dSJacob Faibussowitsch   PetscCall(PetscFree(U));
773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
78a13144ffSStefano Zampini }
79a13144ffSStefano Zampini 
801e0482f5SStefano Zampini /* TODO REMOVE */
811e0482f5SStefano Zampini #if defined(PRINT_GDET)
821e0482f5SStefano Zampini static int inc = 0;
831e0482f5SStefano Zampini static int lev = 0;
841e0482f5SStefano Zampini #endif
851e0482f5SStefano Zampini 
86ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCComputeNedelecChangeEdge(Mat lG, IS edge, IS extrow, IS extcol, IS corners, Mat *Gins, Mat *GKins, PetscScalar cvals[2], PetscScalar *work, PetscReal *rwork)
87d71ae5a4SJacob Faibussowitsch {
88a13144ffSStefano Zampini   Mat          GE, GEd;
89a13144ffSStefano Zampini   PetscInt     rsize, csize, esize;
90a13144ffSStefano Zampini   PetscScalar *ptr;
91a13144ffSStefano Zampini 
92a13144ffSStefano Zampini   PetscFunctionBegin;
939566063dSJacob Faibussowitsch   PetscCall(ISGetSize(edge, &esize));
943ba16761SJacob Faibussowitsch   if (!esize) PetscFunctionReturn(PETSC_SUCCESS);
959566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extrow, &rsize));
969566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extcol, &csize));
97a13144ffSStefano Zampini 
98a13144ffSStefano Zampini   /* gradients */
99a13144ffSStefano Zampini   ptr = work + 5 * esize;
1009566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, extrow, extcol, MAT_INITIAL_MATRIX, &GE));
1019566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, rsize, csize, ptr, Gins));
1029566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, Gins));
1039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
104a13144ffSStefano Zampini 
105a13144ffSStefano Zampini   /* constants */
106a13144ffSStefano Zampini   ptr += rsize * csize;
1079566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, esize, csize, ptr, &GEd));
1089566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, edge, extcol, MAT_INITIAL_MATRIX, &GE));
1099566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, &GEd));
1109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
1119566063dSJacob Faibussowitsch   PetscCall(MatDenseOrthogonalRangeOrComplement(GEd, PETSC_FALSE, 5 * esize, work, rwork, GKins));
1129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GEd));
1131e0482f5SStefano Zampini 
1141e0482f5SStefano Zampini   if (corners) {
1151e0482f5SStefano Zampini     Mat                GEc;
1161683a169SBarry Smith     const PetscScalar *vals;
1171683a169SBarry Smith     PetscScalar        v;
1181e0482f5SStefano Zampini 
1199566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(lG, edge, corners, MAT_INITIAL_MATRIX, &GEc));
1209566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(GEc, *GKins, MAT_INITIAL_MATRIX, 1.0, &GEd));
1219566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(GEd, &vals));
122a8f51744SPierre Jolivet     /* v       = PetscAbsScalar(vals[0]); */
123637e8532SStefano Zampini     v        = 1.;
1241e0482f5SStefano Zampini     cvals[0] = vals[0] / v;
1251e0482f5SStefano Zampini     cvals[1] = vals[1] / v;
1269566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(GEd, &vals));
1279566063dSJacob Faibussowitsch     PetscCall(MatScale(*GKins, 1. / v));
1281e0482f5SStefano Zampini #if defined(PRINT_GDET)
1291e0482f5SStefano Zampini     {
1301e0482f5SStefano Zampini       PetscViewer viewer;
1311e0482f5SStefano Zampini       char        filename[256];
132a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "Gdet_l%d_r%d_cc%d.m", lev, PetscGlobalRank, inc++));
1339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &viewer));
1349566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
1359566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEc, "GEc"));
1369566063dSJacob Faibussowitsch       PetscCall(MatView(GEc, viewer));
137*f4f49eeaSPierre Jolivet       PetscCall(PetscObjectSetName((PetscObject)*GKins, "GK"));
1389566063dSJacob Faibussowitsch       PetscCall(MatView(*GKins, viewer));
1399566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEd, "Gproj"));
1409566063dSJacob Faibussowitsch       PetscCall(MatView(GEd, viewer));
1419566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
1421e0482f5SStefano Zampini     }
1431e0482f5SStefano Zampini #endif
1449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEd));
1459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEc));
1461e0482f5SStefano Zampini   }
1473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
148a13144ffSStefano Zampini }
149a13144ffSStefano Zampini 
150d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNedelecSupport(PC pc)
151d71ae5a4SJacob Faibussowitsch {
152a13144ffSStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
153a13144ffSStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
1540569b399SStefano Zampini   Mat                    G, T, conn, lG, lGt, lGis, lGall, lGe, lGinit;
155eee23b56SStefano Zampini   Vec                    tvec;
156a13144ffSStefano Zampini   PetscSF                sfv;
1571e0482f5SStefano Zampini   ISLocalToGlobalMapping el2g, vl2g, fl2g, al2g;
158a13144ffSStefano Zampini   MPI_Comm               comm;
159c2151214SStefano Zampini   IS                     lned, primals, allprimals, nedfieldlocal;
160c2151214SStefano Zampini   IS                    *eedges, *extrows, *extcols, *alleedges;
1617d871cd7SStefano Zampini   PetscBT                btv, bte, btvc, btb, btbd, btvcand, btvi, btee, bter;
162a13144ffSStefano Zampini   PetscScalar           *vals, *work;
163a13144ffSStefano Zampini   PetscReal             *rwork;
164a13144ffSStefano Zampini   const PetscInt        *idxs, *ii, *jj, *iit, *jjt;
1651e0482f5SStefano Zampini   PetscInt               ne, nv, Lv, order, n, field;
166a13144ffSStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
167eee23b56SStefano Zampini   PetscInt               i, j, extmem, cum, maxsize, nee;
168b03ebc13SStefano Zampini   PetscInt              *extrow, *extrowcum, *marks, *vmarks, *gidxs;
169a13144ffSStefano Zampini   PetscInt              *sfvleaves, *sfvroots;
170b03ebc13SStefano Zampini   PetscInt              *corners, *cedges;
171637e8532SStefano Zampini   PetscInt              *ecount, **eneighs, *vcount, **vneighs;
172b03ebc13SStefano Zampini   PetscInt              *emarks;
173213b8bfaSStefano Zampini   PetscBool              print, eerr, done, lrc[2], conforming, global, singular, setprimal;
174a13144ffSStefano Zampini 
175a13144ffSStefano Zampini   PetscFunctionBegin;
176213b8bfaSStefano Zampini   /* If the discrete gradient is defined for a subset of dofs and global is true,
177213b8bfaSStefano Zampini      it assumes G is given in global ordering for all the dofs.
178213b8bfaSStefano Zampini      Otherwise, the ordering is global for the Nedelec field */
179213b8bfaSStefano Zampini   order      = pcbddc->nedorder;
180213b8bfaSStefano Zampini   conforming = pcbddc->conforming;
181213b8bfaSStefano Zampini   field      = pcbddc->nedfield;
182213b8bfaSStefano Zampini   global     = pcbddc->nedglobal;
183213b8bfaSStefano Zampini   setprimal  = PETSC_FALSE;
184a13144ffSStefano Zampini   print      = PETSC_FALSE;
185213b8bfaSStefano Zampini   singular   = PETSC_FALSE;
186a13144ffSStefano Zampini 
187213b8bfaSStefano Zampini   /* Command line customization */
188d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC Nedelec options", "PC");
1899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_field_primal", "All edge dofs set as primals: Toselli's algorithm C", NULL, setprimal, &setprimal, NULL));
1909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_singular", "Infer nullspace from discrete gradient", NULL, singular, &singular, NULL));
1919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bddc_nedelec_order", "Test variable order code (to be removed)", NULL, order, &order, NULL));
192213b8bfaSStefano Zampini   /* print debug info TODO: to be removed */
1939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_print", "Print debug info", NULL, print, &print, NULL));
194d0609cedSBarry Smith   PetscOptionsEnd();
195213b8bfaSStefano Zampini 
196213b8bfaSStefano Zampini   /* Return if there are no edges in the decomposition and the problem is not singular */
1979566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &al2g, NULL));
1989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(al2g, &n));
1999566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
200213b8bfaSStefano Zampini   if (!singular) {
2019566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
202a13144ffSStefano Zampini     lrc[0] = PETSC_FALSE;
203c2151214SStefano Zampini     for (i = 0; i < n; i++) {
204a13144ffSStefano Zampini       if (PetscRealPart(vals[i]) > 2.) {
205a13144ffSStefano Zampini         lrc[0] = PETSC_TRUE;
206a13144ffSStefano Zampini         break;
207a13144ffSStefano Zampini       }
208a13144ffSStefano Zampini     }
2099566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2101c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lrc[0], &lrc[1], 1, MPIU_BOOL, MPI_LOR, comm));
2113ba16761SJacob Faibussowitsch     if (!lrc[1]) PetscFunctionReturn(PETSC_SUCCESS);
212213b8bfaSStefano Zampini   }
213a13144ffSStefano Zampini 
214213b8bfaSStefano Zampini   /* Get Nedelec field */
21563a3b9bcSJacob Faibussowitsch   PetscCheck(!pcbddc->n_ISForDofsLocal || field < pcbddc->n_ISForDofsLocal, comm, PETSC_ERR_USER, "Invalid field for Nedelec %" PetscInt_FMT ": number of fields is %" PetscInt_FMT, field, pcbddc->n_ISForDofsLocal);
216213b8bfaSStefano Zampini   if (pcbddc->n_ISForDofsLocal && field >= 0) {
2179566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofsLocal[field]));
218c2151214SStefano Zampini     nedfieldlocal = pcbddc->ISForDofsLocal[field];
2199566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nedfieldlocal, &ne));
220213b8bfaSStefano Zampini   } else if (!pcbddc->n_ISForDofsLocal && field != PETSC_DECIDE) {
221213b8bfaSStefano Zampini     ne            = n;
222213b8bfaSStefano Zampini     nedfieldlocal = NULL;
223213b8bfaSStefano Zampini     global        = PETSC_TRUE;
224213b8bfaSStefano Zampini   } else if (field == PETSC_DECIDE) {
225213b8bfaSStefano Zampini     PetscInt rst, ren, *idx;
226213b8bfaSStefano Zampini 
2279566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_leafdata, n));
2289566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
2299566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(pcbddc->discretegradient, &rst, &ren));
230213b8bfaSStefano Zampini     for (i = rst; i < ren; i++) {
231213b8bfaSStefano Zampini       PetscInt nc;
232213b8bfaSStefano Zampini 
2339566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
234213b8bfaSStefano Zampini       if (nc > 1) matis->sf_rootdata[i - rst] = 1;
2359566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
236213b8bfaSStefano Zampini     }
2379566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2389566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &idx));
2409371c9d4SSatish Balay     for (i = 0, ne = 0; i < n; i++)
2419371c9d4SSatish Balay       if (matis->sf_leafdata[i]) idx[ne++] = i;
2429566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, ne, idx, PETSC_OWN_POINTER, &nedfieldlocal));
243213b8bfaSStefano Zampini   } else {
244213b8bfaSStefano Zampini     SETERRQ(comm, PETSC_ERR_USER, "When multiple fields are present, the Nedelec field has to be specified");
245213b8bfaSStefano Zampini   }
246213b8bfaSStefano Zampini 
247213b8bfaSStefano Zampini   /* Sanity checks */
2487827d75bSBarry Smith   PetscCheck(order || conforming, comm, PETSC_ERR_SUP, "Variable order and non-conforming spaces are not supported at the same time");
24928b400f6SJacob Faibussowitsch   PetscCheck(!pcbddc->user_ChangeOfBasisMatrix, comm, PETSC_ERR_SUP, "Cannot generate Nedelec support with user defined change of basis");
25063a3b9bcSJacob Faibussowitsch   PetscCheck(!order || (ne % order == 0), PETSC_COMM_SELF, PETSC_ERR_USER, "The number of local edge dofs %" PetscInt_FMT " is not a multiple of the order %" PetscInt_FMT, ne, order);
251213b8bfaSStefano Zampini 
252213b8bfaSStefano Zampini   /* Just set primal dofs and return */
2531e0482f5SStefano Zampini   if (setprimal) {
254eee23b56SStefano Zampini     IS        enedfieldlocal;
255eee23b56SStefano Zampini     PetscInt *eidxs;
256eee23b56SStefano Zampini 
2579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &eidxs));
2589566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
259213b8bfaSStefano Zampini     if (nedfieldlocal) {
2609566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
261eee23b56SStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
262ad540459SPierre Jolivet         if (PetscRealPart(vals[idxs[i]]) > 2.) eidxs[cum++] = idxs[i];
263eee23b56SStefano Zampini       }
2649566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
265213b8bfaSStefano Zampini     } else {
266213b8bfaSStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
267ad540459SPierre Jolivet         if (PetscRealPart(vals[i]) > 2.) eidxs[cum++] = i;
268213b8bfaSStefano Zampini       }
269213b8bfaSStefano Zampini     }
2709566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2719566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, eidxs, PETSC_COPY_VALUES, &enedfieldlocal));
2729566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, enedfieldlocal));
2739566063dSJacob Faibussowitsch     PetscCall(PetscFree(eidxs));
2749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nedfieldlocal));
2759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&enedfieldlocal));
2763ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2771e0482f5SStefano Zampini   }
278a13144ffSStefano Zampini 
279213b8bfaSStefano Zampini   /* Compute some l2g maps */
280213b8bfaSStefano Zampini   if (nedfieldlocal) {
281c2151214SStefano Zampini     IS is;
282c2151214SStefano Zampini 
283c2151214SStefano Zampini     /* need to map from the local Nedelec field to local numbering */
2849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(nedfieldlocal, &fl2g));
2851e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering for the whole dofs*/
2869566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(al2g, nedfieldlocal, &is));
2879566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &al2g));
2881e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering (for Nedelec only) */
2891e0482f5SStefano Zampini     if (global) {
2909566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)al2g));
2911e0482f5SStefano Zampini       el2g = al2g;
2921e0482f5SStefano Zampini     } else {
2931e0482f5SStefano Zampini       IS gis;
2941e0482f5SStefano Zampini 
2959566063dSJacob Faibussowitsch       PetscCall(ISRenumber(is, NULL, NULL, &gis));
2969566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(gis, &el2g));
2979566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&gis));
2981e0482f5SStefano Zampini     }
2999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
300c2151214SStefano Zampini   } else {
3011e0482f5SStefano Zampini     /* restore default */
3021e0482f5SStefano Zampini     pcbddc->nedfield = -1;
3031e0482f5SStefano Zampini     /* one ref for the destruction of al2g, one for el2g */
3049566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3061e0482f5SStefano Zampini     el2g = al2g;
307c2151214SStefano Zampini     fl2g = NULL;
308c2151214SStefano Zampini   }
309a13144ffSStefano Zampini 
310213b8bfaSStefano Zampini   /* Start communication to drop connections for interior edges (for cc analysis only) */
3119566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
3129566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
313c2151214SStefano Zampini   if (nedfieldlocal) {
3149566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
315c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[idxs[i]] = 1;
3169566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
317c2151214SStefano Zampini   } else {
318c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[i] = 1;
319c2151214SStefano Zampini   }
3209566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
3219566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
322213b8bfaSStefano Zampini 
323213b8bfaSStefano Zampini   if (!singular) { /* drop connections with interior edges to avoid unneeded communications and memory movements */
3249566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(pcbddc->discretegradient, MAT_COPY_VALUES, &G));
3259566063dSJacob Faibussowitsch     PetscCall(MatSetOption(G, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3261e0482f5SStefano Zampini     if (global) {
3271e0482f5SStefano Zampini       PetscInt rst;
3281e0482f5SStefano Zampini 
3299566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(G, &rst, NULL));
330c2151214SStefano Zampini       for (i = 0, cum = 0; i < pc->pmat->rmap->n; i++) {
331ad540459SPierre Jolivet         if (matis->sf_rootdata[i] < 2) matis->sf_rootdata[cum++] = i + rst;
332c2151214SStefano Zampini       }
3339566063dSJacob Faibussowitsch       PetscCall(MatSetOption(G, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE));
3349566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, matis->sf_rootdata, 0., NULL, NULL));
3351e0482f5SStefano Zampini     } else {
3361e0482f5SStefano Zampini       PetscInt *tbz;
3371e0482f5SStefano Zampini 
3389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ne, &tbz));
3399566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3409566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
3421e0482f5SStefano Zampini       for (i = 0, cum = 0; i < ne; i++)
3439371c9d4SSatish Balay         if (matis->sf_leafdata[idxs[i]] == 1) tbz[cum++] = i;
3449566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
3459566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(el2g, cum, tbz, tbz));
3469566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, tbz, 0., NULL, NULL));
3479566063dSJacob Faibussowitsch       PetscCall(PetscFree(tbz));
3481e0482f5SStefano Zampini     }
349213b8bfaSStefano Zampini   } else { /* we need the entire G to infer the nullspace */
3509566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->discretegradient));
351213b8bfaSStefano Zampini     G = pcbddc->discretegradient;
352213b8bfaSStefano Zampini   }
353a13144ffSStefano Zampini 
354a13144ffSStefano Zampini   /* Extract subdomain relevant rows of G */
3559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(el2g, &idxs));
3569566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, ne, idxs, PETSC_USE_POINTER, &lned));
3579566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(G, lned, NULL, MAT_INITIAL_MATRIX, &lGall));
3589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(el2g, &idxs));
3599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&lned));
3609566063dSJacob Faibussowitsch   PetscCall(MatConvert(lGall, MATIS, MAT_INITIAL_MATRIX, &lGis));
3619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGall));
3629566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(lGis, &lG));
363a13144ffSStefano Zampini 
364213b8bfaSStefano Zampini   /* SF for nodal dofs communications */
3659566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(G, NULL, &Lv));
3669566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(lGis, NULL, &vl2g));
3679566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)vl2g));
3689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(vl2g, &nv));
3699566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sfv));
3709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(vl2g, &idxs));
3719566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sfv, lGis->cmap, nv, NULL, PETSC_OWN_POINTER, idxs));
3729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(vl2g, &idxs));
373213b8bfaSStefano Zampini   i = singular ? 2 : 1;
3749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i * nv, &sfvleaves, i * Lv, &sfvroots));
375a13144ffSStefano Zampini 
3761e0482f5SStefano Zampini   /* Destroy temporary G created in MATIS format and modified G */
3779566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)lG));
3789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGis));
3799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&G));
380a13144ffSStefano Zampini 
381213b8bfaSStefano Zampini   if (print) {
3829566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "initial_lG"));
3839566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
384213b8bfaSStefano Zampini   }
385213b8bfaSStefano Zampini 
386213b8bfaSStefano Zampini   /* Save lG for values insertion in change of basis */
3879566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGinit));
3880569b399SStefano Zampini 
389a13144ffSStefano Zampini   /* Analyze the edge-nodes connections (duplicate lG) */
3909566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGe));
3919566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGe, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3929566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btv));
3939566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &bte));
3949566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btb));
3959566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btbd));
3969566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvcand));
397a13144ffSStefano Zampini   /* need to import the boundary specification to ensure the
398a13144ffSStefano Zampini      proper detection of coarse edges' endpoints */
399a13144ffSStefano Zampini   if (pcbddc->DirichletBoundariesLocal) {
400c2151214SStefano Zampini     IS is;
401c2151214SStefano Zampini 
402c2151214SStefano Zampini     if (fl2g) {
4039566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->DirichletBoundariesLocal, &is));
404c2151214SStefano Zampini     } else {
405c2151214SStefano Zampini       is = pcbddc->DirichletBoundariesLocal;
406c2151214SStefano Zampini     }
4079566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4089566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
409a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
410a13144ffSStefano Zampini       if (idxs[i] >= 0) {
4119566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btb, idxs[i]));
4129566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btbd, idxs[i]));
413a13144ffSStefano Zampini       }
414a13144ffSStefano Zampini     }
4159566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
41648a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
417a13144ffSStefano Zampini   }
418a13144ffSStefano Zampini   if (pcbddc->NeumannBoundariesLocal) {
419c2151214SStefano Zampini     IS is;
420c2151214SStefano Zampini 
421c2151214SStefano Zampini     if (fl2g) {
4229566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->NeumannBoundariesLocal, &is));
423c2151214SStefano Zampini     } else {
424c2151214SStefano Zampini       is = pcbddc->NeumannBoundariesLocal;
425c2151214SStefano Zampini     }
4269566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
428a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
42948a46eb9SPierre Jolivet       if (idxs[i] >= 0) PetscCall(PetscBTSet(btb, idxs[i]));
430a13144ffSStefano Zampini     }
4319566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
43248a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
433c2151214SStefano Zampini   }
434c2151214SStefano Zampini 
435213b8bfaSStefano Zampini   /* Count neighs per dof */
4369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, &ecount, &eneighs));
4379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, &vcount, &vneighs));
438637e8532SStefano Zampini 
4397d871cd7SStefano Zampini   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
4407d871cd7SStefano Zampini      for proper detection of coarse edges' endpoints */
4419566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btee));
44262b0c6f7SStefano Zampini   for (i = 0; i < ne; i++) {
44348a46eb9SPierre Jolivet     if ((ecount[i] > 2 && !PetscBTLookup(btbd, i)) || (ecount[i] == 2 && PetscBTLookup(btb, i))) PetscCall(PetscBTSet(btee, i));
44462b0c6f7SStefano Zampini   }
4459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ne, &marks));
44662b0c6f7SStefano Zampini   if (!conforming) {
4479566063dSJacob Faibussowitsch     PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
4489566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
44962b0c6f7SStefano Zampini   }
4509566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
4519566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGe, &vals));
45262b0c6f7SStefano Zampini   cum = 0;
453a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
454dec27d64SStefano Zampini     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
45562b0c6f7SStefano Zampini     if (!PetscBTLookup(btee, i)) {
456a13144ffSStefano Zampini       marks[cum++] = i;
457dec27d64SStefano Zampini       continue;
458dec27d64SStefano Zampini     }
459dec27d64SStefano Zampini     /* set badly connected edge dofs as primal */
46062b0c6f7SStefano Zampini     if (!conforming) {
46162b0c6f7SStefano Zampini       if (ii[i + 1] - ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
462a13144ffSStefano Zampini         marks[cum++] = i;
4639566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(bte, i));
46448a46eb9SPierre Jolivet         for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
46562b0c6f7SStefano Zampini       } else {
466aaa8cc7dSPierre Jolivet         /* every edge dofs should be connected through a certain number of nodal dofs
46762b0c6f7SStefano Zampini            to other edge dofs belonging to coarse edges
46862b0c6f7SStefano Zampini            - at most 2 endpoints
46962b0c6f7SStefano Zampini            - order-1 interior nodal dofs
47062b0c6f7SStefano Zampini            - no undefined nodal dofs (nconn < order)
47162b0c6f7SStefano Zampini         */
47262b0c6f7SStefano Zampini         PetscInt ends = 0, ints = 0, undef = 0;
47362b0c6f7SStefano Zampini         for (j = ii[i]; j < ii[i + 1]; j++) {
47462b0c6f7SStefano Zampini           PetscInt v     = jj[j], k;
47562b0c6f7SStefano Zampini           PetscInt nconn = iit[v + 1] - iit[v];
4769371c9d4SSatish Balay           for (k = iit[v]; k < iit[v + 1]; k++)
4779371c9d4SSatish Balay             if (!PetscBTLookup(btee, jjt[k])) nconn--;
47862b0c6f7SStefano Zampini           if (nconn > order) ends++;
47962b0c6f7SStefano Zampini           else if (nconn == order) ints++;
48062b0c6f7SStefano Zampini           else undef++;
48162b0c6f7SStefano Zampini         }
48262b0c6f7SStefano Zampini         if (undef || ends > 2 || ints != order - 1) {
48362b0c6f7SStefano Zampini           marks[cum++] = i;
4849566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(bte, i));
48548a46eb9SPierre Jolivet           for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
48662b0c6f7SStefano Zampini         }
48762b0c6f7SStefano Zampini       }
488a13144ffSStefano Zampini     }
489dec27d64SStefano Zampini     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
490dec27d64SStefano Zampini     if (!order && ii[i + 1] != ii[i]) {
491dec27d64SStefano Zampini       PetscScalar val = 1. / (ii[i + 1] - ii[i] - 1);
492dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vals[j] = val;
493a13144ffSStefano Zampini     }
494dec27d64SStefano Zampini   }
4959566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btee));
4969566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGe, &vals));
4979566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
49862b0c6f7SStefano Zampini   if (!conforming) {
4999566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
5009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lGt));
50162b0c6f7SStefano Zampini   }
5029566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGe, cum, marks, 0., NULL, NULL));
503637e8532SStefano Zampini 
504b03ebc13SStefano Zampini   /* identify splitpoints and corner candidates */
5059566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
506a13144ffSStefano Zampini   if (print) {
5079566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGe, "edgerestr_lG"));
5089566063dSJacob Faibussowitsch     PetscCall(MatView(lGe, NULL));
5099566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "edgerestr_lGt"));
5109566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
511a13144ffSStefano Zampini   }
5129566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5139566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGt, &vals));
514a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
515637e8532SStefano Zampini     PetscInt  ord = order, test = ii[i + 1] - ii[i], vc = vcount[i];
5167d871cd7SStefano Zampini     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
517b03ebc13SStefano Zampini     if (!order) { /* variable order */
518dec27d64SStefano Zampini       PetscReal vorder = 0.;
519dec27d64SStefano Zampini 
520dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vorder += PetscRealPart(vals[j]);
521dec27d64SStefano Zampini       test = PetscFloorReal(vorder + 10. * PETSC_SQRT_MACHINE_EPSILON);
52263a3b9bcSJacob Faibussowitsch       PetscCheck(vorder - test <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected value for vorder: %g (%" PetscInt_FMT ")", (double)vorder, test);
523dec27d64SStefano Zampini       ord = 1;
524dec27d64SStefano Zampini     }
5256bdcaf15SBarry Smith     PetscAssert(test % ord == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of edge dofs %" PetscInt_FMT " connected with nodal dof %" PetscInt_FMT " with order %" PetscInt_FMT, test, i, ord);
526637e8532SStefano Zampini     for (j = ii[i]; j < ii[i + 1] && sneighs; j++) {
5277d871cd7SStefano Zampini       if (PetscBTLookup(btbd, jj[j])) {
5287d871cd7SStefano Zampini         bdir = PETSC_TRUE;
5297d871cd7SStefano Zampini         break;
5307d871cd7SStefano Zampini       }
531637e8532SStefano Zampini       if (vc != ecount[jj[j]]) {
532637e8532SStefano Zampini         sneighs = PETSC_FALSE;
533637e8532SStefano Zampini       } else {
534637e8532SStefano Zampini         PetscInt k, *vn = vneighs[i], *en = eneighs[jj[j]];
535637e8532SStefano Zampini         for (k = 0; k < vc; k++) {
536637e8532SStefano Zampini           if (vn[k] != en[k]) {
537637e8532SStefano Zampini             sneighs = PETSC_FALSE;
538637e8532SStefano Zampini             break;
539637e8532SStefano Zampini           }
540637e8532SStefano Zampini         }
541637e8532SStefano Zampini       }
542637e8532SStefano Zampini     }
5437d871cd7SStefano Zampini     if (!sneighs || test >= 3 * ord || bdir) { /* splitpoints */
5443ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "SPLITPOINT %" PetscInt_FMT " (%s %s %s)\n", i, PetscBools[!sneighs], PetscBools[test >= 3 * ord], PetscBools[bdir]));
5459566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
546dec27d64SStefano Zampini     } else if (test == ord) {
547b03ebc13SStefano Zampini       if (order == 1 || (!order && ii[i + 1] - ii[i] == 1)) {
5483ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINT %" PetscInt_FMT "\n", i));
5499566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btv, i));
550a13144ffSStefano Zampini       } else {
5513ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "CORNER CANDIDATE %" PetscInt_FMT "\n", i));
5529566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btvcand, i));
553a13144ffSStefano Zampini       }
554a13144ffSStefano Zampini     }
555a13144ffSStefano Zampini   }
5569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(el2g, NULL, &ecount, &eneighs));
5579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(vl2g, NULL, &vcount, &vneighs));
5589566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btbd));
559b03ebc13SStefano Zampini 
560b03ebc13SStefano Zampini   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
561b03ebc13SStefano Zampini   if (order != 1) {
5623ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "INSPECTING CANDIDATES\n"));
5639566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
564b03ebc13SStefano Zampini     for (i = 0; i < nv; i++) {
565b03ebc13SStefano Zampini       if (PetscBTLookup(btvcand, i)) {
566b03ebc13SStefano Zampini         PetscBool found = PETSC_FALSE;
567b03ebc13SStefano Zampini         for (j = ii[i]; j < ii[i + 1] && !found; j++) {
568b03ebc13SStefano Zampini           PetscInt k, e = jj[j];
569b03ebc13SStefano Zampini           if (PetscBTLookup(bte, e)) continue;
570b03ebc13SStefano Zampini           for (k = iit[e]; k < iit[e + 1]; k++) {
571b03ebc13SStefano Zampini             PetscInt v = jjt[k];
572b03ebc13SStefano Zampini             if (v != i && PetscBTLookup(btvcand, v)) {
573b03ebc13SStefano Zampini               found = PETSC_TRUE;
574b03ebc13SStefano Zampini               break;
575b03ebc13SStefano Zampini             }
576b03ebc13SStefano Zampini           }
577b03ebc13SStefano Zampini         }
578b03ebc13SStefano Zampini         if (!found) {
5793ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " CLEARED\n", i));
5809566063dSJacob Faibussowitsch           PetscCall(PetscBTClear(btvcand, i));
581b03ebc13SStefano Zampini         } else {
5823ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " ACCEPTED\n", i));
583b03ebc13SStefano Zampini         }
584b03ebc13SStefano Zampini       }
585b03ebc13SStefano Zampini     }
5869566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
587b03ebc13SStefano Zampini   }
5889566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGt, &vals));
5899566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5909566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGe));
591a13144ffSStefano Zampini 
592a13144ffSStefano Zampini   /* Get the local G^T explicitly */
5939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
5949566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
5959566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGt, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
596a13144ffSStefano Zampini 
5974e64d54eSstefano_zampini   /* Mark interior nodal dofs */
5989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
5999566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvi));
600a13144ffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
60148a46eb9SPierre Jolivet     for (j = 0; j < n_shared[i]; j++) PetscCall(PetscBTSet(btvi, shared[i][j]));
602a13144ffSStefano Zampini   }
6039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
604a13144ffSStefano Zampini 
605a13144ffSStefano Zampini   /* communicate corners and splitpoints */
6069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nv, &vmarks));
6079566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvleaves, nv));
6089566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvroots, Lv));
6099371c9d4SSatish Balay   for (i = 0; i < nv; i++)
6109371c9d4SSatish Balay     if (PetscUnlikely(PetscBTLookup(btv, i))) sfvleaves[i] = 1;
611a13144ffSStefano Zampini 
612a13144ffSStefano Zampini   if (print) {
613a13144ffSStefano Zampini     IS tbz;
614a13144ffSStefano Zampini 
615a13144ffSStefano Zampini     cum = 0;
616a13144ffSStefano Zampini     for (i = 0; i < nv; i++)
6179371c9d4SSatish Balay       if (sfvleaves[i]) vmarks[cum++] = i;
618a13144ffSStefano Zampini 
6199566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6209566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_local"));
6219566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6229566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
623a13144ffSStefano Zampini   }
624a13144ffSStefano Zampini 
6259566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6269566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6279566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
6289566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
629a13144ffSStefano Zampini 
6304e64d54eSstefano_zampini   /* Zero rows of lGt corresponding to identified corners
6314e64d54eSstefano_zampini      and interior nodal dofs */
632a13144ffSStefano Zampini   cum = 0;
633a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
634a13144ffSStefano Zampini     if (sfvleaves[i]) {
635a13144ffSStefano Zampini       vmarks[cum++] = i;
6369566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
637a13144ffSStefano Zampini     }
6384e64d54eSstefano_zampini     if (!PetscBTLookup(btvi, i)) vmarks[cum++] = i;
639a13144ffSStefano Zampini   }
6409566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvi));
641a13144ffSStefano Zampini   if (print) {
642a13144ffSStefano Zampini     IS tbz;
643a13144ffSStefano Zampini 
6449566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6459566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_with_interior"));
6469566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
648a13144ffSStefano Zampini   }
6499566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGt, cum, vmarks, 0., NULL, NULL));
6509566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmarks));
6519566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfv));
6529566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sfvleaves, sfvroots));
653a13144ffSStefano Zampini 
654a13144ffSStefano Zampini   /* Recompute G */
6559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
6569566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGt, MAT_INITIAL_MATRIX, &lG));
657a13144ffSStefano Zampini   if (print) {
6589566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "used_lG"));
6599566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
6609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "used_lGt"));
6619566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
662a13144ffSStefano Zampini   }
663a13144ffSStefano Zampini 
664a13144ffSStefano Zampini   /* Get primal dofs (if any) */
665a13144ffSStefano Zampini   cum = 0;
666a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
667a13144ffSStefano Zampini     if (PetscUnlikely(PetscBTLookup(bte, i))) marks[cum++] = i;
668a13144ffSStefano Zampini   }
6691baa6e33SBarry Smith   if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, marks, marks));
6709566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, cum, marks, PETSC_COPY_VALUES, &primals));
671a13144ffSStefano Zampini   if (print) {
6729566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "prescribed_primal_dofs"));
6739566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
674a13144ffSStefano Zampini   }
6759566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bte));
676c2151214SStefano Zampini   /* TODO: what if the user passed in some of them ?  */
6779566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
6789566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&primals));
679a13144ffSStefano Zampini 
680a13144ffSStefano Zampini   /* Compute edge connectivity */
6819566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lG, "econn_"));
6824222ddf1SHong Zhang 
6834222ddf1SHong Zhang   /* Symbolic conn = lG*lGt */
6849566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(lG, lGt, NULL, &conn));
6859566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(conn, MATPRODUCT_AB));
6869566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(conn, "default"));
6879566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(conn, PETSC_DEFAULT));
6889566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)conn, "econn_"));
6899566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(conn));
6909566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(conn));
6914222ddf1SHong Zhang 
6929566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
693c2151214SStefano Zampini   if (fl2g) {
694c2151214SStefano Zampini     PetscBT   btf;
695c2151214SStefano Zampini     PetscInt *iia, *jja, *iiu, *jju;
696c2151214SStefano Zampini     PetscBool rest = PETSC_FALSE, free = PETSC_FALSE;
697c2151214SStefano Zampini 
698c2151214SStefano Zampini     /* create CSR for all local dofs */
6999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &iia));
700c2151214SStefano Zampini     if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
70163a3b9bcSJacob Faibussowitsch       PetscCheck(pcbddc->mat_graph->nvtxs_csr == n, PETSC_COMM_SELF, PETSC_ERR_USER, "Invalid size of CSR graph %" PetscInt_FMT ". Should be %" PetscInt_FMT, pcbddc->mat_graph->nvtxs_csr, n);
702c2151214SStefano Zampini       iiu = pcbddc->mat_graph->xadj;
703c2151214SStefano Zampini       jju = pcbddc->mat_graph->adjncy;
704c2151214SStefano Zampini     } else if (pcbddc->use_local_adj) {
705c2151214SStefano Zampini       rest = PETSC_TRUE;
7069566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
707c2151214SStefano Zampini     } else {
708c2151214SStefano Zampini       free = PETSC_TRUE;
7099566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n + 1, &iiu, n, &jju));
710c2151214SStefano Zampini       iiu[0] = 0;
711c2151214SStefano Zampini       for (i = 0; i < n; i++) {
712c2151214SStefano Zampini         iiu[i + 1] = i + 1;
713c2151214SStefano Zampini         jju[i]     = -1;
714d904f53bSStefano Zampini       }
715c2151214SStefano Zampini     }
716c2151214SStefano Zampini 
717c2151214SStefano Zampini     /* import sizes of CSR */
718c2151214SStefano Zampini     iia[0] = 0;
719c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] = iiu[i + 1] - iiu[i];
720c2151214SStefano Zampini 
721c2151214SStefano Zampini     /* overwrite entries corresponding to the Nedelec field */
7229566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(n, &btf));
7239566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
724c2151214SStefano Zampini     for (i = 0; i < ne; i++) {
7259566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btf, idxs[i]));
726c2151214SStefano Zampini       iia[idxs[i] + 1] = ii[i + 1] - ii[i];
727c2151214SStefano Zampini     }
728c2151214SStefano Zampini 
729c2151214SStefano Zampini     /* iia in CSR */
730c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] += iia[i];
731c2151214SStefano Zampini 
732c2151214SStefano Zampini     /* jja in CSR */
7339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(iia[n], &jja));
734c2151214SStefano Zampini     for (i = 0; i < n; i++)
735c2151214SStefano Zampini       if (!PetscBTLookup(btf, i))
7369371c9d4SSatish Balay         for (j = 0; j < iiu[i + 1] - iiu[i]; j++) jja[iia[i] + j] = jju[iiu[i] + j];
737c2151214SStefano Zampini 
738c2151214SStefano Zampini     /* map edge dofs connectivity */
7391e0482f5SStefano Zampini     if (jj) {
7409566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, ii[ne], jj, (PetscInt *)jj));
741c2151214SStefano Zampini       for (i = 0; i < ne; i++) {
742c2151214SStefano Zampini         PetscInt e = idxs[i];
743c2151214SStefano Zampini         for (j = 0; j < ii[i + 1] - ii[i]; j++) jja[iia[e] + j] = jj[ii[i] + j];
744c2151214SStefano Zampini       }
7451e0482f5SStefano Zampini     }
7469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
7479566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, iia, jja, PETSC_OWN_POINTER));
74848a46eb9SPierre Jolivet     if (rest) PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
7491baa6e33SBarry Smith     if (free) PetscCall(PetscFree2(iiu, jju));
7509566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&btf));
751c2151214SStefano Zampini   } else {
7529566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, ii, jj, PETSC_USE_POINTER));
753c2151214SStefano Zampini   }
754c2151214SStefano Zampini 
755a13144ffSStefano Zampini   /* Analyze interface for edge dofs */
7569566063dSJacob Faibussowitsch   PetscCall(PCBDDCAnalyzeInterface(pc));
757213b8bfaSStefano Zampini   pcbddc->mat_graph->twodim = PETSC_FALSE;
758a13144ffSStefano Zampini 
759a13144ffSStefano Zampini   /* Get coarse edges in the edge space */
7609566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
7619566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
762a13144ffSStefano Zampini 
763c2151214SStefano Zampini   if (fl2g) {
7649566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
7659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee, &eedges));
76648a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
767c2151214SStefano Zampini   } else {
768c2151214SStefano Zampini     eedges  = alleedges;
769c2151214SStefano Zampini     primals = allprimals;
770c2151214SStefano Zampini   }
771c2151214SStefano Zampini 
772a13144ffSStefano Zampini   /* Mark fine edge dofs with their coarse edge id */
7739566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(marks, ne));
7749566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
7759566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
776c2151214SStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = nee + 1;
7779566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
778c2151214SStefano Zampini   if (print) {
7799566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs"));
7809566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
781c2151214SStefano Zampini   }
782c2151214SStefano Zampini 
783c2151214SStefano Zampini   maxsize = 0;
784a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
785a13144ffSStefano Zampini     PetscInt size, mark = i + 1;
786a13144ffSStefano Zampini 
7879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
7889566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
789a13144ffSStefano Zampini     for (j = 0; j < size; j++) marks[idxs[j]] = mark;
7909566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
791a13144ffSStefano Zampini     maxsize = PetscMax(maxsize, size);
792a13144ffSStefano Zampini   }
793a13144ffSStefano Zampini 
794a13144ffSStefano Zampini   /* Find coarse edge endpoints */
7959566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
7969566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
797a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
798a13144ffSStefano Zampini     PetscInt mark = i + 1, size;
799a13144ffSStefano Zampini 
8009566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
8011e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
80263a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8039566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
804a13144ffSStefano Zampini     if (print) {
80563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINTS ANALYSIS EDGE %" PetscInt_FMT "\n", i));
8069566063dSJacob Faibussowitsch       PetscCall(ISView(eedges[i], NULL));
807a13144ffSStefano Zampini     }
808a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
809a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
8103ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  idx %" PetscInt_FMT "\n", ee));
811a13144ffSStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
8123ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    inspect %" PetscInt_FMT "\n", jj[k]));
813a13144ffSStefano Zampini         if (PetscBTLookup(btv, jj[k])) {
8143ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      corner found (already set) %" PetscInt_FMT "\n", jj[k]));
815a13144ffSStefano Zampini         } else if (PetscBTLookup(btvcand, jj[k])) { /* is it ok? */
816a13144ffSStefano Zampini           PetscInt  k2;
817a13144ffSStefano Zampini           PetscBool corner = PETSC_FALSE;
818a13144ffSStefano Zampini           for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) {
8193ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        INSPECTING %" PetscInt_FMT ": mark %" PetscInt_FMT " (ref mark %" PetscInt_FMT "), boundary %d\n", jjt[k2], marks[jjt[k2]], mark, (int)!!PetscBTLookup(btb, jjt[k2])));
820c2151214SStefano Zampini             /* it's a corner if either is connected with an edge dof belonging to a different cc or
821c2151214SStefano Zampini                if the edge dof lie on the natural part of the boundary */
822c2151214SStefano Zampini             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb, jjt[k2]))) {
823a13144ffSStefano Zampini               corner = PETSC_TRUE;
824a13144ffSStefano Zampini               break;
825a13144ffSStefano Zampini             }
826a13144ffSStefano Zampini           }
827a13144ffSStefano Zampini           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
8283ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        corner found %" PetscInt_FMT "\n", jj[k]));
8299566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
830a13144ffSStefano Zampini           } else {
8313ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        no corners found\n"));
832a13144ffSStefano Zampini           }
833a13144ffSStefano Zampini         }
834a13144ffSStefano Zampini       }
835a13144ffSStefano Zampini     }
8369566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
837a13144ffSStefano Zampini   }
8389566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
8399566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8409566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btb));
841a13144ffSStefano Zampini 
842a13144ffSStefano Zampini   /* Reset marked primal dofs */
8439566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
8449566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
845a13144ffSStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = 0;
8469566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
847a13144ffSStefano Zampini 
8480569b399SStefano Zampini   /* Now use the initial lG */
8499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
8509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
8510569b399SStefano Zampini   lG = lGinit;
8529566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
8530569b399SStefano Zampini 
854a13144ffSStefano Zampini   /* Compute extended cols indices */
8559566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvc));
8569566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nee, &bter));
8579566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8589566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lG, &i));
859a13144ffSStefano Zampini   i *= maxsize;
8609566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extcols));
8619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i, &extrow, i, &gidxs));
862a13144ffSStefano Zampini   eerr = PETSC_FALSE;
863a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
864b03ebc13SStefano Zampini     PetscInt size, found = 0;
865a13144ffSStefano Zampini 
866a13144ffSStefano Zampini     cum = 0;
8679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
8681e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
86963a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8709566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
8719566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
872a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
873a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
874b03ebc13SStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
875b03ebc13SStefano Zampini         PetscInt vv = jj[k];
876b03ebc13SStefano Zampini         if (!PetscBTLookup(btv, vv)) extrow[cum++] = vv;
877b03ebc13SStefano Zampini         else if (!PetscBTLookupSet(btvc, vv)) found++;
878b03ebc13SStefano Zampini       }
879a13144ffSStefano Zampini     }
8809566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
8819566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
8829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
8839566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
8849566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
885a13144ffSStefano Zampini     /* it may happen that endpoints are not defined at this point
886a13144ffSStefano Zampini        if it is the case, mark this edge for a second pass */
887b03ebc13SStefano Zampini     if (cum != size - 1 || found != 2) {
8889566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(bter, i));
889a13144ffSStefano Zampini       if (print) {
8909566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge"));
8919566063dSJacob Faibussowitsch         PetscCall(ISView(eedges[i], NULL));
8929566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol"));
8939566063dSJacob Faibussowitsch         PetscCall(ISView(extcols[i], NULL));
894a13144ffSStefano Zampini       }
895a13144ffSStefano Zampini       eerr = PETSC_TRUE;
896a13144ffSStefano Zampini     }
897a13144ffSStefano Zampini   }
89828b400f6SJacob Faibussowitsch   /* PetscCheck(!eerr,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
8991c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&eerr, &done, 1, MPIU_BOOL, MPI_LOR, comm));
900a13144ffSStefano Zampini   if (done) {
901a13144ffSStefano Zampini     PetscInt *newprimals;
902a13144ffSStefano Zampini 
9039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &newprimals));
9049566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(primals, &cum));
9059566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(primals, &idxs));
9069566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(newprimals, idxs, cum));
9079566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(primals, &idxs));
9089566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9093ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOING SECOND PASS (eerr %s)\n", PetscBools[eerr]));
910a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
911b03ebc13SStefano Zampini       PetscBool has_candidates = PETSC_FALSE;
912b03ebc13SStefano Zampini       if (PetscBTLookup(bter, i)) {
913a13144ffSStefano Zampini         PetscInt size, mark = i + 1;
914a13144ffSStefano Zampini 
9159566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(eedges[i], &size));
9169566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(eedges[i], &idxs));
917c2151214SStefano Zampini         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
918a13144ffSStefano Zampini         for (j = 0; j < size; j++) {
919a13144ffSStefano Zampini           PetscInt k, ee = idxs[j];
9203ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Inspecting edge dof %" PetscInt_FMT " [%" PetscInt_FMT " %" PetscInt_FMT ")\n", ee, ii[ee], ii[ee + 1]));
921a13144ffSStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
922a13144ffSStefano Zampini             /* set all candidates located on the edge as corners */
923a13144ffSStefano Zampini             if (PetscBTLookup(btvcand, jj[k])) {
924a13144ffSStefano Zampini               PetscInt k2, vv = jj[k];
925b03ebc13SStefano Zampini               has_candidates = PETSC_TRUE;
9263ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Candidate set to vertex %" PetscInt_FMT "\n", vv));
9279566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(btv, vv));
928a13144ffSStefano Zampini               /* set all edge dofs connected to candidate as primals */
929a13144ffSStefano Zampini               for (k2 = iit[vv]; k2 < iit[vv + 1]; k2++) {
930a13144ffSStefano Zampini                 if (marks[jjt[k2]] == mark) {
931a13144ffSStefano Zampini                   PetscInt k3, ee2 = jjt[k2];
9323ba16761SJacob Faibussowitsch                   if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Connected edge dof set to primal %" PetscInt_FMT "\n", ee2));
933a13144ffSStefano Zampini                   newprimals[cum++] = ee2;
934a13144ffSStefano Zampini                   /* finally set the new corners */
935a13144ffSStefano Zampini                   for (k3 = ii[ee2]; k3 < ii[ee2 + 1]; k3++) {
9363ba16761SJacob Faibussowitsch                     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Connected nodal dof set to vertex %" PetscInt_FMT "\n", jj[k3]));
9379566063dSJacob Faibussowitsch                     PetscCall(PetscBTSet(btv, jj[k3]));
938a13144ffSStefano Zampini                   }
939a13144ffSStefano Zampini                 }
940a13144ffSStefano Zampini               }
941b03ebc13SStefano Zampini             } else {
9423ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Not a candidate vertex %" PetscInt_FMT "\n", jj[k]));
943a13144ffSStefano Zampini             }
944a13144ffSStefano Zampini           }
945a13144ffSStefano Zampini         }
946b03ebc13SStefano Zampini         if (!has_candidates) { /* circular edge */
947b03ebc13SStefano Zampini           PetscInt k, ee = idxs[0], *tmarks;
948b03ebc13SStefano Zampini 
9499566063dSJacob Faibussowitsch           PetscCall(PetscCalloc1(ne, &tmarks));
9503ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Circular edge %" PetscInt_FMT "\n", i));
951b03ebc13SStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
952b03ebc13SStefano Zampini             PetscInt k2;
9533ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Set to corner %" PetscInt_FMT "\n", jj[k]));
9549566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
955b03ebc13SStefano Zampini             for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) tmarks[jjt[k2]]++;
956b03ebc13SStefano Zampini           }
957b03ebc13SStefano Zampini           for (j = 0; j < size; j++) {
958b03ebc13SStefano Zampini             if (tmarks[idxs[j]] > 1) {
9593ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge dof set to primal %" PetscInt_FMT "\n", idxs[j]));
960b03ebc13SStefano Zampini               newprimals[cum++] = idxs[j];
961b03ebc13SStefano Zampini             }
962b03ebc13SStefano Zampini           }
9639566063dSJacob Faibussowitsch           PetscCall(PetscFree(tmarks));
964b03ebc13SStefano Zampini         }
9659566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(eedges[i], &idxs));
966a13144ffSStefano Zampini       }
9679566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&extcols[i]));
968a13144ffSStefano Zampini     }
9699566063dSJacob Faibussowitsch     PetscCall(PetscFree(extcols));
9709566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9719566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, newprimals));
972c2151214SStefano Zampini     if (fl2g) {
9739566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, newprimals, newprimals));
9749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&primals));
97548a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
9769566063dSJacob Faibussowitsch       PetscCall(PetscFree(eedges));
977c2151214SStefano Zampini     }
9789566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
9799566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, newprimals, PETSC_COPY_VALUES, &primals));
9809566063dSJacob Faibussowitsch     PetscCall(PetscFree(newprimals));
9819566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
9829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
9839566063dSJacob Faibussowitsch     PetscCall(PCBDDCAnalyzeInterface(pc));
984213b8bfaSStefano Zampini     pcbddc->mat_graph->twodim = PETSC_FALSE;
9859566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
986c2151214SStefano Zampini     if (fl2g) {
9879566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
9889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nee, &eedges));
98948a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
990c2151214SStefano Zampini     } else {
991c2151214SStefano Zampini       eedges  = alleedges;
992c2151214SStefano Zampini       primals = allprimals;
993c2151214SStefano Zampini     }
9949566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nee, &extcols));
995a13144ffSStefano Zampini 
996a13144ffSStefano Zampini     /* Mark again */
9979566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(marks, ne));
998a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
999a13144ffSStefano Zampini       PetscInt size, mark = i + 1;
1000a13144ffSStefano Zampini 
10019566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10029566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1003a13144ffSStefano Zampini       for (j = 0; j < size; j++) marks[idxs[j]] = mark;
10049566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1005a13144ffSStefano Zampini     }
1006a13144ffSStefano Zampini     if (print) {
10079566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs_secondpass"));
10089566063dSJacob Faibussowitsch       PetscCall(ISView(primals, NULL));
1009a13144ffSStefano Zampini     }
1010a13144ffSStefano Zampini 
1011a13144ffSStefano Zampini     /* Recompute extended cols */
1012a13144ffSStefano Zampini     eerr = PETSC_FALSE;
1013a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1014a13144ffSStefano Zampini       PetscInt size;
1015a13144ffSStefano Zampini 
1016a13144ffSStefano Zampini       cum = 0;
10179566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10181e0482f5SStefano Zampini       if (!size && nedfieldlocal) continue;
101963a3b9bcSJacob Faibussowitsch       PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10209566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1021a13144ffSStefano Zampini       for (j = 0; j < size; j++) {
1022a13144ffSStefano Zampini         PetscInt k, ee = idxs[j];
10239371c9d4SSatish Balay         for (k = ii[ee]; k < ii[ee + 1]; k++)
10249371c9d4SSatish Balay           if (!PetscBTLookup(btv, jj[k])) extrow[cum++] = jj[k];
1025a13144ffSStefano Zampini       }
10269566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
10279566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
10289566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
10299566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
10309566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1031a13144ffSStefano Zampini       if (cum != size - 1) {
1032a13144ffSStefano Zampini         if (print) {
10339566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge_secondpass"));
10349566063dSJacob Faibussowitsch           PetscCall(ISView(eedges[i], NULL));
10359566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol_secondpass"));
10369566063dSJacob Faibussowitsch           PetscCall(ISView(extcols[i], NULL));
1037a13144ffSStefano Zampini         }
1038a13144ffSStefano Zampini         eerr = PETSC_TRUE;
1039a13144ffSStefano Zampini       }
1040a13144ffSStefano Zampini     }
1041a13144ffSStefano Zampini   }
10429566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10439566063dSJacob Faibussowitsch   PetscCall(PetscFree2(extrow, gidxs));
10449566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bter));
10459566063dSJacob Faibussowitsch   if (print) PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, 5, PETSC_VIEWER_STDOUT_SELF));
1046a13144ffSStefano Zampini   /* an error should not occur at this point */
104728b400f6SJacob Faibussowitsch   PetscCheck(!eerr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1048a13144ffSStefano Zampini 
10494e64d54eSstefano_zampini   /* Check the number of endpoints */
10509566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * nee, &corners));
10529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &cedges));
10534e64d54eSstefano_zampini   for (i = 0; i < nee; i++) {
1054b03ebc13SStefano Zampini     PetscInt size, found = 0, gc[2];
10554e64d54eSstefano_zampini 
1056b03ebc13SStefano Zampini     /* init with defaults */
1057b03ebc13SStefano Zampini     cedges[i] = corners[i * 2] = corners[i * 2 + 1] = -1;
10589566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
10591e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
106063a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
10629566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
10634e64d54eSstefano_zampini     for (j = 0; j < size; j++) {
10644e64d54eSstefano_zampini       PetscInt k, ee = idxs[j];
10654e64d54eSstefano_zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
10664e64d54eSstefano_zampini         PetscInt vv = jj[k];
10674e64d54eSstefano_zampini         if (PetscBTLookup(btv, vv) && !PetscBTLookupSet(btvc, vv)) {
1068467446fbSPierre Jolivet           PetscCheck(found != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more than two corners for edge %" PetscInt_FMT, i);
1069b03ebc13SStefano Zampini           corners[i * 2 + found++] = vv;
10704e64d54eSstefano_zampini         }
10714e64d54eSstefano_zampini       }
10724e64d54eSstefano_zampini     }
1073b03ebc13SStefano Zampini     if (found != 2) {
1074b03ebc13SStefano Zampini       PetscInt e;
1075b03ebc13SStefano Zampini       if (fl2g) {
10769566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, 1, idxs, &e));
1077b03ebc13SStefano Zampini       } else {
1078b03ebc13SStefano Zampini         e = idxs[0];
1079b03ebc13SStefano Zampini       }
108063a3b9bcSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found %" PetscInt_FMT " corners for edge %" PetscInt_FMT " (astart %" PetscInt_FMT ", estart %" PetscInt_FMT ")", found, i, e, idxs[0]);
1081b03ebc13SStefano Zampini     }
1082eee23b56SStefano Zampini 
1083eee23b56SStefano Zampini     /* get primal dof index on this coarse edge */
10849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, 2, corners + 2 * i, gc));
1085b03ebc13SStefano Zampini     if (gc[0] > gc[1]) {
1086b03ebc13SStefano Zampini       PetscInt swap      = corners[2 * i];
1087b03ebc13SStefano Zampini       corners[2 * i]     = corners[2 * i + 1];
1088b03ebc13SStefano Zampini       corners[2 * i + 1] = swap;
1089b03ebc13SStefano Zampini     }
1090eee23b56SStefano Zampini     cedges[i] = idxs[size - 1];
10919566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
10923ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "EDGE %" PetscInt_FMT ": ce %" PetscInt_FMT ", corners (%" PetscInt_FMT ",%" PetscInt_FMT ")\n", i, cedges[i], corners[2 * i], corners[2 * i + 1]));
10934e64d54eSstefano_zampini   }
10949566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10959566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvc));
10964e64d54eSstefano_zampini 
109776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
1098a13144ffSStefano Zampini     /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1099a13144ffSStefano Zampini      not interfere with neighbouring coarse edges */
11009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee + 1, &emarks));
11019566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
1102a13144ffSStefano Zampini     for (i = 0; i < nv; i++) {
1103a13144ffSStefano Zampini       PetscInt emax = 0, eemax = 0;
1104a13144ffSStefano Zampini 
1105a13144ffSStefano Zampini       if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
11069566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(emarks, nee + 1));
1107a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) emarks[marks[jj[j]]]++;
1108a13144ffSStefano Zampini       for (j = 1; j < nee + 1; j++) {
1109a13144ffSStefano Zampini         if (emax < emarks[j]) {
1110a13144ffSStefano Zampini           emax  = emarks[j];
1111a13144ffSStefano Zampini           eemax = j;
1112a13144ffSStefano Zampini         }
1113a13144ffSStefano Zampini       }
1114a13144ffSStefano Zampini       /* not relevant for edges */
1115a13144ffSStefano Zampini       if (!eemax) continue;
1116a13144ffSStefano Zampini 
1117a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
11187a46b595SBarry Smith         PetscCheck(!marks[jj[j]] || marks[jj[j]] == eemax, PETSC_COMM_SELF, PETSC_ERR_SUP, "Found 2 coarse edges (id %" PetscInt_FMT " and %" PetscInt_FMT ") connected through the %" PetscInt_FMT " nodal dof at edge dof %" PetscInt_FMT, marks[jj[j]] - 1, eemax, i, jj[j]);
1119a13144ffSStefano Zampini       }
1120a13144ffSStefano Zampini     }
11219566063dSJacob Faibussowitsch     PetscCall(PetscFree(emarks));
11229566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
112376bd3646SJed Brown   }
1124a13144ffSStefano Zampini 
1125a13144ffSStefano Zampini   /* Compute extended rows indices for edge blocks of the change of basis */
11269566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11279566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lGt, &extmem));
1128a13144ffSStefano Zampini   extmem *= maxsize;
11299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(extmem * nee, &extrow));
11309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &extrows));
11319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extrowcum));
1132a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
1133a13144ffSStefano Zampini     PetscInt mark = 0, size, start;
1134213b8bfaSStefano Zampini 
1135a13144ffSStefano Zampini     if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
1136a13144ffSStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++)
11379371c9d4SSatish Balay       if (marks[jj[j]] && !mark) mark = marks[jj[j]];
1138a13144ffSStefano Zampini 
1139a13144ffSStefano Zampini     /* not relevant */
1140a13144ffSStefano Zampini     if (!mark) continue;
1141a13144ffSStefano Zampini 
1142a13144ffSStefano Zampini     /* import extended row */
1143a13144ffSStefano Zampini     mark--;
1144a13144ffSStefano Zampini     start = mark * extmem + extrowcum[mark];
1145a13144ffSStefano Zampini     size  = ii[i + 1] - ii[i];
114663a3b9bcSJacob Faibussowitsch     PetscCheck(extrowcum[mark] + size <= extmem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not enough memory allocated %" PetscInt_FMT " > %" PetscInt_FMT, extrowcum[mark] + size, extmem);
11479566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(extrow + start, jj + ii[i], size));
1148a13144ffSStefano Zampini     extrowcum[mark] += size;
1149a13144ffSStefano Zampini   }
11509566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
11529566063dSJacob Faibussowitsch   PetscCall(PetscFree(marks));
1153213b8bfaSStefano Zampini 
1154213b8bfaSStefano Zampini   /* Compress extrows */
1155a13144ffSStefano Zampini   cum = 0;
1156a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1157a13144ffSStefano Zampini     PetscInt size = extrowcum[i], *start = extrow + i * extmem;
11589566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&size, start));
11599566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, start, PETSC_USE_POINTER, &extrows[i]));
1160a13144ffSStefano Zampini     cum = PetscMax(cum, size);
1161a13144ffSStefano Zampini   }
11629566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrowcum));
11639566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btv));
11649566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvcand));
1165a13144ffSStefano Zampini 
1166a13144ffSStefano Zampini   /* Workspace for lapack inner calls and VecSetValues */
11679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2((5 + cum + maxsize) * maxsize, &work, maxsize, &rwork));
1168a13144ffSStefano Zampini 
1169a13144ffSStefano Zampini   /* Create change of basis matrix (preallocation can be improved) */
11709566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
1171d0609cedSBarry Smith   PetscCall(MatSetSizes(T, pc->pmat->rmap->n, pc->pmat->rmap->n, pc->pmat->rmap->N, pc->pmat->rmap->N));
11729566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
11739566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(T, 10, NULL));
11749566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(T, 10, NULL, 10, NULL));
11759566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
11769566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
11779566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
11789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1179a13144ffSStefano Zampini 
1180a13144ffSStefano Zampini   /* Defaults to identity */
11819566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &tvec, NULL));
11829566063dSJacob Faibussowitsch   PetscCall(VecSet(tvec, 1.0));
11839566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(T, tvec, INSERT_VALUES));
11849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&tvec));
1185a13144ffSStefano Zampini 
11861e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
11879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
11889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
11891e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
11901e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
11911e0482f5SStefano Zampini     IS                     wis, gwis;
11921e0482f5SStefano Zampini     PetscInt               cnv, cne;
11931e0482f5SStefano Zampini 
11949566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
11951e0482f5SStefano Zampini     if (fl2g) {
11969566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
11971e0482f5SStefano Zampini     } else {
11989566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
11991e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
12001e0482f5SStefano Zampini     }
12019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
12029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12039566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
12049566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
12059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12071e0482f5SStefano Zampini 
12089566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
12099566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
12109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12119566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
12129566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
12139566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12151e0482f5SStefano Zampini 
12169566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
12179566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
12189566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
12199566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
12209566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
12219566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
12229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
12239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
12241e0482f5SStefano Zampini   }
12259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
12261e0482f5SStefano Zampini 
12271e0482f5SStefano Zampini #if defined(PRINT_GDET)
12281e0482f5SStefano Zampini   inc = 0;
12291e0482f5SStefano Zampini   lev = pcbddc->current_level;
12301e0482f5SStefano Zampini #endif
1231213b8bfaSStefano Zampini 
1232213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1233a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1234a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
12351e0482f5SStefano Zampini     IS          cornersis = NULL;
12361e0482f5SStefano Zampini     PetscScalar cvals[2];
1237a13144ffSStefano Zampini 
123848a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
12399566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1240a13144ffSStefano Zampini     if (Gins && GKins) {
12411683a169SBarry Smith       const PetscScalar *data;
1242a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1243a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1244a13144ffSStefano Zampini 
12459566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1246a13144ffSStefano Zampini       /* H1 */
12479566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
12489566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
12499566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
12509566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
12519566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
12529566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1253a13144ffSStefano Zampini       /* complement */
12549566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
125563a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
125663a3b9bcSJacob Faibussowitsch       PetscCheck(ncc + nch == nrc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "The sum of the number of columns of GKins %" PetscInt_FMT " and Gins %" PetscInt_FMT " does not match %" PetscInt_FMT " for coarse edge %" PetscInt_FMT, ncc, nch, nrc, i);
125763a3b9bcSJacob Faibussowitsch       PetscCheck(ncc == 1 || !pcbddc->nedcG, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot generate the coarse discrete gradient for coarse edge %" PetscInt_FMT " with ncc %" PetscInt_FMT, i, ncc);
12589566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
12599566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
12609566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
12611e0482f5SStefano Zampini 
12621e0482f5SStefano Zampini       /* coarse discrete gradient */
12631e0482f5SStefano Zampini       if (pcbddc->nedcG) {
12641e0482f5SStefano Zampini         PetscInt cols[2];
12651e0482f5SStefano Zampini 
12661e0482f5SStefano Zampini         cols[0] = 2 * i;
12671e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
12689566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
12691e0482f5SStefano Zampini       }
12709566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1271a13144ffSStefano Zampini     }
12729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
12739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
12749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
12759566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
12769566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1277a13144ffSStefano Zampini   }
12789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1279a13144ffSStefano Zampini 
1280a13144ffSStefano Zampini   /* Start assembling */
12819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
12821baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1283a13144ffSStefano Zampini 
1284a13144ffSStefano Zampini   /* Free */
1285c2151214SStefano Zampini   if (fl2g) {
12869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
128748a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
12889566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1289c2151214SStefano Zampini   }
1290eee23b56SStefano Zampini 
1291eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1292eee23b56SStefano Zampini   {
1293eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1294eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1295eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1296eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1297eee23b56SStefano Zampini 
1298eee23b56SStefano Zampini     /* find first primal edge */
1299eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
13009566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1301eee23b56SStefano Zampini     } else {
13021baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1303eee23b56SStefano Zampini       idxs = cedges;
1304eee23b56SStefano Zampini     }
1305eee23b56SStefano Zampini     cum = 0;
1306eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1307eee23b56SStefano Zampini 
1308eee23b56SStefano Zampini     /* adapt connected components */
13099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1310eee23b56SStefano Zampini     graph->cptr[0] = 0;
1311eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1312eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1313eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1314eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1315eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1316eee23b56SStefano Zampini         ncc++;
1317eee23b56SStefano Zampini         lc--;
1318eee23b56SStefano Zampini         cum++;
1319eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1320eee23b56SStefano Zampini       }
1321eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1322eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1323eee23b56SStefano Zampini       ncc++;
1324eee23b56SStefano Zampini     }
1325eee23b56SStefano Zampini     graph->ncc = ncc;
132648a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
13279566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1328eee23b56SStefano Zampini   }
13299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
13309566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
13319566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
13329566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
1333eee23b56SStefano Zampini 
13349566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
13359566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
13369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
13379566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
13389566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
13399566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
13409566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
13419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1342a13144ffSStefano Zampini 
1343a13144ffSStefano Zampini   /* Complete assembling */
13449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
13451e0482f5SStefano Zampini   if (pcbddc->nedcG) {
13469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
13471e0482f5SStefano Zampini #if 0
13489566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->nedcG,"coarse_G"));
13499566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->nedcG,NULL));
13501e0482f5SStefano Zampini #endif
13511e0482f5SStefano Zampini   }
1352a13144ffSStefano Zampini 
1353a13144ffSStefano Zampini   /* set change of basis */
13549566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, singular));
13559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
13563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1357a13144ffSStefano Zampini }
1358a13144ffSStefano Zampini 
1359d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1360d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1361d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
1362d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1363d71ae5a4SJacob Faibussowitsch {
1364d8203eabSStefano Zampini   PetscInt i;
1365d8203eabSStefano Zampini 
1366d8203eabSStefano Zampini   PetscFunctionBegin;
1367d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1368d8203eabSStefano Zampini     PetscInt first, last;
1369d8203eabSStefano Zampini 
13709566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
13717827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1372d8203eabSStefano Zampini     if (i >= first && i < last) {
1373d8203eabSStefano Zampini       PetscScalar *data;
13749566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1375d8203eabSStefano Zampini       if (!has_const) {
1376d8203eabSStefano Zampini         data[i - first] = 1.;
1377d8203eabSStefano Zampini       } else {
137886fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
137986fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1380d8203eabSStefano Zampini       }
13819566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1382d8203eabSStefano Zampini     }
13839566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1384d8203eabSStefano Zampini   }
13859566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1386d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1387d8203eabSStefano Zampini     PetscInt first, last;
13889566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
13899566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1390d8203eabSStefano Zampini     if (i >= first && i < last) {
1391d8203eabSStefano Zampini       PetscScalar *data;
13929566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1393d8203eabSStefano Zampini       if (!has_const) {
1394d8203eabSStefano Zampini         data[i - first] = 0.;
1395d8203eabSStefano Zampini       } else {
139686fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
139786fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1398d8203eabSStefano Zampini       }
13999566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1400d8203eabSStefano Zampini     }
14019566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
14029566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1403d8203eabSStefano Zampini   }
14043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1405d8203eabSStefano Zampini }
1406d8203eabSStefano Zampini 
1407d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1408d71ae5a4SJacob Faibussowitsch {
1409a198735bSStefano Zampini   Mat                    loc_divudotp;
1410fa23a32eSStefano Zampini   Vec                    p, v, vins, quad_vec, *quad_vecs;
14118ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
1412669cc0f4SStefano Zampini   PetscScalar           *vals;
1413669cc0f4SStefano Zampini   const PetscScalar     *array;
14140f04eeffSStefano Zampini   PetscInt               i, maxneighs = 0, maxsize, *gidxs;
1415a040e873SStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
14161ae86dd6SStefano Zampini   PetscMPIInt            rank;
1417669cc0f4SStefano Zampini 
1418669cc0f4SStefano Zampini   PetscFunctionBegin;
14199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14200f04eeffSStefano Zampini   for (i = 0; i < n_neigh; i++) maxneighs = PetscMax(graph->count[shared[i][0]] + 1, maxneighs);
14211c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &maxneighs, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)A)));
14228037d520SStefano Zampini   if (!maxneighs) {
14239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14248037d520SStefano Zampini     *nnsp = NULL;
14253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1426669cc0f4SStefano Zampini   }
1427669cc0f4SStefano Zampini   maxsize = 0;
1428a040e873SStefano Zampini   for (i = 0; i < n_neigh; i++) maxsize = PetscMax(n_shared[i], maxsize);
14299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxsize, &gidxs, maxsize, &vals));
1430669cc0f4SStefano Zampini   /* create vectors to hold quadrature weights */
14319566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
14328ae0ca82SStefano Zampini   if (!transpose) {
14339566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
14348ae0ca82SStefano Zampini   } else {
14359566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
14368ae0ca82SStefano Zampini   }
14379566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(quad_vec, maxneighs, &quad_vecs));
14389566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&quad_vec));
14399566063dSJacob Faibussowitsch   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, maxneighs, quad_vecs, nnsp));
144048a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecLockReadPop(quad_vecs[i]));
1441d8203eabSStefano Zampini 
1442669cc0f4SStefano Zampini   /* compute local quad vec */
14439566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
14448ae0ca82SStefano Zampini   if (!transpose) {
14459566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
14468ae0ca82SStefano Zampini   } else {
14479566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
14488ae0ca82SStefano Zampini   }
14499566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
14508ae0ca82SStefano Zampini   if (!transpose) {
14519566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
14528ae0ca82SStefano Zampini   } else {
14539566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
14548ae0ca82SStefano Zampini   }
1455fa23a32eSStefano Zampini   if (vl2l) {
1456187c917aSStefano Zampini     Mat        lA;
1457187c917aSStefano Zampini     VecScatter sc;
1458187c917aSStefano Zampini 
14599566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
14609566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
14619566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
14629566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14639566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14649566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
1465fa23a32eSStefano Zampini   } else {
1466fa23a32eSStefano Zampini     vins = v;
1467fa23a32eSStefano Zampini   }
14689566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(vins, &array));
14699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&p));
14709a962809SStefano Zampini 
14711ae86dd6SStefano Zampini   /* insert in global quadrature vecs */
14729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
14730f04eeffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
1474669cc0f4SStefano Zampini     const PetscInt *idxs;
1475669cc0f4SStefano Zampini     PetscInt        idx, nn, j;
1476669cc0f4SStefano Zampini 
1477a040e873SStefano Zampini     idxs = shared[i];
1478a040e873SStefano Zampini     nn   = n_shared[i];
1479669cc0f4SStefano Zampini     for (j = 0; j < nn; j++) vals[j] = array[idxs[j]];
14809566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(rank, graph->count[idxs[0]], graph->neighbours_set[idxs[0]], &idx));
1481669cc0f4SStefano Zampini     idx = -(idx + 1);
148263a3b9bcSJacob Faibussowitsch     PetscCheck(idx >= 0 && idx < maxneighs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid index %" PetscInt_FMT " not in [0,%" PetscInt_FMT ")", idx, maxneighs);
14839566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(map, nn, idxs, gidxs));
14849566063dSJacob Faibussowitsch     PetscCall(VecSetValues(quad_vecs[idx], nn, gidxs, vals, INSERT_VALUES));
1485669cc0f4SStefano Zampini   }
14869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(vins, &array));
148848a46eb9SPierre Jolivet   if (vl2l) PetscCall(VecDestroy(&vins));
14899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
14909566063dSJacob Faibussowitsch   PetscCall(PetscFree2(gidxs, vals));
1491669cc0f4SStefano Zampini 
1492669cc0f4SStefano Zampini   /* assemble near null space */
149348a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecAssemblyBegin(quad_vecs[i]));
1494669cc0f4SStefano Zampini   for (i = 0; i < maxneighs; i++) {
14959566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(quad_vecs[i]));
14969566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(quad_vecs[i], NULL, "-pc_bddc_quad_vecs_view"));
14979566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1498669cc0f4SStefano Zampini   }
14999566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(maxneighs, &quad_vecs));
15003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1501669cc0f4SStefano Zampini }
1502669cc0f4SStefano Zampini 
1503d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1504d71ae5a4SJacob Faibussowitsch {
15057620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
15067620a527SStefano Zampini 
15077620a527SStefano Zampini   PetscFunctionBegin;
15087620a527SStefano Zampini   if (primalv) {
15097620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
15107620a527SStefano Zampini       IS list[2], newp;
15117620a527SStefano Zampini 
15127620a527SStefano Zampini       list[0] = primalv;
15137620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
15149566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
15159566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
15169566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
15177620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
15187620a527SStefano Zampini     } else {
15199566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
15207620a527SStefano Zampini     }
15217620a527SStefano Zampini   }
15223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15237620a527SStefano Zampini }
1524669cc0f4SStefano Zampini 
1525d71ae5a4SJacob Faibussowitsch static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1526d71ae5a4SJacob Faibussowitsch {
15271c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
15281c7a958bSStefano Zampini 
15291c7a958bSStefano Zampini   PetscFunctionBegin;
15301c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
15313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15321c7a958bSStefano Zampini }
1533674ae819SStefano Zampini 
1534d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1535d71ae5a4SJacob Faibussowitsch {
15361f4df5f7SStefano Zampini   Vec       local, global;
15371f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
15381f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
15395c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
15401f4df5f7SStefano Zampini 
15411f4df5f7SStefano Zampini   PetscFunctionBegin;
1542d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
15439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1544d0609cedSBarry Smith   PetscOptionsEnd();
15451f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
15469566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
15479566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
15489566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
15499566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
15506a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
155148a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
15526a8fc67bSStefano Zampini     goto boundary;
15536a8fc67bSStefano Zampini   }
15545c5e10d6SStefano Zampini 
15551f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
15561f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
15571f4df5f7SStefano Zampini       PetscInt i;
15580c85b387SStefano Zampini 
15599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
15601f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
15610c85b387SStefano Zampini         PetscInt bs;
15620c85b387SStefano Zampini 
15639566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
15649566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
15659566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15669566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
15671f4df5f7SStefano Zampini       }
15681f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
15691f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
15709566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
15711f4df5f7SStefano Zampini     }
15721f4df5f7SStefano Zampini   } else {
157321ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
157421ef3d20SStefano Zampini       DM dm;
157521ef3d20SStefano Zampini 
15769566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
157748a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
157821ef3d20SStefano Zampini       if (dm) {
157921ef3d20SStefano Zampini         IS      *fields;
158021ef3d20SStefano Zampini         PetscInt nf, i;
15810c85b387SStefano Zampini 
15829566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
15839566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
158421ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
15850c85b387SStefano Zampini           PetscInt bs;
15860c85b387SStefano Zampini 
15879566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
15889566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
15899566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15909566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
159121ef3d20SStefano Zampini         }
15929566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
159321ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
159421ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
159521ef3d20SStefano Zampini         PetscContainer c;
159621ef3d20SStefano Zampini 
15979566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
159821ef3d20SStefano Zampini         if (c) {
159921ef3d20SStefano Zampini           MatISLocalFields lf;
16009566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
16019566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
160221ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
16031f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
16049566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
160521ef3d20SStefano Zampini           if (i > 1) {
1606986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
16079566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
160848a46eb9SPierre Jolivet             for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n / pcbddc->n_ISForDofsLocal, i, pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal[i]));
16091f4df5f7SStefano Zampini           }
161021ef3d20SStefano Zampini         }
161121ef3d20SStefano Zampini       }
16127a0e7b2cSstefano_zampini     } else {
16137a0e7b2cSstefano_zampini       PetscInt i;
161448a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
16151f4df5f7SStefano Zampini     }
1616986cdee1SStefano Zampini   }
16171f4df5f7SStefano Zampini 
16185c5e10d6SStefano Zampini boundary:
16191f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
16209566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
16217a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
16229566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
16231f4df5f7SStefano Zampini   }
16241f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
16259566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
16267a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
16279566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
16281f4df5f7SStefano Zampini   }
162948a46eb9SPierre Jolivet   if (!pcbddc->user_primal_vertices_local && pcbddc->user_primal_vertices) PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->user_primal_vertices, &pcbddc->user_primal_vertices_local));
16309566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
16319566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
16327620a527SStefano Zampini   /* detect local disconnected subdomains if requested (use matis->A) */
16337620a527SStefano Zampini   if (pcbddc->detect_disconnected) {
16347620a527SStefano Zampini     IS        primalv = NULL;
16357620a527SStefano Zampini     PetscInt  i;
16368361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
16377a0e7b2cSstefano_zampini 
163848a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
16399566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
16409566063dSJacob Faibussowitsch     PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
16419566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
16429566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
16437620a527SStefano Zampini   }
16447620a527SStefano Zampini   /* early stage corner detection */
16457620a527SStefano Zampini   {
16467620a527SStefano Zampini     DM dm;
16477620a527SStefano Zampini 
16489566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
164948a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
16507620a527SStefano Zampini     if (dm) {
16517620a527SStefano Zampini       PetscBool isda;
16527620a527SStefano Zampini 
16539566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
16547620a527SStefano Zampini       if (isda) {
16557620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
16567620a527SStefano Zampini         IS                     corners;
16577620a527SStefano Zampini         Mat                    lA;
16584f819b78SStefano Zampini         PetscBool              gl, lo;
16597620a527SStefano Zampini 
16604f819b78SStefano Zampini         {
16614f819b78SStefano Zampini           Vec                cvec;
16624f819b78SStefano Zampini           const PetscScalar *coords;
16634f819b78SStefano Zampini           PetscInt           dof, n, cdim;
16644f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
16654f819b78SStefano Zampini 
16669566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
16679566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
16689566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
16699566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
16704f819b78SStefano Zampini           n /= cdim;
16719566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
16729566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
16739566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
16744f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
16754f819b78SStefano Zampini           memc = PETSC_FALSE;
16764f819b78SStefano Zampini #endif
16774f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
16784f819b78SStefano Zampini           if (memc) {
16799566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
16804f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
16814f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
16824f819b78SStefano Zampini             PetscInt   i, b, d;
16834f819b78SStefano Zampini 
16844f819b78SStefano Zampini             for (i = 0; i < n; i++) {
16854f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
1686ad540459SPierre Jolivet                 for (d = 0; d < cdim; d++) bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]);
16874f819b78SStefano Zampini               }
16884f819b78SStefano Zampini             }
16894f819b78SStefano Zampini           }
16909566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
16914f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
16924f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
16934f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
16944f819b78SStefano Zampini         }
16959566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
16969566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
16979566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
16989566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
16994f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
17001c2dc1cbSBarry Smith         PetscCall(MPIU_Allreduce(&lo, &gl, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
17014f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
17027620a527SStefano Zampini           const PetscInt *idx;
170372ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
17047620a527SStefano Zampini 
17059566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
17069566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
17079566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
17089566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
170972ed36d8SStefano Zampini           if (bs == dof) {
17109566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
17119566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
171272ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
171372ed36d8SStefano Zampini             PetscInt i, d;
171472ed36d8SStefano Zampini 
17159566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
17169371c9d4SSatish Balay             for (i = 0; i < n; i++)
17179371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
17189566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
171972ed36d8SStefano Zampini 
172072ed36d8SStefano Zampini             bs = 1;
172172ed36d8SStefano Zampini             n *= dof;
172272ed36d8SStefano Zampini           }
17239566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
17249566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17259566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
17269566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
17279566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
17281c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
17294f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
17304f819b78SStefano Zampini         }
173148a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17327620a527SStefano Zampini       }
17337620a527SStefano Zampini     }
17347620a527SStefano Zampini   }
17351c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
17361c7a958bSStefano Zampini     DM dm;
17371c7a958bSStefano Zampini 
17389566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
173948a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
17404f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
17411c7a958bSStefano Zampini       Vec          vcoords;
17421c7a958bSStefano Zampini       PetscSection section;
17431c7a958bSStefano Zampini       PetscReal   *coords;
17441c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
17451c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
174651ab8ad6SStefano Zampini       /* debug coordinates */
174751ab8ad6SStefano Zampini       PetscViewer       viewer;
174851ab8ad6SStefano Zampini       PetscBool         flg;
174951ab8ad6SStefano Zampini       PetscViewerFormat format;
175051ab8ad6SStefano Zampini       const char       *prefix;
17511c7a958bSStefano Zampini 
17529566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
17539566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
17549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
17559566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
17569566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
17579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
17589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
17599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
17601c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
17611c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
176251ab8ad6SStefano Zampini 
176351ab8ad6SStefano Zampini       /* debug coordinates */
176451ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
176551ab8ad6SStefano Zampini       PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
176651ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
17671c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
17681c7a958bSStefano Zampini         PetscInt           i;
17691c7a958bSStefano Zampini         const PetscScalar *v;
177051ab8ad6SStefano Zampini         char               name[16];
17711c7a958bSStefano Zampini 
17721c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
177351ab8ad6SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%d", (int)d));
177451ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
17759566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
177651ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
17779566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
17781c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
17799566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
17801c7a958bSStefano Zampini       }
17819566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
17829566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
17839566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
17849566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
17859566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
178651ab8ad6SStefano Zampini       if (flg) {
178751ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
1788cd791dc2SBarry Smith         PetscCall(PetscOptionsRestoreViewer(&viewer));
178951ab8ad6SStefano Zampini       }
17901c7a958bSStefano Zampini     }
17911c7a958bSStefano Zampini   }
17923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17937a0e7b2cSstefano_zampini }
17947a0e7b2cSstefano_zampini 
1795d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
1796d71ae5a4SJacob Faibussowitsch {
1797*f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
17987a0e7b2cSstefano_zampini   IS              nis;
17997a0e7b2cSstefano_zampini   const PetscInt *idxs;
18007a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
18017a0e7b2cSstefano_zampini 
18027a0e7b2cSstefano_zampini   PetscFunctionBegin;
18037827d75bSBarry Smith   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)(pc)), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
18047a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
18057a0e7b2cSstefano_zampini     /* init rootdata with true */
18061bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
18077a0e7b2cSstefano_zampini   } else {
18089566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
18097a0e7b2cSstefano_zampini   }
18109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
18119566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
18129566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
18137a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
18149371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
18159566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
18169566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18179566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18189566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18199566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18207a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
18219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
18227a0e7b2cSstefano_zampini   } else {
18239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
18247a0e7b2cSstefano_zampini   }
18257a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
18269371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
1827*f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)*is), nnd, nidxs, PETSC_OWN_POINTER, &nis));
18289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
18297a0e7b2cSstefano_zampini   *is = nis;
18303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18311f4df5f7SStefano Zampini }
18321f4df5f7SStefano Zampini 
1833d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z)
1834d71ae5a4SJacob Faibussowitsch {
1835*f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
1836*f4f49eeaSPierre Jolivet   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
18373e589ea0SStefano Zampini 
18383e589ea0SStefano Zampini   PetscFunctionBegin;
18393ba16761SJacob Faibussowitsch   if (!pcbddc->benign_have_null) PetscFunctionReturn(PETSC_SUCCESS);
18403e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
18413e589ea0SStefano Zampini     Vec swap;
18423e589ea0SStefano Zampini 
18439566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
18443e589ea0SStefano Zampini     swap                = pcbddc->work_change;
18453e589ea0SStefano Zampini     pcbddc->work_change = r;
18463e589ea0SStefano Zampini     r                   = swap;
18473e589ea0SStefano Zampini   }
18489566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18499566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18519566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
18529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18539566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
18549566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
18559566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18569566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18573e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
1858f913dca9SStefano Zampini     pcbddc->work_change = r;
18599566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
18609566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
18613e589ea0SStefano Zampini   }
18623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18633e589ea0SStefano Zampini }
18643e589ea0SStefano Zampini 
1865ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
1866d71ae5a4SJacob Faibussowitsch {
1867a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1868a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
1869a3df083aSStefano Zampini 
1870a3df083aSStefano Zampini   PetscFunctionBegin;
18719566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
1872a3df083aSStefano Zampini   if (transpose) {
1873a3df083aSStefano Zampini     apply_right = ctx->apply_left;
1874a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
1875a3df083aSStefano Zampini   } else {
1876a3df083aSStefano Zampini     apply_right = ctx->apply_right;
1877a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
1878a3df083aSStefano Zampini   }
1879a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
1880a3df083aSStefano Zampini   if (apply_right) {
1881a3df083aSStefano Zampini     const PetscScalar *ax;
1882a3df083aSStefano Zampini     PetscInt           nl, i;
1883a3df083aSStefano Zampini 
18849566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
18859566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
18869566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
18879566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
1888a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1889a3df083aSStefano Zampini       PetscScalar     sum, val;
1890a3df083aSStefano Zampini       const PetscInt *idxs;
1891a3df083aSStefano Zampini       PetscInt        nz, j;
18929566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
18939566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1894a3df083aSStefano Zampini       sum = 0.;
1895a3df083aSStefano Zampini       if (ctx->apply_p0) {
1896a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
1897a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1898a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
1899a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
1900a3df083aSStefano Zampini         }
1901a3df083aSStefano Zampini       } else {
1902ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) sum += ctx->work[idxs[j]];
1903a3df083aSStefano Zampini       }
1904a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
19059566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1906a3df083aSStefano Zampini     }
19079566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
1908a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
1909a3df083aSStefano Zampini   }
1910a3df083aSStefano Zampini   if (transpose) {
19119566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
1912a3df083aSStefano Zampini   } else {
19139566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
1914a3df083aSStefano Zampini   }
19151baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
1916a3df083aSStefano Zampini   if (apply_left) {
1917a3df083aSStefano Zampini     PetscScalar *ay;
1918a3df083aSStefano Zampini     PetscInt     i;
1919a3df083aSStefano Zampini 
19209566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
1921a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1922a3df083aSStefano Zampini       PetscScalar     sum, val;
1923a3df083aSStefano Zampini       const PetscInt *idxs;
1924a3df083aSStefano Zampini       PetscInt        nz, j;
19259566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
19269566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1927a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
1928a3df083aSStefano Zampini       if (ctx->apply_p0) {
1929a3df083aSStefano Zampini         sum = 0.;
1930a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1931a3df083aSStefano Zampini           sum += ay[idxs[j]];
1932a3df083aSStefano Zampini           ay[idxs[j]] += val;
1933a3df083aSStefano Zampini         }
1934a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
1935a3df083aSStefano Zampini       } else {
1936ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) ay[idxs[j]] += val;
1937a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
1938a3df083aSStefano Zampini       }
19399566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1940a3df083aSStefano Zampini     }
19419566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
1942a3df083aSStefano Zampini   }
19433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1944a3df083aSStefano Zampini }
1945a3df083aSStefano Zampini 
1946ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
1947d71ae5a4SJacob Faibussowitsch {
1948a3df083aSStefano Zampini   PetscFunctionBegin;
19499566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
19503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1951a3df083aSStefano Zampini }
1952a3df083aSStefano Zampini 
1953ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
1954d71ae5a4SJacob Faibussowitsch {
1955a3df083aSStefano Zampini   PetscFunctionBegin;
19569566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
19573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1958a3df083aSStefano Zampini }
1959a3df083aSStefano Zampini 
1960d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
1961d71ae5a4SJacob Faibussowitsch {
1962a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
1963a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
1964a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1965a3df083aSStefano Zampini 
1966a3df083aSStefano Zampini   PetscFunctionBegin;
1967a3df083aSStefano Zampini   if (!restore) {
19681dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
1969a3df083aSStefano Zampini     PetscScalar       *work;
1970b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
1971a3df083aSStefano Zampini 
197228b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
19733ba16761SJacob Faibussowitsch     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(PETSC_SUCCESS);
19749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
19759566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
19769566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
19779566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
19789566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (void (*)(void))PCBDDCBenignMatMult_Private));
19799566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (void (*)(void))PCBDDCBenignMatMultTranspose_Private));
19809566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
19819566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
1982a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
1983a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
1984a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
1985a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
1986059032f7SStefano Zampini     if (reuse) {
1987a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
19881dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
1989059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
1990059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
1991059032f7SStefano Zampini       PetscInt               i;
1992059032f7SStefano Zampini 
19939566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
19949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
199548a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISGlobalToLocalMappingApplyIS(N_to_D, IS_GTOLM_DROP, pcbddc->benign_zerodiag_subs[i], &ctx->benign_zerodiag_subs[i]));
19969566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
19971dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
1998059032f7SStefano Zampini     }
1999a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
2000a3df083aSStefano Zampini     ctx->work = work;
20019566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
20029566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
20039566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
2004a3df083aSStefano Zampini     pcis->A_IB = A_IB;
2005a3df083aSStefano Zampini 
2006a3df083aSStefano Zampini     /* A_BI as A_IB^T */
20079566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
2008a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
2009a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
2010a3df083aSStefano Zampini   } else {
20113ba16761SJacob Faibussowitsch     if (!pcbddc->benign_original_mat) PetscFunctionReturn(PETSC_SUCCESS);
20129566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
20139566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2014a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
20151dd7afcfSStefano Zampini     ctx->A     = NULL;
20169566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
20171dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
20181dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
20191dd7afcfSStefano Zampini     if (ctx->free) {
2020059032f7SStefano Zampini       PetscInt i;
202148a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
20229566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2023059032f7SStefano Zampini     }
20249566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
20259566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2026a3df083aSStefano Zampini   }
20273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2028a3df083aSStefano Zampini }
2029a3df083aSStefano Zampini 
2030a3df083aSStefano Zampini /* used just in bddc debug mode */
2031ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2032d71ae5a4SJacob Faibussowitsch {
2033a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2034a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2035a3df083aSStefano Zampini   Mat      An;
2036a3df083aSStefano Zampini 
2037a3df083aSStefano Zampini   PetscFunctionBegin;
20389566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
20399566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2040a3df083aSStefano Zampini   if (is1) {
20419566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
20429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2043a3df083aSStefano Zampini   } else {
2044a3df083aSStefano Zampini     *B = An;
2045a3df083aSStefano Zampini   }
20463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2047a3df083aSStefano Zampini }
2048a3df083aSStefano Zampini 
20491cf9b237SStefano Zampini /* TODO: add reuse flag */
2050d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2051d71ae5a4SJacob Faibussowitsch {
20521cf9b237SStefano Zampini   Mat             Bt;
20531cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
20541cf9b237SStefano Zampini   const PetscInt *ii, *ij;
20551cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
20561cf9b237SStefano Zampini   PetscBool       flg_row;
20571cf9b237SStefano Zampini 
20581cf9b237SStefano Zampini   PetscFunctionBegin;
20599566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
20609566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20619566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
20621cf9b237SStefano Zampini   nnz = n;
20631cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
20641cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
20651cf9b237SStefano Zampini   }
20669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
20679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
20689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
20691cf9b237SStefano Zampini   nnz    = 0;
20701cf9b237SStefano Zampini   bii[0] = 0;
20711cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
20721cf9b237SStefano Zampini     PetscInt j;
20731cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
20741cf9b237SStefano Zampini       PetscScalar entry = a[j];
20753272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
20761cf9b237SStefano Zampini         bij[nnz]   = ij[j];
20771cf9b237SStefano Zampini         bdata[nnz] = entry;
20781cf9b237SStefano Zampini         nnz++;
20791cf9b237SStefano Zampini       }
20801cf9b237SStefano Zampini     }
20811cf9b237SStefano Zampini     bii[i + 1] = nnz;
20821cf9b237SStefano Zampini   }
20839566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
20849566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
20859566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20861cf9b237SStefano Zampini   {
2087*f4f49eeaSPierre Jolivet     Mat_SeqAIJ *b = (Mat_SeqAIJ *)Bt->data;
20881cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
20891cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
20901cf9b237SStefano Zampini   }
209148a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
20921cf9b237SStefano Zampini   *B = Bt;
20933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20941cf9b237SStefano Zampini }
20951cf9b237SStefano Zampini 
2096d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv)
2097d71ae5a4SJacob Faibussowitsch {
2098c80a6c00SStefano Zampini   Mat                    B = NULL;
2099c80a6c00SStefano Zampini   DM                     dm;
21004f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
21014f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
21024f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2103c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
21044f1b2e48SStefano Zampini   PetscInt               i, n;
21054f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2106c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
21074f1b2e48SStefano Zampini 
21084f1b2e48SStefano Zampini   PetscFunctionBegin;
2109a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2110a2eca866SStefano Zampini   if (cc) *cc = NULL;
2111a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
21129566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
21139566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
211448a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
2115f9635d15SStefano Zampini   if (dm) PetscCall(PetscObjectTypeCompareAny((PetscObject)dm, &isplex, DMPLEX, DMP4EST, DMP8EST, ""));
21168361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
21178361f951SStefano Zampini 
2118c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2119c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2120c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2121c80a6c00SStefano Zampini     IS              cellNumbering;
2122c80a6c00SStefano Zampini     const PetscInt *cellNum;
2123c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2124c80a6c00SStefano Zampini     PetscSection    section;
2125c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2126c80a6c00SStefano Zampini     PetscSF         sfPoint;
2127c80a6c00SStefano Zampini 
2128f9635d15SStefano Zampini     PetscCall(DMConvert(dm, DMPLEX, &dm));
21299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
21309566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
21319566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2132c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
21339566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
21349566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
21359566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2136c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
21379566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
21389566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
21399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
21409566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2141c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2142c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
21439371c9d4SSatish Balay       if (nroots > 0) {
21449371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21459371c9d4SSatish Balay       }
2146c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
21479566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2148c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2149c80a6c00SStefano Zampini         const PetscInt point = adj[a];
21505cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2151c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
21529566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
21539566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2154c80a6c00SStefano Zampini           *pBuf = point;
2155c80a6c00SStefano Zampini         }
2156c80a6c00SStefano Zampini       }
2157c80a6c00SStefano Zampini       n++;
2158c80a6c00SStefano Zampini     }
21599566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2160c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
21619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
21629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
21639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2164c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
21659371c9d4SSatish Balay       if (nroots > 0) {
21669371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21679371c9d4SSatish Balay       }
2168*f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetOffset(section, p, &xadj[idx++]));
2169c80a6c00SStefano Zampini     }
2170c80a6c00SStefano Zampini     xadj[n] = size;
21719566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2172c80a6c00SStefano Zampini     /* Clean up */
21739566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
21749566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
21759566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2176c80a6c00SStefano Zampini     graph->xadj   = xadj;
2177c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2178c80a6c00SStefano Zampini   } else {
2179c80a6c00SStefano Zampini     Mat       A;
21808361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2181c80a6c00SStefano Zampini 
21829566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
218363c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
21849566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
21853ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
218663c961adSStefano Zampini     }
21879566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
21884f1b2e48SStefano Zampini     if (!isseqaij && filter) {
21891cf9b237SStefano Zampini       PetscBool isseqdense;
21901cf9b237SStefano Zampini 
21919566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
21921cf9b237SStefano Zampini       if (!isseqdense) {
21939566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
21941cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
21951cf9b237SStefano Zampini         PetscScalar *array;
21961cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
21971cf9b237SStefano Zampini 
21989566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
21999566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
22009566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
22011cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
22021cf9b237SStefano Zampini           PetscInt j;
22031cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
22041cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
22051cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
22061cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
22071cf9b237SStefano Zampini           }
22081cf9b237SStefano Zampini         }
22099566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
22109566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
22111cf9b237SStefano Zampini       }
22124f1b2e48SStefano Zampini     } else {
22139566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
22144f1b2e48SStefano Zampini       B = A;
22154f1b2e48SStefano Zampini     }
22169566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22174f1b2e48SStefano Zampini 
22184f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
22194f1b2e48SStefano Zampini     if (filter) {
22204f1b2e48SStefano Zampini       PetscScalar *data;
22214f1b2e48SStefano Zampini       PetscInt     j, cum;
22224f1b2e48SStefano Zampini 
22239566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
22249566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
22254f1b2e48SStefano Zampini       cum = 0;
22264f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
22274f1b2e48SStefano Zampini         PetscInt t;
22284f1b2e48SStefano Zampini 
22294f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
2230ad540459SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) continue;
22314f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
22324f1b2e48SStefano Zampini         }
22334f1b2e48SStefano Zampini         t                = xadj_filtered[i];
22344f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
22354f1b2e48SStefano Zampini         cum += t;
22364f1b2e48SStefano Zampini       }
22379566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
22384f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
22394f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
22404f1b2e48SStefano Zampini     } else {
22414f1b2e48SStefano Zampini       graph->xadj   = xadj;
22424f1b2e48SStefano Zampini       graph->adjncy = adjncy;
22434f1b2e48SStefano Zampini     }
2244c80a6c00SStefano Zampini   }
2245c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
22469566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
22479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
22489566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
22499566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_MAX_INT));
22509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
22519566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
22529566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2253c80a6c00SStefano Zampini 
22544f1b2e48SStefano Zampini   /* partial clean up */
22559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2256c80a6c00SStefano Zampini   if (B) {
2257c80a6c00SStefano Zampini     PetscBool flg_row;
22589566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22599566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
22604f1b2e48SStefano Zampini   }
2261c80a6c00SStefano Zampini   if (isplex) {
22629566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
22639566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2264c80a6c00SStefano Zampini   }
22654f1b2e48SStefano Zampini 
22664f1b2e48SStefano Zampini   /* get back data */
2267c80a6c00SStefano Zampini   if (isplex) {
2268c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2269c80a6c00SStefano Zampini     if (cc || primalv) {
2270c80a6c00SStefano Zampini       Mat          A;
2271f9635d15SStefano Zampini       PetscBT      btv, btvt, btvc;
2272c80a6c00SStefano Zampini       PetscSection subSection;
2273c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2274f9635d15SStefano Zampini       PetscInt     dim, cStart, cEnd, fStart, fEnd, vStart, vEnd, pStart, pEnd;
2275c80a6c00SStefano Zampini 
2276f9635d15SStefano Zampini       PetscCall(DMGetDimension(dm, &dim));
22779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
2278f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2279f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2280f9635d15SStefano Zampini       PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2281f9635d15SStefano Zampini       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
22829566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
22839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
22849566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
22859566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2286f9635d15SStefano Zampini       PetscCall(PetscBTCreate(pEnd - pStart, &btvc));
2287f9635d15SStefano Zampini 
2288f9635d15SStefano Zampini       /* First see if we find corners for the subdomains, i.e. a vertex
2289f9635d15SStefano Zampini          shared by at least dim subdomain boundary faces. This does not
2290f9635d15SStefano Zampini          cover all the possible cases with simplices but it is enough
2291f9635d15SStefano Zampini          for tensor cells */
2292f9635d15SStefano Zampini       if (vStart != fStart && dim <= 3) {
2293f9635d15SStefano Zampini         for (PetscInt c = cStart; c < cEnd; c++) {
2294f9635d15SStefano Zampini           PetscInt        nf, cnt = 0, mcnt = dim, *cfaces;
2295f9635d15SStefano Zampini           const PetscInt *faces;
2296f9635d15SStefano Zampini 
2297f9635d15SStefano Zampini           PetscCall(DMPlexGetConeSize(dm, c, &nf));
2298f9635d15SStefano Zampini           PetscCall(DMGetWorkArray(dm, nf, MPIU_INT, &cfaces));
2299f9635d15SStefano Zampini           PetscCall(DMPlexGetCone(dm, c, &faces));
2300f9635d15SStefano Zampini           for (PetscInt f = 0; f < nf; f++) {
2301f9635d15SStefano Zampini             PetscInt nc, ff;
2302f9635d15SStefano Zampini 
2303f9635d15SStefano Zampini             PetscCall(DMPlexGetSupportSize(dm, faces[f], &nc));
2304f9635d15SStefano Zampini             PetscCall(DMPlexGetTreeParent(dm, faces[f], &ff, NULL));
2305f9635d15SStefano Zampini             if (nc == 1 && faces[f] == ff) cfaces[cnt++] = faces[f];
2306f9635d15SStefano Zampini           }
2307f9635d15SStefano Zampini           if (cnt >= mcnt) {
2308f9635d15SStefano Zampini             PetscInt size, *closure = NULL;
2309f9635d15SStefano Zampini 
2310f9635d15SStefano Zampini             PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2311f9635d15SStefano Zampini             for (PetscInt k = 0; k < 2 * size; k += 2) {
2312f9635d15SStefano Zampini               PetscInt v = closure[k];
2313f9635d15SStefano Zampini               if (v >= vStart && v < vEnd) {
2314f9635d15SStefano Zampini                 PetscInt vsize, *vclosure = NULL;
2315f9635d15SStefano Zampini 
2316f9635d15SStefano Zampini                 cnt = 0;
2317f9635d15SStefano Zampini                 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2318f9635d15SStefano Zampini                 for (PetscInt vk = 0; vk < 2 * vsize; vk += 2) {
2319f9635d15SStefano Zampini                   PetscInt f = vclosure[vk];
2320f9635d15SStefano Zampini                   if (f >= fStart && f < fEnd) {
2321f9635d15SStefano Zampini                     PetscInt  nc, ff;
2322f9635d15SStefano Zampini                     PetscBool valid = PETSC_FALSE;
2323f9635d15SStefano Zampini 
2324f9635d15SStefano Zampini                     for (PetscInt fk = 0; fk < nf; fk++)
2325f9635d15SStefano Zampini                       if (f == cfaces[fk]) valid = PETSC_TRUE;
2326f9635d15SStefano Zampini                     if (!valid) continue;
2327f9635d15SStefano Zampini                     PetscCall(DMPlexGetSupportSize(dm, f, &nc));
2328f9635d15SStefano Zampini                     PetscCall(DMPlexGetTreeParent(dm, f, &ff, NULL));
2329f9635d15SStefano Zampini                     if (nc == 1 && f == ff) cnt++;
2330f9635d15SStefano Zampini                   }
2331f9635d15SStefano Zampini                 }
2332f9635d15SStefano Zampini                 if (cnt >= mcnt) PetscCall(PetscBTSet(btvc, v - pStart));
2333f9635d15SStefano Zampini                 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2334f9635d15SStefano Zampini               }
2335f9635d15SStefano Zampini             }
2336f9635d15SStefano Zampini             PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2337f9635d15SStefano Zampini           }
2338f9635d15SStefano Zampini           PetscCall(DMRestoreWorkArray(dm, nf, MPIU_INT, &cfaces));
2339f9635d15SStefano Zampini         }
2340f9635d15SStefano Zampini       }
2341c80a6c00SStefano Zampini 
2342c80a6c00SStefano Zampini       cids[0] = 0;
2343c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2344c80a6c00SStefano Zampini         PetscInt j;
2345c80a6c00SStefano Zampini 
23469566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2347c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2348c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2349c80a6c00SStefano Zampini 
23509566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2351c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
235220c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2353c80a6c00SStefano Zampini 
23549566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
23559566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
23569566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2357c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2358c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2359f9635d15SStefano Zampini               if (PetscBTLookup(btvc, p - pStart)) pids[cump++] = off + s; /* subdomain corner */
2360f9635d15SStefano Zampini               else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2361e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2362c80a6c00SStefano Zampini             }
23639566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
236420c3699dSStefano Zampini             if (pp != p) {
23659566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
23669566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
23679566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
236820c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
236920c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2370f9635d15SStefano Zampini                 if (PetscBTLookup(btvc, pp - pStart)) pids[cump++] = off + s; /* subdomain corner */
2371f9635d15SStefano Zampini                 else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2372e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
237320c3699dSStefano Zampini               }
237420c3699dSStefano Zampini             }
2375c80a6c00SStefano Zampini           }
23769566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2377c80a6c00SStefano Zampini         }
2378c80a6c00SStefano Zampini         cids[i + 1] = cum;
2379c80a6c00SStefano Zampini         /* mark dofs as already assigned */
238048a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2381c80a6c00SStefano Zampini       }
2382c80a6c00SStefano Zampini       if (cc) {
23839566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
238448a46eb9SPierre Jolivet         for (i = 0; i < graph->ncc; i++) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cids[i + 1] - cids[i], ids + cids[i], PETSC_COPY_VALUES, &cc_n[i]));
2385c80a6c00SStefano Zampini         *cc = cc_n;
2386c80a6c00SStefano Zampini       }
23871baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
23889566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
23899566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
23909566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2391f9635d15SStefano Zampini       PetscCall(PetscBTDestroy(&btvc));
2392f9635d15SStefano Zampini       PetscCall(DMDestroy(&dm));
2393c80a6c00SStefano Zampini     }
2394c80a6c00SStefano Zampini   } else {
23951cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
23961cf9b237SStefano Zampini     if (cc) {
23979566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
239848a46eb9SPierre Jolivet       for (i = 0; i < graph->ncc; i++) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, graph->cptr[i + 1] - graph->cptr[i], graph->queue + graph->cptr[i], PETSC_COPY_VALUES, &cc_n[i]));
23994f1b2e48SStefano Zampini       *cc = cc_n;
24001cf9b237SStefano Zampini     }
2401c80a6c00SStefano Zampini   }
24024f1b2e48SStefano Zampini   /* clean up graph */
24030a545947SLisandro Dalcin   graph->xadj   = NULL;
24040a545947SLisandro Dalcin   graph->adjncy = NULL;
24059566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
24063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24074f1b2e48SStefano Zampini }
24084f1b2e48SStefano Zampini 
2409d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2410d71ae5a4SJacob Faibussowitsch {
24115408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2412*f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2413dee84bffSStefano Zampini   IS       dirIS  = NULL;
24144f1b2e48SStefano Zampini   PetscInt i;
24155408967cSStefano Zampini 
24165408967cSStefano Zampini   PetscFunctionBegin;
24179566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
24185408967cSStefano Zampini   if (zerodiag) {
24195408967cSStefano Zampini     Mat             A;
24205408967cSStefano Zampini     Vec             vec3_N;
24215408967cSStefano Zampini     PetscScalar    *vals;
24225408967cSStefano Zampini     const PetscInt *idxs;
2423d12d3064SStefano Zampini     PetscInt        nz, *count;
24245408967cSStefano Zampini 
24255408967cSStefano Zampini     /* p0 */
24269566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
24279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
24289566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
24299566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
24304f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
24319566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
24329566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
24339566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
24345408967cSStefano Zampini     /* v_I */
24359566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
24365408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
24379566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
24389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
24399566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
24405408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
24419566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
24429566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
24435408967cSStefano Zampini     if (dirIS) {
24445408967cSStefano Zampini       PetscInt n;
24455408967cSStefano Zampini 
24469566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
24479566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
24485408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
24499566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
24509566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
24515408967cSStefano Zampini     }
24529566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
24539566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
24549566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
24559566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
24569566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
24579566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
24589566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
24597827d75bSBarry Smith     PetscCheck(PetscAbsScalar(vals[0]) <= 1.e-1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Benign trick can not be applied! b(v_I,p_0) = %1.6e (should be numerically 0.)", (double)PetscAbsScalar(vals[0]));
24609566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
24619566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2462d12d3064SStefano Zampini 
2463d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
24649566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
24659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2466d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
24679566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
24689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
246963a3b9bcSJacob Faibussowitsch     for (i = 0; i < nz; i++) PetscCheck(!count[idxs[i]], PETSC_COMM_SELF, PETSC_ERR_SUP, "Benign trick can not be applied! pressure dof %" PetscInt_FMT " is an interface dof", idxs[i]);
24709566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
24719566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
24725408967cSStefano Zampini   }
24739566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
24745408967cSStefano Zampini 
24755408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
24769566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
24774f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
24789566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
24794f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
24809566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2481f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2482f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
248363a3b9bcSJacob Faibussowitsch     PetscCheck(val == -PetscGlobalRank - i, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error testing PCBDDCBenignGetOrSetP0! Found %g at %" PetscInt_FMT " instead of %g", (double)PetscRealPart(pcbddc->benign_p0[i]), i, (double)(-PetscGlobalRank - i));
2484f2a566d8SStefano Zampini   }
24853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24865408967cSStefano Zampini }
24875408967cSStefano Zampini 
2488d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal)
2489d71ae5a4SJacob Faibussowitsch {
2490339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2491*f4f49eeaSPierre Jolivet   Mat_IS   *matis     = (Mat_IS *)pc->pmat->data;
24923b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
24933b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
24944edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
24954edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2496339f8db1SStefano Zampini 
2497339f8db1SStefano Zampini   PetscFunctionBegin;
24983b03f7bbSStefano Zampini   if (reuse) goto project_b0;
24999566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
25009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
250148a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
25029566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
25033b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
25043b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
25053b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
25063b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
25074f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
25084f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
25091ae86dd6SStefano Zampini      since the local Schur complements are already SPD
25104f1b2e48SStefano Zampini   */
251140fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
25127fbe2174Sstefano_zampini     IS        iP = NULL;
25133b03f7bbSStefano Zampini     PetscInt  p, *pp;
25143b03f7bbSStefano Zampini     PetscBool flg;
25154f1b2e48SStefano Zampini 
25169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
25173b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2518d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
25199566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
2520d0609cedSBarry Smith     PetscOptionsEnd();
25213b03f7bbSStefano Zampini     if (!flg) {
25223b03f7bbSStefano Zampini       n     = 1;
25233b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
25243b03f7bbSStefano Zampini     }
25253b03f7bbSStefano Zampini 
25263b03f7bbSStefano Zampini     bsp = 0;
25273b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
25283b03f7bbSStefano Zampini       PetscInt bs;
25293b03f7bbSStefano Zampini 
253063a3b9bcSJacob Faibussowitsch       PetscCheck(pp[p] >= 0 && pp[p] < pcbddc->n_ISForDofsLocal, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Invalid field id for pressures %" PetscInt_FMT, pp[p]);
25319566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
25323b03f7bbSStefano Zampini       bsp += bs;
25333b03f7bbSStefano Zampini     }
25349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
25353b03f7bbSStefano Zampini     bsp = 0;
25363b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
25373b03f7bbSStefano Zampini       const PetscInt *idxs;
25383b03f7bbSStefano Zampini       PetscInt        b, bs, npl, *bidxs;
25393b03f7bbSStefano Zampini 
25409566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
25419566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
25429566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
25439566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
25443b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
25453b03f7bbSStefano Zampini         PetscInt i;
25463b03f7bbSStefano Zampini 
25473b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
25489566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
25493b03f7bbSStefano Zampini         bsp++;
25503b03f7bbSStefano Zampini       }
25519566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
25529566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
25533b03f7bbSStefano Zampini     }
25549566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
25553b03f7bbSStefano Zampini 
25567fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
25579566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
25587fbe2174Sstefano_zampini     if (iP) {
25597fbe2174Sstefano_zampini       IS newpressures;
25607fbe2174Sstefano_zampini 
25619566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
25629566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
25637fbe2174Sstefano_zampini       pressures = newpressures;
25647fbe2174Sstefano_zampini     }
25659566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
256648a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
25679566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
256840fa8d13SStefano Zampini   }
25693b03f7bbSStefano Zampini 
257097d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
25719566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
257227b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
25739566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
25749566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
257548a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
25769566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
25774edc6404Sstefano_zampini   zerodiag_save = zerodiag;
25789566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
25794f1b2e48SStefano Zampini   if (!nz) {
25804f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
25814f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
25829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
258340fa8d13SStefano Zampini   }
25844f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
25853b03f7bbSStefano Zampini 
25864f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
25874f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
25883b03f7bbSStefano Zampini   benign_n        = 0;
25891f4df5f7SStefano Zampini   n_interior_dofs = 0;
25901f4df5f7SStefano Zampini   interior_dofs   = NULL;
25914edc6404Sstefano_zampini   nneu            = 0;
259248a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
25933369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
25944edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
25951f4df5f7SStefano Zampini     PetscInt  n, i, j;
25961f4df5f7SStefano Zampini     PetscInt  n_neigh, *neigh, *n_shared, **shared;
25971f4df5f7SStefano Zampini     PetscInt *iwork;
25981f4df5f7SStefano Zampini 
25999566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &n));
26009566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
26019566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &iwork));
26029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
260390648384SStefano Zampini     for (i = 1; i < n_neigh; i++)
26049371c9d4SSatish Balay       for (j = 0; j < n_shared[i]; j++) iwork[shared[i][j]] += 1;
26051f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
26069371c9d4SSatish Balay       if (!iwork[i]) interior_dofs[n_interior_dofs++] = i;
26079566063dSJacob Faibussowitsch     PetscCall(PetscFree(iwork));
26089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
26091f4df5f7SStefano Zampini   }
26104f1b2e48SStefano Zampini   if (has_null_pressures) {
26114f1b2e48SStefano Zampini     IS             *subs;
26124edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
26131f4df5f7SStefano Zampini     const PetscInt *idxs;
26141f4df5f7SStefano Zampini     PetscScalar    *array;
26151f4df5f7SStefano Zampini     Vec            *work;
26164f1b2e48SStefano Zampini 
26174f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
26184f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
26191f4df5f7SStefano Zampini     /* 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) */
26204edc6404Sstefano_zampini     if (checkb) {
26219566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
26229566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
26239566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
26241f4df5f7SStefano Zampini       /* work[0] = 1_p */
26259566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
26269566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
26271f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
26289566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
26291f4df5f7SStefano Zampini       /* work[0] = 1_v */
26309566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
26319566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
26321f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
26339566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
26349566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
26351f4df5f7SStefano Zampini     }
26363b03f7bbSStefano Zampini 
26373b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
26383b03f7bbSStefano Zampini       IS      *is;
26393b03f7bbSStefano Zampini       PetscInt b, totb;
26403b03f7bbSStefano Zampini 
26413b03f7bbSStefano Zampini       totb  = bsp;
26423b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
26433b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
26449566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
26453b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
26464f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
26474f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
26484f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
26494f1b2e48SStefano Zampini           PetscInt               nl;
26504f1b2e48SStefano Zampini 
26513b03f7bbSStefano Zampini           if (subs) {
26529566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
26533b03f7bbSStefano Zampini           } else {
26543b03f7bbSStefano Zampini             IS tis;
26553b03f7bbSStefano Zampini 
26569566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
26579566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
26589566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
26599566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
26603b03f7bbSStefano Zampini           }
26619566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
26629566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
26634f1b2e48SStefano Zampini           if (nl) {
26644f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
26654f1b2e48SStefano Zampini 
26664edc6404Sstefano_zampini             if (checkb) {
26679566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
26689566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
26699566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
26709566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
26711f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
26729566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
26739566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
26749566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
26759566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
26769566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
26779566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
26781f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
26791f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
26801f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
26811f4df5f7SStefano Zampini                   break;
26821f4df5f7SStefano Zampini                 }
26831f4df5f7SStefano Zampini               }
26849566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
26851f4df5f7SStefano Zampini             }
26866632bad2Sstefano_zampini             if (valid && nneu) {
26876632bad2Sstefano_zampini               const PetscInt *idxs;
26881f4df5f7SStefano Zampini               PetscInt        nzb;
26891f4df5f7SStefano Zampini 
26909566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26919566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
26929566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26931f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
26941f4df5f7SStefano Zampini             }
26951f4df5f7SStefano Zampini             if (valid && pressures) {
26963b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
26973b03f7bbSStefano Zampini               PetscInt i1, i2;
26983b03f7bbSStefano Zampini 
26999566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
27009566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
27019566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
27029566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
27033b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
27049566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
27059566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
27064f1b2e48SStefano Zampini             }
27074f1b2e48SStefano Zampini             if (valid) {
27089566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
27093b03f7bbSStefano Zampini               benign_n++;
27103b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
27114f1b2e48SStefano Zampini           }
27129566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
27139566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
27144f1b2e48SStefano Zampini         }
27153b03f7bbSStefano Zampini       }
27164f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
27174f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
27181f4df5f7SStefano Zampini 
27196632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
272048a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
27214edc6404Sstefano_zampini       if (valid && checkb) {
27229566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
27239566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
27249566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
27251f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
27261f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
27271f4df5f7SStefano Zampini             valid = PETSC_FALSE;
27281f4df5f7SStefano Zampini             break;
27291f4df5f7SStefano Zampini           }
27301f4df5f7SStefano Zampini         }
27319566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
27321f4df5f7SStefano Zampini       }
27334f1b2e48SStefano Zampini       if (valid) {
27343b03f7bbSStefano Zampini         benign_n = 1;
27359566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
27369566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
27374f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
27384f1b2e48SStefano Zampini       }
27394f1b2e48SStefano Zampini     }
274048a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
27411f4df5f7SStefano Zampini   }
27429566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
27434f1b2e48SStefano Zampini 
27443b03f7bbSStefano Zampini   if (!benign_n) {
2745b9b0e38cSStefano Zampini     PetscInt n;
2746b9b0e38cSStefano Zampini 
27479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
27484f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
27499566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
275076a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
2751b9b0e38cSStefano Zampini   }
27524f1b2e48SStefano Zampini 
27534f1b2e48SStefano Zampini   /* final check for null pressures */
275448a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
27554f1b2e48SStefano Zampini 
27564f1b2e48SStefano Zampini   if (recompute_zerodiag) {
27579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
27583b03f7bbSStefano Zampini     if (benign_n == 1) {
27599566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
27604f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
27614f1b2e48SStefano Zampini     } else {
27624f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
27634f1b2e48SStefano Zampini 
27644f1b2e48SStefano Zampini       nzn = 0;
27653b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
27664f1b2e48SStefano Zampini         PetscInt ns;
27679566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
27684f1b2e48SStefano Zampini         nzn += ns;
27694f1b2e48SStefano Zampini       }
27709566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
27714f1b2e48SStefano Zampini       nzn = 0;
27723b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
27734f1b2e48SStefano Zampini         PetscInt ns, *idxs;
27749566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
27759566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
27769566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
27779566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
27784f1b2e48SStefano Zampini         nzn += ns;
27794f1b2e48SStefano Zampini       }
27809566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
27819566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
27824f1b2e48SStefano Zampini     }
27834f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
27844f1b2e48SStefano Zampini   }
27854f1b2e48SStefano Zampini 
27863b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
27871c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
27883b03f7bbSStefano Zampini 
2789669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
2790a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2791a198735bSStefano Zampini     Mat                    A, loc_divudotp;
2792a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
2793a198735bSStefano Zampini     IS                     row, col, isused = NULL;
2794a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
2795a198735bSStefano Zampini 
27961f4df5f7SStefano Zampini     if (pressures) {
27971f4df5f7SStefano Zampini       isused = pressures;
27981f4df5f7SStefano Zampini     } else {
27994edc6404Sstefano_zampini       isused = zerodiag_save;
28001f4df5f7SStefano Zampini     }
28019566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
28029566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
28039566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
28047827d75bSBarry Smith     PetscCheck(isused || (n == 0), PETSC_COMM_SELF, PETSC_ERR_USER, "Don't know how to extract div u dot p! Please provide the pressure field");
2805a198735bSStefano Zampini     n_isused = 0;
280648a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
28079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
2808a198735bSStefano Zampini     st = st - n_isused;
28091ae86dd6SStefano Zampini     if (n) {
2810a198735bSStefano Zampini       const PetscInt *gidxs;
2811a198735bSStefano Zampini 
28129566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
28139566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
2814a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
28159566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
28169566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
28179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
28181ae86dd6SStefano Zampini     } else {
28199566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
28209566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
28219566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
2822a198735bSStefano Zampini     }
28239566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
28249566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
28259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
28269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
28279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
28289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
28299566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
28309566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
28319566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
28329566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
28339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
28349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
28359566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
28369566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
28379566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
28389566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
28391ae86dd6SStefano Zampini   }
28409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
28419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
28423b03f7bbSStefano Zampini   if (bzerodiag) {
28433b03f7bbSStefano Zampini     PetscInt i;
2844b3afcdbeSStefano Zampini 
284548a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
28469566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
28473b03f7bbSStefano Zampini   }
28483b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
28493b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
28503b03f7bbSStefano Zampini 
28513b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
28523b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
28531c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
28543b03f7bbSStefano Zampini 
28553b03f7bbSStefano Zampini project_b0:
28569566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
2857b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
28583b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
28594f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
28604f1b2e48SStefano Zampini 
2861339f8db1SStefano Zampini     /* local change of basis for pressures */
28629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
28639566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
28649566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
28659566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
28669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
2867aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
28684f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
2869aa0d93e9SStefano Zampini       const PetscInt *idxs;
28704f1b2e48SStefano Zampini       PetscInt        nzs, j;
28714f1b2e48SStefano Zampini 
28729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
28739566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
28744f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
28754f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
28769566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
28774f1b2e48SStefano Zampini     }
28789566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
28799566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
28809566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
2881aa0d93e9SStefano Zampini     /* set identity by default */
288248a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
28839566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
28849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
2885339f8db1SStefano Zampini     /* set change on pressures */
28864f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
28874f1b2e48SStefano Zampini       PetscScalar    *array;
2888aa0d93e9SStefano Zampini       const PetscInt *idxs;
28894f1b2e48SStefano Zampini       PetscInt        nzs;
28904f1b2e48SStefano Zampini 
28919566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
28929566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
28934f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
2894339f8db1SStefano Zampini         PetscScalar vals[2];
2895339f8db1SStefano Zampini         PetscInt    cols[2];
2896339f8db1SStefano Zampini 
2897339f8db1SStefano Zampini         cols[0] = idxs[i];
28984f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
2899339f8db1SStefano Zampini         vals[0] = 1.;
2900b0f5fe93SStefano Zampini         vals[1] = 1.;
29019566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
2902339f8db1SStefano Zampini       }
29039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
29044f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
29054f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
29069566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
29074f1b2e48SStefano Zampini       /* store local idxs for p0 */
29084f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
29099566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
29109566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
29114f1b2e48SStefano Zampini     }
29129566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
29139566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
29143b03f7bbSStefano Zampini 
2915a3df083aSStefano Zampini     /* project if needed */
2916a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
29171dd7afcfSStefano Zampini       Mat M;
29181dd7afcfSStefano Zampini 
29199566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
29209566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
29219566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
29229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
2923a3df083aSStefano Zampini     }
29244f1b2e48SStefano Zampini     /* store global idxs for p0 */
29259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
2926339f8db1SStefano Zampini   }
2927339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
29283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2929339f8db1SStefano Zampini }
2930339f8db1SStefano Zampini 
2931d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
2932d71ae5a4SJacob Faibussowitsch {
2933efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
2934de9d7bd0SStefano Zampini   PetscScalar *array;
2935efc2fbd9SStefano Zampini 
2936efc2fbd9SStefano Zampini   PetscFunctionBegin;
2937efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
29389566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
29399566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
2940efc2fbd9SStefano Zampini   }
2941de9d7bd0SStefano Zampini   if (get) {
29429566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
29439566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
29449566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
29459566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
2946de9d7bd0SStefano Zampini   } else {
29479566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
29489566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
29499566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
29509566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
2951efc2fbd9SStefano Zampini   }
29523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2953efc2fbd9SStefano Zampini }
2954efc2fbd9SStefano Zampini 
2955d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
2956d71ae5a4SJacob Faibussowitsch {
2957c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2958c263805aSStefano Zampini 
2959c263805aSStefano Zampini   PetscFunctionBegin;
2960c263805aSStefano Zampini   /* TODO: add error checking
2961c263805aSStefano Zampini     - avoid nested pop (or push) calls.
2962c263805aSStefano Zampini     - cannot push before pop.
29631c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
2964c263805aSStefano Zampini   */
29653ba16761SJacob Faibussowitsch   if (!pcbddc->benign_n) PetscFunctionReturn(PETSC_SUCCESS);
2966c263805aSStefano Zampini   if (pop) {
2967a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
29684f1b2e48SStefano Zampini       IS       is_p0;
29694f1b2e48SStefano Zampini       MatReuse reuse;
2970c263805aSStefano Zampini 
2971c263805aSStefano Zampini       /* extract B_0 */
29724f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
2973ad540459SPierre Jolivet       if (pcbddc->benign_B0) reuse = MAT_REUSE_MATRIX;
29749566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
29759566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
2976c263805aSStefano Zampini       /* remove rows and cols from local problem */
29779566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
29789566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
29799566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
29809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
2981a3df083aSStefano Zampini     } else {
2982a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
2983a3df083aSStefano Zampini       PetscScalar *vals;
2984a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
2985a3df083aSStefano Zampini 
29869566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
29879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
2988a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
29890b5adadeSStefano Zampini         PetscInt *nnz;
29909566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
29919566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
29929566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
29939566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
2994331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
29959566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
2996331e053bSStefano Zampini           nnz[i] = n - nnz[i];
2997331e053bSStefano Zampini         }
29989566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
29999566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
30009566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
3001331e053bSStefano Zampini       }
3002a3df083aSStefano Zampini 
3003a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
3004a3df083aSStefano Zampini         PetscScalar *array;
3005a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
3006a3df083aSStefano Zampini 
30079566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
30089566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
30099566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3010a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
30119566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
30129566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
30139566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
30149566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
30159566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
30169566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
3017a3df083aSStefano Zampini         cum = 0;
3018a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
301922db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
3020a3df083aSStefano Zampini             vals[cum]     = array[j];
3021a3df083aSStefano Zampini             idxs_ins[cum] = j;
3022a3df083aSStefano Zampini             cum++;
3023a3df083aSStefano Zampini           }
3024a3df083aSStefano Zampini         }
30259566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
30269566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
30279566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3028a3df083aSStefano Zampini       }
30299566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
30309566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
30319566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
3032a3df083aSStefano Zampini     }
3033c263805aSStefano Zampini   } else { /* push */
30344f1b2e48SStefano Zampini 
30350fdf79fbSJacob Faibussowitsch     PetscCheck(pcbddc->benign_change_explicit, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
30360fdf79fbSJacob Faibussowitsch     for (PetscInt i = 0; i < pcbddc->benign_n; i++) {
30374f1b2e48SStefano Zampini       PetscScalar *B0_vals;
30384f1b2e48SStefano Zampini       PetscInt    *B0_cols, B0_ncol;
30394f1b2e48SStefano Zampini 
30409566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
30419566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
30429566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
30439566063dSJacob Faibussowitsch       PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
30449566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
30454f1b2e48SStefano Zampini     }
30469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
30479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
3048c263805aSStefano Zampini   }
30493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3050c263805aSStefano Zampini }
3051c263805aSStefano Zampini 
3052d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
3053d71ae5a4SJacob Faibussowitsch {
3054b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
305508122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
305608122e43SStefano Zampini   PetscBLASInt    B_dummyint, B_neigs, B_ierr, B_lwork;
305708122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
305808122e43SStefano Zampini   PetscScalar    *work, lwork;
305908122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
306008122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
3061bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
30621b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
306332fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
306408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
306508122e43SStefano Zampini   PetscReal *rwork;
306608122e43SStefano Zampini #endif
3067b1b3d7a2SStefano Zampini 
3068b1b3d7a2SStefano Zampini   PetscFunctionBegin;
30693ba16761SJacob Faibussowitsch   if (!pcbddc->adaptive_selection) PetscFunctionReturn(PETSC_SUCCESS);
307028b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
307132fe681dSStefano Zampini   PetscCheck(sub_schurs->schur_explicit || !sub_schurs->n_subs, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Adaptive selection of constraints requires MUMPS and/or MKL_CPARDISO");
30729371c9d4SSatish Balay   PetscCheck(!sub_schurs->n_subs || sub_schurs->is_symmetric, 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,
30739371c9d4SSatish Balay              sub_schurs->is_posdef);
30749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
307506a4e24aSStefano Zampini 
3076fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
307732fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
30789566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
30799566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
30809566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
30819566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
3082fd14bc51SStefano Zampini   }
3083fd14bc51SStefano Zampini 
308448a46eb9SPierre Jolivet   if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d cc %" PetscInt_FMT " (%d,%d).\n", PetscGlobalRank, sub_schurs->n_subs, sub_schurs->is_hermitian, sub_schurs->is_posdef));
3085e496cd5dSStefano Zampini 
308608122e43SStefano Zampini   /* max size of subsets */
308708122e43SStefano Zampini   mss = 0;
308808122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
308908122e43SStefano Zampini     PetscInt subset_size;
3090862806e4SStefano Zampini 
30919566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
309208122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
309308122e43SStefano Zampini   }
309408122e43SStefano Zampini 
309508122e43SStefano Zampini   /* min/max and threshold */
309608122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3097f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
309808122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3099f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3100bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3101f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3102f6f667cfSStefano Zampini   }
310308122e43SStefano Zampini 
310408122e43SStefano Zampini   /* allocate lapack workspace */
310508122e43SStefano Zampini   cum = cum2 = 0;
310608122e43SStefano Zampini   maxneigs   = 0;
310708122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
310808122e43SStefano Zampini     PetscInt n, subset_size;
3109f6f667cfSStefano Zampini 
31109566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
311108122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
31129162d606SStefano Zampini     cum += subset_size;
31139162d606SStefano Zampini     cum2 += subset_size * n;
311408122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
311508122e43SStefano Zampini   }
31167ebab0bbSStefano Zampini   lwork = 0;
311708122e43SStefano Zampini   if (mss) {
31187ebab0bbSStefano Zampini     PetscScalar  sdummy  = 0.;
311908122e43SStefano Zampini     PetscBLASInt B_itype = 1;
31207ebab0bbSStefano Zampini     PetscBLASInt B_N = mss, idummy = 0;
31217ebab0bbSStefano Zampini     PetscReal    rdummy = 0., zero = 0.0;
31224c6709b3SStefano Zampini     PetscReal    eps = 0.0; /* dlamch? */
312308122e43SStefano Zampini 
31240fdf79fbSJacob Faibussowitsch     PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
312508122e43SStefano Zampini     B_lwork = -1;
31267ebab0bbSStefano Zampini     /* some implementations may complain about NULL pointers, even if we are querying */
31277ebab0bbSStefano Zampini     S       = &sdummy;
31287ebab0bbSStefano Zampini     St      = &sdummy;
31297ebab0bbSStefano Zampini     eigs    = &rdummy;
31307ebab0bbSStefano Zampini     eigv    = &sdummy;
31317ebab0bbSStefano Zampini     B_iwork = &idummy;
31327ebab0bbSStefano Zampini     B_ifail = &idummy;
3133d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
31347ebab0bbSStefano Zampini     rwork = &rdummy;
3135d1710679SStefano Zampini #endif
31368bec7fa6SStefano Zampini     thresh = 1.0;
31379566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
313808122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3139792fecdfSBarry Smith     PetscCallBLAS("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));
314008122e43SStefano Zampini #else
3141792fecdfSBarry Smith     PetscCallBLAS("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));
314208122e43SStefano Zampini #endif
314308401ef6SPierre Jolivet     PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %d", (int)B_ierr);
31449566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
314508122e43SStefano Zampini   }
314608122e43SStefano Zampini 
314708122e43SStefano Zampini   nv = 0;
3148d62866d3SStefano Zampini   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) */
31499566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
315008122e43SStefano Zampini   }
31519566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
315248a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
31539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
315408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
31559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
315608122e43SStefano Zampini #endif
31579371c9d4SSatish Balay   PetscCall(PetscMalloc5(nv + sub_schurs->n_subs, &pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs + 1, &pcbddc->adaptive_constraints_idxs_ptr, nv + sub_schurs->n_subs + 1, &pcbddc->adaptive_constraints_data_ptr, nv + cum, &pcbddc->adaptive_constraints_idxs, nv + cum2,
31589371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
31599566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
316008122e43SStefano Zampini 
316108122e43SStefano Zampini   maxneigs = 0;
316272b8c272SStefano Zampini   cum = cumarray                           = 0;
31639162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
31649162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3165d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
316608122e43SStefano Zampini     const PetscInt *idxs;
316708122e43SStefano Zampini 
31689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
316908122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
317008122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
317108122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
317208122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
31739162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
31749162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
317508122e43SStefano Zampini     }
31769566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
317708122e43SStefano Zampini   }
317808122e43SStefano Zampini 
317908122e43SStefano Zampini   if (mss) { /* multilevel */
318032fe681dSStefano Zampini     if (sub_schurs->gdsw) {
318132fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
318232fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
318332fe681dSStefano Zampini     } else {
31849566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
31859566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
318608122e43SStefano Zampini     }
318732fe681dSStefano Zampini   }
318808122e43SStefano Zampini 
3189bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3190bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
319132fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
319208122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
319308122e43SStefano Zampini     const PetscInt *idxs;
31949d54b7f4SStefano Zampini     PetscReal       upper, lower;
3195862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
319608122e43SStefano Zampini     PetscBLASInt    B_N;
3197aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3198bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
319908122e43SStefano Zampini 
320032fe681dSStefano Zampini     if (upart) {
32019d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3202bd2a564bSStefano Zampini       lower = uthresh;
32039d54b7f4SStefano Zampini     } else {
320432fe681dSStefano Zampini       if (sub_schurs->gdsw) {
320532fe681dSStefano Zampini         upper = uthresh;
320632fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
320732fe681dSStefano Zampini       } else {
320828b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3209bd2a564bSStefano Zampini         upper = 1. / uthresh;
32109d54b7f4SStefano Zampini         lower = 0.;
32119d54b7f4SStefano Zampini       }
321232fe681dSStefano Zampini     }
32139566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
32149566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
32159566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3216bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3217bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3218bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3219bd2a564bSStefano Zampini       Mat T;
3220bd2a564bSStefano Zampini 
3221bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3222bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
32239566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
32249566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
32259566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
32269566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
32279566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
32289566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3229bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3230bd2a564bSStefano Zampini             PetscInt        nz, k;
3231bd2a564bSStefano Zampini             const PetscInt *idxs;
3232bd2a564bSStefano Zampini 
32339566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
32349566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3235bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3236bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3237bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3238bd2a564bSStefano Zampini             }
32399566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3240bd2a564bSStefano Zampini           }
3241bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3242bd2a564bSStefano Zampini           break;
3243bd2a564bSStefano Zampini         }
3244bd2a564bSStefano Zampini       }
3245bd2a564bSStefano Zampini     }
3246bd2a564bSStefano Zampini 
3247f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3248bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3249aff50787SStefano Zampini         PetscInt j, k;
3250580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
32519566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
32529566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
325308122e43SStefano Zampini         }
325408122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3255aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3256aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3257aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3258aff50787SStefano Zampini           }
325908122e43SStefano Zampini         }
326008122e43SStefano Zampini       } else {
32619566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
32629566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
326308122e43SStefano Zampini       }
32648bec7fa6SStefano Zampini     } else {
3265f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3266f6f667cfSStefano Zampini       St = Starray + cumarray;
32678bec7fa6SStefano Zampini     }
3268aff50787SStefano Zampini     /* see if we can save some work */
326948a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3270aff50787SStefano Zampini 
3271b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3272aff50787SStefano Zampini       B_neigs = 0;
3273aff50787SStefano Zampini     } else {
327408122e43SStefano Zampini       PetscBLASInt B_itype = 1;
3275f6f667cfSStefano Zampini       PetscBLASInt B_IL, B_IU;
32764c6709b3SStefano Zampini       PetscReal    eps = -1.0; /* dlamch? */
32779552c7c7SStefano Zampini       PetscInt     nmin_s;
3278bd2a564bSStefano Zampini       PetscBool    compute_range;
3279bd2a564bSStefano Zampini 
32800fdf79fbSJacob Faibussowitsch       PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
32819036ceccSStefano Zampini       B_neigs       = 0;
3282bd2a564bSStefano Zampini       compute_range = (PetscBool)!same_data;
3283bd2a564bSStefano Zampini       if (nmin >= subset_size) compute_range = PETSC_FALSE;
328408122e43SStefano Zampini 
3285fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
32869036ceccSStefano Zampini         PetscInt nc = 0;
3287d16cbb6bSStefano Zampini 
328848a46eb9SPierre Jolivet         if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
32899371c9d4SSatish Balay         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Computing for sub %" PetscInt_FMT "/%" PetscInt_FMT " size %" PetscInt_FMT " count %" PetscInt_FMT " fid %" PetscInt_FMT " (range %d) (change %" PetscInt_FMT ").\n", i,
32909371c9d4SSatish Balay                                                      sub_schurs->n_subs, subset_size, pcbddc->mat_graph->count[idxs[0]] + 1, pcbddc->mat_graph->which_dof[idxs[0]], compute_range, nc));
3291b7ab4a40SStefano Zampini       }
3292b7ab4a40SStefano Zampini 
32939566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3294b7ab4a40SStefano Zampini       if (compute_range) {
3295d16cbb6bSStefano Zampini         /* ask for eigenvalues larger than thresh */
3296bd2a564bSStefano Zampini         if (sub_schurs->is_posdef) {
329708122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3298792fecdfSBarry Smith           PetscCallBLAS("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));
329908122e43SStefano Zampini #else
3300792fecdfSBarry Smith           PetscCallBLAS("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));
330108122e43SStefano Zampini #endif
33029566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3303bd2a564bSStefano Zampini         } else { /* no theory so far, but it works nicely */
33049036ceccSStefano Zampini           PetscInt  recipe = 0, recipe_m = 1;
3305bd2a564bSStefano Zampini           PetscReal bb[2];
3306bd2a564bSStefano Zampini 
33079566063dSJacob Faibussowitsch           PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3308bd2a564bSStefano Zampini           switch (recipe) {
3309bd2a564bSStefano Zampini           case 0:
33109371c9d4SSatish Balay             if (scal) {
33119371c9d4SSatish Balay               bb[0] = PETSC_MIN_REAL;
33129371c9d4SSatish Balay               bb[1] = lthresh;
33139371c9d4SSatish Balay             } else {
33149371c9d4SSatish Balay               bb[0] = uthresh;
33159371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
33169371c9d4SSatish Balay             }
3317bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3318792fecdfSBarry Smith             PetscCallBLAS("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));
3319bd2a564bSStefano Zampini #else
3320792fecdfSBarry Smith             PetscCallBLAS("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));
3321bd2a564bSStefano Zampini #endif
33229566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3323bd2a564bSStefano Zampini             break;
3324d71ae5a4SJacob Faibussowitsch           case 1:
3325d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3326d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh * lthresh;
3327bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3328792fecdfSBarry Smith             PetscCallBLAS("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));
3329bd2a564bSStefano Zampini #else
3330792fecdfSBarry Smith             PetscCallBLAS("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));
3331bd2a564bSStefano Zampini #endif
33329566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3333bd2a564bSStefano Zampini             if (!scal) {
33349036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
3335bd2a564bSStefano Zampini 
33369371c9d4SSatish Balay               bb[0] = PetscMax(lthresh * lthresh, uthresh);
33379371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
33389566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33399566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3340bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3341792fecdfSBarry Smith               PetscCallBLAS("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));
3342bd2a564bSStefano Zampini #else
3343792fecdfSBarry Smith               PetscCallBLAS("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));
3344bd2a564bSStefano Zampini #endif
33459566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3346bd2a564bSStefano Zampini               B_neigs += B_neigs2;
3347bd2a564bSStefano Zampini             }
3348bd2a564bSStefano Zampini             break;
33499036ceccSStefano Zampini           case 2:
33509036ceccSStefano Zampini             if (scal) {
33519036ceccSStefano Zampini               bb[0] = PETSC_MIN_REAL;
33529036ceccSStefano Zampini               bb[1] = 0;
33539036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3354792fecdfSBarry Smith               PetscCallBLAS("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));
33559036ceccSStefano Zampini #else
3356792fecdfSBarry Smith               PetscCallBLAS("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));
33579036ceccSStefano Zampini #endif
33589566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33599036ceccSStefano Zampini             } else {
33609036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
336113bcc0bdSJacob Faibussowitsch               PetscBool    do_copy  = PETSC_FALSE;
33629036ceccSStefano Zampini 
33639036ceccSStefano Zampini               lthresh = PetscMax(lthresh, 0.0);
33649036ceccSStefano Zampini               if (lthresh > 0.0) {
33659036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
33669036ceccSStefano Zampini                 bb[1] = lthresh * lthresh;
33679036ceccSStefano Zampini 
336813bcc0bdSJacob Faibussowitsch                 do_copy = PETSC_TRUE;
33699036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3370792fecdfSBarry Smith                 PetscCallBLAS("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));
33719036ceccSStefano Zampini #else
3372792fecdfSBarry Smith                 PetscCallBLAS("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));
33739036ceccSStefano Zampini #endif
33749566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33759036ceccSStefano Zampini               }
33769036ceccSStefano Zampini               bb[0] = PetscMax(lthresh * lthresh, uthresh);
33779036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
337813bcc0bdSJacob Faibussowitsch               if (do_copy) {
33799566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33809566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
33819036ceccSStefano Zampini               }
33829036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3383792fecdfSBarry Smith               PetscCallBLAS("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));
33849036ceccSStefano Zampini #else
3385792fecdfSBarry Smith               PetscCallBLAS("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));
33869036ceccSStefano Zampini #endif
33879566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33889036ceccSStefano Zampini               B_neigs += B_neigs2;
33899036ceccSStefano Zampini             }
33909036ceccSStefano Zampini             break;
33919036ceccSStefano Zampini           case 3:
33929036ceccSStefano Zampini             if (scal) {
33939566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
33949036ceccSStefano Zampini             } else {
33959566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
33969036ceccSStefano Zampini             }
33979036ceccSStefano Zampini             if (!scal) {
33989036ceccSStefano Zampini               bb[0] = uthresh;
33999036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
34009036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3401792fecdfSBarry Smith               PetscCallBLAS("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));
34029036ceccSStefano Zampini #else
3403792fecdfSBarry Smith               PetscCallBLAS("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));
34049036ceccSStefano Zampini #endif
34059566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34069036ceccSStefano Zampini             }
34079036ceccSStefano Zampini             if (recipe_m > 0 && B_N - B_neigs > 0) {
34089036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
34099036ceccSStefano Zampini 
34109036ceccSStefano Zampini               B_IL = 1;
34119566063dSJacob Faibussowitsch               PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
34129566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34139566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
34149036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3415792fecdfSBarry Smith               PetscCallBLAS("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));
34169036ceccSStefano Zampini #else
3417792fecdfSBarry Smith               PetscCallBLAS("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));
34189036ceccSStefano Zampini #endif
34199566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34209036ceccSStefano Zampini               B_neigs += B_neigs2;
34219036ceccSStefano Zampini             }
34229036ceccSStefano Zampini             break;
3423d71ae5a4SJacob Faibussowitsch           case 4:
3424d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3425d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh;
342648cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3427792fecdfSBarry Smith             PetscCallBLAS("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));
342848cebe81SStefano Zampini #else
3429792fecdfSBarry Smith             PetscCallBLAS("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));
343048cebe81SStefano Zampini #endif
34319566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
343248cebe81SStefano Zampini             {
343348cebe81SStefano Zampini               PetscBLASInt B_neigs2 = 0;
343448cebe81SStefano Zampini 
34359371c9d4SSatish Balay               bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
34369371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
34379566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34389566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
343948cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3440792fecdfSBarry Smith               PetscCallBLAS("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));
344148cebe81SStefano Zampini #else
3442792fecdfSBarry Smith               PetscCallBLAS("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));
344348cebe81SStefano Zampini #endif
34449566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
344548cebe81SStefano Zampini               B_neigs += B_neigs2;
344648cebe81SStefano Zampini             }
344748cebe81SStefano Zampini             break;
344880db8efeSStefano Zampini           case 5: /* same as before: first compute all eigenvalues, then filter */
344980db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3450792fecdfSBarry Smith             PetscCallBLAS("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));
345180db8efeSStefano Zampini #else
3452792fecdfSBarry Smith             PetscCallBLAS("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));
345380db8efeSStefano Zampini #endif
34549566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
345580db8efeSStefano Zampini             {
345680db8efeSStefano Zampini               PetscInt e, k, ne;
345780db8efeSStefano Zampini               for (e = 0, ne = 0; e < B_neigs; e++) {
345880db8efeSStefano Zampini                 if (eigs[e] < lthresh || eigs[e] > uthresh) {
345980db8efeSStefano Zampini                   for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
346080db8efeSStefano Zampini                   eigs[ne] = eigs[e];
346180db8efeSStefano Zampini                   ne++;
346280db8efeSStefano Zampini                 }
346380db8efeSStefano Zampini               }
34649566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(eigv, S, B_N * ne));
346580db8efeSStefano Zampini               B_neigs = ne;
346680db8efeSStefano Zampini             }
346780db8efeSStefano Zampini             break;
3468d71ae5a4SJacob Faibussowitsch           default:
3469d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3470bd2a564bSStefano Zampini           }
3471bd2a564bSStefano Zampini         }
3472bd2a564bSStefano Zampini       } else if (!same_data) { /* this is just to see all the eigenvalues */
3473d16cbb6bSStefano Zampini         B_IU = PetscMax(1, PetscMin(B_N, nmax));
3474d16cbb6bSStefano Zampini         B_IL = 1;
3475d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3476792fecdfSBarry Smith         PetscCallBLAS("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));
3477d16cbb6bSStefano Zampini #else
3478792fecdfSBarry Smith         PetscCallBLAS("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));
3479d16cbb6bSStefano Zampini #endif
34809566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3481b03ebc13SStefano Zampini       } else { /* same_data is true, so just get the adaptive functional requested by the user */
3482b7ab4a40SStefano Zampini         PetscInt k;
348328b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
34849566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
34859566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3486b7ab4a40SStefano Zampini         nmin = nmax;
34879566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3488b7ab4a40SStefano Zampini         for (k = 0; k < nmax; k++) {
3489b7ab4a40SStefano Zampini           eigs[k]                     = 1. / PETSC_SMALL;
3490b7ab4a40SStefano Zampini           eigv[k * (subset_size + 1)] = 1.0;
3491b7ab4a40SStefano Zampini         }
3492d16cbb6bSStefano Zampini       }
34939566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
349408122e43SStefano Zampini       if (B_ierr) {
349563a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
349663a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr > B_N, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: %" PetscBLASInt_FMT " eigenvalues failed to converge", B_ierr);
349763a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: leading minor of order %" PetscBLASInt_FMT " is not positive definite", B_ierr - B_N - 1);
349808122e43SStefano Zampini       }
349908122e43SStefano Zampini 
350008122e43SStefano Zampini       if (B_neigs > nmax) {
350148a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
350232fe681dSStefano Zampini         if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
350308122e43SStefano Zampini         B_neigs = nmax;
350408122e43SStefano Zampini       }
350508122e43SStefano Zampini 
35069552c7c7SStefano Zampini       nmin_s = PetscMin(nmin, B_N);
35079552c7c7SStefano Zampini       if (B_neigs < nmin_s) {
35089036ceccSStefano Zampini         PetscBLASInt B_neigs2 = 0;
350908122e43SStefano Zampini 
351032fe681dSStefano Zampini         if (upart) {
3511bd2a564bSStefano Zampini           if (scal) {
3512bd2a564bSStefano Zampini             B_IU = nmin_s;
3513bd2a564bSStefano Zampini             B_IL = B_neigs + 1;
3514bd2a564bSStefano Zampini           } else {
3515f6f667cfSStefano Zampini             B_IL = B_N - nmin_s + 1;
35169d54b7f4SStefano Zampini             B_IU = B_N - B_neigs;
3517bd2a564bSStefano Zampini           }
35189d54b7f4SStefano Zampini         } else {
35199d54b7f4SStefano Zampini           B_IL = B_neigs + 1;
35209d54b7f4SStefano Zampini           B_IU = nmin_s;
35219d54b7f4SStefano Zampini         }
3522fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
352363a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, less than minimum required %" PetscInt_FMT ". Asking for %" PetscBLASInt_FMT " to %" PetscBLASInt_FMT " incl (fortran like)\n", B_neigs, nmin, B_IL, B_IU));
3524fd14bc51SStefano Zampini         }
3525bd2a564bSStefano Zampini         if (sub_schurs->is_symmetric) {
35261ae86dd6SStefano Zampini           PetscInt j, k;
352708122e43SStefano Zampini           for (j = 0; j < subset_size; j++) {
35281ae86dd6SStefano Zampini             for (k = j; k < subset_size; k++) {
35291ae86dd6SStefano Zampini               S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
35301ae86dd6SStefano Zampini               St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
353108122e43SStefano Zampini             }
353208122e43SStefano Zampini           }
353308122e43SStefano Zampini         } else {
35349566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35359566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
353608122e43SStefano Zampini         }
35379566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
353808122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3539792fecdfSBarry Smith         PetscCallBLAS("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));
354008122e43SStefano Zampini #else
3541792fecdfSBarry Smith         PetscCallBLAS("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));
354208122e43SStefano Zampini #endif
35439566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35449566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
354508122e43SStefano Zampini         B_neigs += B_neigs2;
354608122e43SStefano Zampini       }
354708122e43SStefano Zampini       if (B_ierr) {
354863a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
354963a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr > B_N, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: %" PetscBLASInt_FMT " eigenvalues failed to converge", B_ierr);
355063a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: leading minor of order %" PetscBLASInt_FMT " is not positive definite", B_ierr - B_N - 1);
355108122e43SStefano Zampini       }
3552fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
355363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
355408122e43SStefano Zampini         for (j = 0; j < B_neigs; j++) {
355532fe681dSStefano Zampini           if (!sub_schurs->gdsw) {
355608122e43SStefano Zampini             if (eigs[j] == 0.0) {
35579566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
355808122e43SStefano Zampini             } else {
355932fe681dSStefano Zampini               if (upart) {
356063a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
35619d54b7f4SStefano Zampini               } else {
356263a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1. / eigs[j + eigs_start])));
35639d54b7f4SStefano Zampini               }
3564fd14bc51SStefano Zampini             }
356532fe681dSStefano Zampini           } else {
356632fe681dSStefano Zampini             double pg = (double)eigs[j + eigs_start];
356732fe681dSStefano Zampini             if (pg < 2 * PETSC_SMALL) pg = 0.0;
356832fe681dSStefano Zampini             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
356932fe681dSStefano Zampini           }
357008122e43SStefano Zampini         }
357108122e43SStefano Zampini       }
3572aff50787SStefano Zampini     }
35736c3e6151SStefano Zampini     /* change the basis back to the original one */
35746c3e6151SStefano Zampini     if (sub_schurs->change) {
357572b8c272SStefano Zampini       Mat change, phi, phit;
35766c3e6151SStefano Zampini 
357703dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
35786c3e6151SStefano Zampini         PetscInt ii;
35796c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
358063a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
35816c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3582684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3583684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3584684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
358563a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3586684229deSStefano Zampini #else
358763a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3588684229deSStefano Zampini #endif
35896c3e6151SStefano Zampini           }
35906c3e6151SStefano Zampini         }
35916c3e6151SStefano Zampini       }
35929566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
35939566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
35949566063dSJacob Faibussowitsch       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &phi));
35959566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
35969566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
35979566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
35986c3e6151SStefano Zampini     }
35998bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
36008bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
36019162d606SStefano Zampini     if (B_neigs) {
36029566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3603fd14bc51SStefano Zampini 
3604fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
36059552c7c7SStefano Zampini         PetscInt ii;
36069552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
360763a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
36089552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3609ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3610ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3611ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
361263a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3613ac47001eSStefano Zampini #else
361463a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]])));
3615ac47001eSStefano Zampini #endif
36169552c7c7SStefano Zampini           }
36179552c7c7SStefano Zampini         }
3618fd14bc51SStefano Zampini       }
36199566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
36209162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
36219162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
36229162d606SStefano Zampini       cum++;
362308122e43SStefano Zampini     }
36249566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
362508122e43SStefano Zampini     /* shift for next computation */
362608122e43SStefano Zampini     cumarray += subset_size * subset_size;
362708122e43SStefano Zampini   }
36281baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
362908122e43SStefano Zampini 
363008122e43SStefano Zampini   if (mss) {
363132fe681dSStefano Zampini     if (sub_schurs->gdsw) {
363232fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
363332fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
363432fe681dSStefano Zampini     } else {
36359566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
36369566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3637f6f667cfSStefano Zampini       /* destroy matrices (junk) */
36389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
36399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
364008122e43SStefano Zampini     }
364132fe681dSStefano Zampini   }
36421baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
36439566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
364408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
36459566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
364608122e43SStefano Zampini #endif
364708122e43SStefano Zampini   if (pcbddc->dbg_flag) {
36481b968477SStefano Zampini     PetscInt maxneigs_r;
36491c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
365063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
365108122e43SStefano Zampini   }
36529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
36533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
365408122e43SStefano Zampini }
3655b1b3d7a2SStefano Zampini 
3656d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3657d71ae5a4SJacob Faibussowitsch {
36588629588bSStefano Zampini   PetscScalar *coarse_submat_vals;
3659c8587f34SStefano Zampini 
3660c8587f34SStefano Zampini   PetscFunctionBegin;
3661f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
36625e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
36639566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3664c8587f34SStefano Zampini 
3665684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
36660fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
36679566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3668c8587f34SStefano Zampini 
36698629588bSStefano Zampini   /*
36708629588bSStefano Zampini      Setup local correction and local part of coarse basis.
36718629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
36728629588bSStefano Zampini   */
36739566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat_vals));
36748629588bSStefano Zampini 
36758629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
36769566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat_vals));
36778629588bSStefano Zampini 
36788629588bSStefano Zampini   /* free */
36799566063dSJacob Faibussowitsch   PetscCall(PetscFree(coarse_submat_vals));
36803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3681c8587f34SStefano Zampini }
3682c8587f34SStefano Zampini 
3683d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetCustomization(PC pc)
3684d71ae5a4SJacob Faibussowitsch {
3685674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3686674ae819SStefano Zampini 
3687674ae819SStefano Zampini   PetscFunctionBegin;
36889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
36899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
36909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
36919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
36929566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
36939566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
36949566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
36959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
36969566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
36979566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
36983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3699674ae819SStefano Zampini }
3700674ae819SStefano Zampini 
3701d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetTopography(PC pc)
3702d71ae5a4SJacob Faibussowitsch {
3703674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
37044f1b2e48SStefano Zampini   PetscInt i;
3705674ae819SStefano Zampini 
3706674ae819SStefano Zampini   PetscFunctionBegin;
37079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
37089566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
37099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
37109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
37119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
37129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
37139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
37149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
37159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
37169566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
37179566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
371848a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
3719e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
37209566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
37219566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
3722c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
37238af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
37241c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
37253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3726674ae819SStefano Zampini }
3727674ae819SStefano Zampini 
3728d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetSolvers(PC pc)
3729d71ae5a4SJacob Faibussowitsch {
3730674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3731674ae819SStefano Zampini 
3732674ae819SStefano Zampini   PetscFunctionBegin;
37339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
373458da7f69SStefano Zampini   if (pcbddc->coarse_phi_B) {
3735ca92afb2SStefano Zampini     PetscScalar *array;
37369566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &array));
37379566063dSJacob Faibussowitsch     PetscCall(PetscFree(array));
373858da7f69SStefano Zampini   }
37399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
37409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
37419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
37429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
37439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
37449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
37459566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
37469566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
37479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
37489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
37499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
37509566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
37519566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
37529566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
37539566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
37549566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
37559566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
37569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
37579566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
37589566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
37599566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
37609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
37619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
37629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
37639566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
37649566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
37659566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
3766ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
3767ca92afb2SStefano Zampini     PetscInt i;
376848a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
37699566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
3770ca92afb2SStefano Zampini   }
37719566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
37723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3773674ae819SStefano Zampini }
3774674ae819SStefano Zampini 
3775d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
3776d71ae5a4SJacob Faibussowitsch {
37776bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
37786bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
37796bfb1811SStefano Zampini   VecType  impVecType;
37804f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
37816bfb1811SStefano Zampini 
37826bfb1811SStefano Zampini   PetscFunctionBegin;
37834f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3784b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
37859566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
3786e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
3787e7b262bdSStefano Zampini   /* R nodes */
3788e7b262bdSStefano Zampini   old_size = -1;
378948a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
3790e7b262bdSStefano Zampini   if (n_R != old_size) {
37919566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
37929566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
37939566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
37949566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
37959566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
37969566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
3797e7b262bdSStefano Zampini   }
3798e7b262bdSStefano Zampini   /* local primal dofs */
3799e7b262bdSStefano Zampini   old_size = -1;
380048a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
3801e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
38029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
38039566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
38049566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
38059566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
3806e7b262bdSStefano Zampini   }
3807e7b262bdSStefano Zampini   /* local explicit constraints */
3808e7b262bdSStefano Zampini   old_size = -1;
380948a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
3810e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
38119566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
38129566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
38139566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
38149566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
381583b7ccabSStefano Zampini   }
38163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38176bfb1811SStefano Zampini }
38186bfb1811SStefano Zampini 
3819d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpCorrection(PC pc, PetscScalar **coarse_submat_vals_n)
3820d71ae5a4SJacob Faibussowitsch {
382125084f0cSStefano Zampini   /* pointers to pcis and pcbddc */
382288ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
382388ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
3824d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
382525084f0cSStefano Zampini   /* submatrices of local problem */
382680677318SStefano Zampini   Mat A_RV, A_VR, A_VV, local_auxmat2_R;
382706656605SStefano Zampini   /* submatrices of local coarse problem */
382806656605SStefano Zampini   Mat S_VV, S_CV, S_VC, S_CC;
382925084f0cSStefano Zampini   /* working matrices */
383006656605SStefano Zampini   Mat C_CR;
383125084f0cSStefano Zampini   /* additional working stuff */
383206656605SStefano Zampini   PC           pc_R;
3833c58f9fdbSStefano Zampini   Mat          F, Brhs = NULL;
38345cbda25cSStefano Zampini   Vec          dummy_vec;
38357ebab0bbSStefano Zampini   PetscBool    isLU, isCHOL, need_benign_correction, sparserhs;
383625084f0cSStefano Zampini   PetscScalar *coarse_submat_vals; /* TODO: use a PETSc matrix */
383706656605SStefano Zampini   PetscScalar *work;
383806656605SStefano Zampini   PetscInt    *idx_V_B;
3839ffd830a3SStefano Zampini   PetscInt     lda_rhs, n, n_vertices, n_constraints, *p0_lidx_I;
384006656605SStefano Zampini   PetscInt     i, n_R, n_D, n_B;
384106656605SStefano Zampini   PetscScalar  one = 1.0, m_one = -1.0;
384288ebb749SStefano Zampini 
384388ebb749SStefano Zampini   PetscFunctionBegin;
38447827d75bSBarry Smith   PetscCheck(pcbddc->symmetric_primal || !pcbddc->benign_n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Non-symmetric primal basis computation with benign trick not yet implemented");
38459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
3846ffd830a3SStefano Zampini 
3847ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
3848b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
38494f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
3850b371cd4fSStefano Zampini   n_B           = pcis->n_B;
3851b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
385288ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
385388ebb749SStefano Zampini 
385488ebb749SStefano Zampini   /* vertices in boundary numbering */
38559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
38569566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
385763a3b9bcSJacob Faibussowitsch   PetscCheck(i == n_vertices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error in boundary numbering for BDDC vertices! %" PetscInt_FMT " != %" PetscInt_FMT, n_vertices, i);
385888ebb749SStefano Zampini 
385906656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
38609566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pcbddc->local_primal_size * pcbddc->local_primal_size, &coarse_submat_vals));
38619566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_vertices, coarse_submat_vals, &S_VV));
38629566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VV, pcbddc->local_primal_size));
38638e3a54c0SPierre Jolivet   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_vertices, PetscSafePointerPlusOffset(coarse_submat_vals, n_vertices), &S_CV));
38649566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CV, pcbddc->local_primal_size));
38658e3a54c0SPierre Jolivet   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_constraints, PetscSafePointerPlusOffset(coarse_submat_vals, pcbddc->local_primal_size * n_vertices), &S_VC));
38669566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VC, pcbddc->local_primal_size));
38678e3a54c0SPierre Jolivet   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_constraints, PetscSafePointerPlusOffset(coarse_submat_vals, (pcbddc->local_primal_size + 1) * n_vertices), &S_CC));
38689566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CC, pcbddc->local_primal_size));
386906656605SStefano Zampini 
387006656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
38719566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
38729566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
38739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
38749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
3875ffd830a3SStefano Zampini   lda_rhs                = n_R;
3876a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
38777ebab0bbSStefano Zampini   if (isLU || isCHOL) {
38789566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
3879b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
3880df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3881d62866d3SStefano Zampini     MatFactorType      type;
3882d62866d3SStefano Zampini 
3883df4d28bfSStefano Zampini     F = reuse_solver->F;
38849566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
3885d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
38867ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
38879566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
388822db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
38897ebab0bbSStefano Zampini   } else F = NULL;
389006656605SStefano Zampini 
3891c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
3892c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
3893c58f9fdbSStefano Zampini   if (F) {
3894ea799195SBarry Smith     MatSolverType solver;
3895c58f9fdbSStefano Zampini 
38969566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
38979566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
3898c58f9fdbSStefano Zampini   }
3899c58f9fdbSStefano Zampini 
3900ffd830a3SStefano Zampini   /* allocate workspace */
3901ffd830a3SStefano Zampini   n = 0;
3902ad540459SPierre Jolivet   if (n_constraints) n += lda_rhs * n_constraints;
3903ffd830a3SStefano Zampini   if (n_vertices) {
3904ffd830a3SStefano Zampini     n = PetscMax(2 * lda_rhs * n_vertices, n);
3905ffd830a3SStefano Zampini     n = PetscMax((lda_rhs + n_B) * n_vertices, n);
3906ffd830a3SStefano Zampini   }
3907ad540459SPierre Jolivet   if (!pcbddc->symmetric_primal) n = PetscMax(2 * lda_rhs * pcbddc->local_primal_size, n);
39089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &work));
3909ffd830a3SStefano Zampini 
39105cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
39115cbda25cSStefano Zampini   dummy_vec = NULL;
39125cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
39139566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
39149566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
39159566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
39165cbda25cSStefano Zampini   }
39175cbda25cSStefano Zampini 
39189566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
39199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
39207ebab0bbSStefano Zampini 
392188ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
392288ebb749SStefano Zampini   if (n_constraints) {
3923837cedc9SStefano Zampini     Mat M3, C_B;
392406656605SStefano Zampini     IS  is_aux;
392506656605SStefano Zampini 
392625084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
39279566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_aux));
39289566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
39299566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
393088ebb749SStefano Zampini 
393180677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
393280677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
3933c58f9fdbSStefano Zampini     if (!sparserhs) {
39349566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(work, lda_rhs * n_constraints));
393588ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
393606656605SStefano Zampini         const PetscScalar *row_cmat_values;
393706656605SStefano Zampini         const PetscInt    *row_cmat_indices;
393806656605SStefano Zampini         PetscInt           size_of_constraint, j;
393988ebb749SStefano Zampini 
39409566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
3941ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) work[row_cmat_indices[j] + i * lda_rhs] = -row_cmat_values[j];
39429566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
394306656605SStefano Zampini       }
39449566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &Brhs));
3945c58f9fdbSStefano Zampini     } else {
3946c58f9fdbSStefano Zampini       Mat tC_CR;
3947c58f9fdbSStefano Zampini 
39489566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
3949c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
3950c58f9fdbSStefano Zampini         PetscScalar *aa;
3951c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
3952c58f9fdbSStefano Zampini         PetscBool    done;
3953c58f9fdbSStefano Zampini 
39549566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
395528b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
39569566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
39579566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
39589566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
395928b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
3960c58f9fdbSStefano Zampini       } else {
39619566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
3962c58f9fdbSStefano Zampini         tC_CR = C_CR;
3963c58f9fdbSStefano Zampini       }
39649566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
39659566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
3966c58f9fdbSStefano Zampini     }
39679566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, NULL, &local_auxmat2_R));
396806656605SStefano Zampini     if (F) {
3969a3df083aSStefano Zampini       if (need_benign_correction) {
3970df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3971a3df083aSStefano Zampini 
397272b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
39739566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
3974a3df083aSStefano Zampini       }
39759566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
3976a3df083aSStefano Zampini       if (need_benign_correction) {
3977a3df083aSStefano Zampini         PetscScalar       *marr;
3978df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3979a3df083aSStefano Zampini 
39809566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
39815cbda25cSStefano Zampini         if (lda_rhs != n_R) {
39825cbda25cSStefano Zampini           for (i = 0; i < n_constraints; i++) {
39839566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
39849566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
39859566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
39865cbda25cSStefano Zampini           }
39875cbda25cSStefano Zampini         } else {
3988a3df083aSStefano Zampini           for (i = 0; i < n_constraints; i++) {
39899566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
39909566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
39919566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
3992a3df083aSStefano Zampini           }
39935cbda25cSStefano Zampini         }
39949566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
3995a3df083aSStefano Zampini       }
399606656605SStefano Zampini     } else {
399780677318SStefano Zampini       PetscScalar *marr;
399880677318SStefano Zampini 
39999566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
400006656605SStefano Zampini       for (i = 0; i < n_constraints; i++) {
40019566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
40029566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
40039566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
40049566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
40059566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
40069566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
400706656605SStefano Zampini       }
40089566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
400906656605SStefano Zampini     }
40101baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
40119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
401280677318SStefano Zampini     if (!pcbddc->switch_static) {
40139566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_constraints, NULL, &pcbddc->local_auxmat2));
401480677318SStefano Zampini       for (i = 0; i < n_constraints; i++) {
4015ab2d12f3SJunchao Zhang         Vec r, b;
40169566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
40179566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
40189566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
40199566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
40209566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
40219566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
402280677318SStefano Zampini       }
40239566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
402480677318SStefano Zampini     } else {
4025ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
4026ffd830a3SStefano Zampini         IS dummy;
4027ffd830a3SStefano Zampini 
40289566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &dummy));
40299566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(local_auxmat2_R, dummy, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
40309566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
4031ffd830a3SStefano Zampini       } else {
40329566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
403380677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
4034ffd830a3SStefano Zampini       }
40359566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
403680677318SStefano Zampini     }
40379566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
403880677318SStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
40399566063dSJacob Faibussowitsch     PetscCall(MatScale(M3, m_one));
404080677318SStefano Zampini     if (isCHOL) {
40419566063dSJacob Faibussowitsch       PetscCall(MatCholeskyFactor(M3, NULL, NULL));
404280677318SStefano Zampini     } else {
40439566063dSJacob Faibussowitsch       PetscCall(MatLUFactor(M3, NULL, NULL, NULL));
404480677318SStefano Zampini     }
40459566063dSJacob Faibussowitsch     PetscCall(MatSeqDenseInvertFactors_Private(M3));
404680677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
40479566063dSJacob Faibussowitsch     PetscCall(MatMatMult(M3, C_B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->local_auxmat1));
40489566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
40499566063dSJacob Faibussowitsch     PetscCall(MatCopy(M3, S_CC, SAME_NONZERO_PATTERN)); /* S_CC can have a different LDA, MatMatSolve doesn't support it */
40509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M3));
4051f4ddd8eeSStefano Zampini   }
4052fc227af8SStefano Zampini 
4053fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
405488ebb749SStefano Zampini   if (n_vertices) {
40557ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
40567ebab0bbSStefano Zampini     PetscBool oldpin;
40577ebab0bbSStefano Zampini #endif
40587ebab0bbSStefano Zampini     PetscBool isaij;
405906656605SStefano Zampini     IS        is_aux;
40603a50541eSStefano Zampini 
4061b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
40626816873aSStefano Zampini       IS tis;
40636816873aSStefano Zampini 
40649566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
40659566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
40669566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
40679566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
40686816873aSStefano Zampini     } else {
40699566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
40706816873aSStefano Zampini     }
40717ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4072b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
40737ebab0bbSStefano Zampini #endif
40749566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
40759566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
40769566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
40779566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A_VR, MATSEQAIJ, &isaij));
40787ebab0bbSStefano Zampini     if (!isaij) { /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
40799566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
40807ebab0bbSStefano Zampini     }
40819566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
40827ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
40839566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
40847ebab0bbSStefano Zampini #endif
40859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
408688ebb749SStefano Zampini   }
408788ebb749SStefano Zampini 
408888ebb749SStefano Zampini   /* Matrix of coarse basis functions (local) */
4089f4ddd8eeSStefano Zampini   if (pcbddc->coarse_phi_B) {
409006656605SStefano Zampini     PetscInt on_B, on_primal, on_D = n_D;
409148a46eb9SPierre Jolivet     if (pcbddc->coarse_phi_D) PetscCall(MatGetSize(pcbddc->coarse_phi_D, &on_D, NULL));
40929566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pcbddc->coarse_phi_B, &on_B, &on_primal));
409306656605SStefano Zampini     if (on_B != n_B || on_primal != pcbddc->local_primal_size || on_D != n_D) {
409406656605SStefano Zampini       PetscScalar *marray;
409506656605SStefano Zampini 
40969566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &marray));
40979566063dSJacob Faibussowitsch       PetscCall(PetscFree(marray));
40989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
40999566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
41009566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
41019566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
4102f4ddd8eeSStefano Zampini     }
4103f4ddd8eeSStefano Zampini   }
410406656605SStefano Zampini 
4105f4ddd8eeSStefano Zampini   if (!pcbddc->coarse_phi_B) {
4106a6e023c1Sstefano_zampini     PetscScalar *marr;
410788ebb749SStefano Zampini 
4108a6e023c1Sstefano_zampini     /* memory size */
410906656605SStefano Zampini     n = n_B * pcbddc->local_primal_size;
4110a6e023c1Sstefano_zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) n += n_D * pcbddc->local_primal_size;
4111a6e023c1Sstefano_zampini     if (!pcbddc->symmetric_primal) n *= 2;
41129566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &marr));
41139566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_B));
41148e3a54c0SPierre Jolivet     marr = PetscSafePointerPlusOffset(marr, n_B * pcbddc->local_primal_size);
41158eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
41169566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_D));
4117a6e023c1Sstefano_zampini       marr += n_D * pcbddc->local_primal_size;
411888ebb749SStefano Zampini     }
41193301b35fSStefano Zampini     if (!pcbddc->symmetric_primal) {
41209566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_B));
4121a6e023c1Sstefano_zampini       marr += n_B * pcbddc->local_primal_size;
412248a46eb9SPierre Jolivet       if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_D));
412388ebb749SStefano Zampini     } else {
41249566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
4125c0553b1fSStefano Zampini       pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
41261b968477SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
41279566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
4128c0553b1fSStefano Zampini         pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
4129c0553b1fSStefano Zampini       }
413088ebb749SStefano Zampini     }
413106656605SStefano Zampini   }
4132019a44ceSStefano Zampini 
413306656605SStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
41344f1b2e48SStefano Zampini   p0_lidx_I = NULL;
41354f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4136d12edf2fSStefano Zampini     const PetscInt *idxs;
4137d12edf2fSStefano Zampini 
41389566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
41399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
414048a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(PetscFindInt(pcbddc->benign_p0_lidx[i], pcis->n - pcis->n_B, idxs, &p0_lidx_I[i]));
41419566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4142d12edf2fSStefano Zampini   }
4143d16cbb6bSStefano Zampini 
414406656605SStefano Zampini   /* vertices */
414506656605SStefano Zampini   if (n_vertices) {
4146c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
414716f15bc4SStefano Zampini 
41489566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VV, MATDENSE, MAT_INPLACE_MATRIX, &A_VV));
414904708bb6SStefano Zampini 
415016f15bc4SStefano Zampini     if (n_R) {
415114393ed6SStefano Zampini       Mat                A_RRmA_RV, A_RV_bcorr = NULL, S_VVt; /* S_VVt with LDA=N */
415206656605SStefano Zampini       PetscBLASInt       B_N, B_one            = 1;
41531683a169SBarry Smith       const PetscScalar *x;
41541683a169SBarry Smith       PetscScalar       *y;
415506656605SStefano Zampini 
41569566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
415714393ed6SStefano Zampini       if (need_benign_correction) {
415814393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
415914393ed6SStefano Zampini         IS                     is_p0;
416014393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
416114393ed6SStefano Zampini 
41629566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
41639566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
41649566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
416563a3b9bcSJacob Faibussowitsch         PetscCheck(n == pcbddc->benign_n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error in R numbering for benign p0! %" PetscInt_FMT " != %" PetscInt_FMT, n, pcbddc->benign_n);
41669566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
41679566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
41689566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
41699566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
417014393ed6SStefano Zampini       }
417114393ed6SStefano Zampini 
41729566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work, &A_RRmA_RV));
4173c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
4174ffd830a3SStefano Zampini         if (lda_rhs == n_R) {
41759566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4176ffd830a3SStefano Zampini         } else {
4177ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4178ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4179ca92afb2SStefano Zampini           PetscInt        n;
4180ca92afb2SStefano Zampini           PetscBool       flg_row;
4181ffd830a3SStefano Zampini 
4182ca92afb2SStefano Zampini           array = work + lda_rhs * n_vertices;
41839566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(array, lda_rhs * n_vertices));
41849566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
41859566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
41869566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4187ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4188ca92afb2SStefano Zampini             PetscInt j;
4189ca92afb2SStefano Zampini             for (j = xadj[i]; j < xadj[i + 1]; j++) array[lda_rhs * adjncy[j] + i] = av[j];
4190ffd830a3SStefano Zampini           }
41919566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
41929566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
41939566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, array, &A_RV));
4194ffd830a3SStefano Zampini         }
4195a3df083aSStefano Zampini         if (need_benign_correction) {
4196df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4197a3df083aSStefano Zampini           PetscScalar       *marr;
4198a3df083aSStefano Zampini 
41999566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
420014393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
420114393ed6SStefano Zampini 
420214393ed6SStefano Zampini                  | 0 0  0 | (V)
420314393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
420414393ed6SStefano Zampini                  | 0 0 -1 | (p0)
420514393ed6SStefano Zampini 
420614393ed6SStefano Zampini           */
4207df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
420814393ed6SStefano Zampini             const PetscScalar *vals;
420914393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
421014393ed6SStefano Zampini             PetscInt           n, j, nz;
421114393ed6SStefano Zampini 
42129566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
42139566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
42149566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
421514393ed6SStefano Zampini             for (j = 0; j < n; j++) {
421614393ed6SStefano Zampini               PetscScalar val = vals[j];
421714393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
421814393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
421914393ed6SStefano Zampini             }
42209566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
42219566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
422214393ed6SStefano Zampini           }
42239566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
422472b8c272SStefano Zampini         }
42259566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4226c58f9fdbSStefano Zampini         Brhs = A_RV;
4227c58f9fdbSStefano Zampini       } else {
4228c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4229c58f9fdbSStefano Zampini 
4230c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4231fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
42329566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4233c58f9fdbSStefano Zampini         } else {
4234c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
42359566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
42369566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4237c58f9fdbSStefano Zampini           A_RVT = A_VR;
4238c58f9fdbSStefano Zampini         }
4239c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4240c58f9fdbSStefano Zampini           PetscScalar *aa;
4241c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4242c58f9fdbSStefano Zampini           PetscBool    done;
4243c58f9fdbSStefano Zampini 
42449566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
424528b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
42469566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
42479566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
42489566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
424928b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4250c58f9fdbSStefano Zampini         } else {
42519566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4252c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4253c58f9fdbSStefano Zampini         }
42549566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
42559566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
42569566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4257c58f9fdbSStefano Zampini       }
425872b8c272SStefano Zampini       if (F) {
425914393ed6SStefano Zampini         /* need to correct the rhs */
426072b8c272SStefano Zampini         if (need_benign_correction) {
426172b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
426272b8c272SStefano Zampini           PetscScalar       *marr;
426372b8c272SStefano Zampini 
42649566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
42655cbda25cSStefano Zampini           if (lda_rhs != n_R) {
42665cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42679566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
42689566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
42699566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
42705cbda25cSStefano Zampini             }
42715cbda25cSStefano Zampini           } else {
4272a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42739566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
42749566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
42759566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4276a3df083aSStefano Zampini             }
42775cbda25cSStefano Zampini           }
42789566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4279a3df083aSStefano Zampini         }
42809566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
42811baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
428214393ed6SStefano Zampini         /* need to correct the solution */
4283a3df083aSStefano Zampini         if (need_benign_correction) {
4284df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4285a3df083aSStefano Zampini           PetscScalar       *marr;
4286a3df083aSStefano Zampini 
42879566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
42885cbda25cSStefano Zampini           if (lda_rhs != n_R) {
42895cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42909566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
42919566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
42929566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
42935cbda25cSStefano Zampini             }
42945cbda25cSStefano Zampini           } else {
4295a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42969566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
42979566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
42989566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4299a3df083aSStefano Zampini             }
43005cbda25cSStefano Zampini           }
43019566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4302a3df083aSStefano Zampini         }
430306656605SStefano Zampini       } else {
43049566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(Brhs, &y));
430506656605SStefano Zampini         for (i = 0; i < n_vertices; i++) {
43069566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, y + i * lda_rhs));
43079566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * lda_rhs));
43089566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
43099566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
43109566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
43119566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
431206656605SStefano Zampini         }
43139566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(Brhs, &y));
431406656605SStefano Zampini       }
43159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
43169566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4317ffd830a3SStefano Zampini       /* S_VV and S_CV */
431806656605SStefano Zampini       if (n_constraints) {
431906656605SStefano Zampini         Mat B;
432080677318SStefano Zampini 
43219566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(work + lda_rhs * n_vertices, n_B * n_vertices));
432280677318SStefano Zampini         for (i = 0; i < n_vertices; i++) {
43239566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
43249566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcis->vec1_B, work + lda_rhs * n_vertices + i * n_B));
43259566063dSJacob Faibussowitsch           PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
43269566063dSJacob Faibussowitsch           PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
43279566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcis->vec1_B));
43289566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
432980677318SStefano Zampini         }
43309566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_vertices, work + lda_rhs * n_vertices, &B));
43314222ddf1SHong Zhang         /* Reuse dense S_C = pcbddc->local_auxmat1 * B */
43329566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(pcbddc->local_auxmat1, B, NULL, S_CV));
43339566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
43349566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
43359566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
43369566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
43379566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
43384222ddf1SHong Zhang 
43399566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
43409566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work + lda_rhs * n_vertices, &B));
43414222ddf1SHong Zhang         /* Reuse B = local_auxmat2_R * S_CV */
43429566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CV, NULL, B));
43439566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
43449566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
43459566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
43469566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
43474222ddf1SHong Zhang 
43489566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
43499566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(lda_rhs * n_vertices, &B_N));
4350792fecdfSBarry Smith         PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, work + lda_rhs * n_vertices, &B_one, work, &B_one));
43519566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
435206656605SStefano Zampini       }
4353ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
43549566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RRmA_RV));
43559566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, work, &A_RRmA_RV));
43569566063dSJacob Faibussowitsch         PetscCall(MatDenseSetLDA(A_RRmA_RV, lda_rhs));
4357ffd830a3SStefano Zampini       }
43589566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VVt));
435914393ed6SStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
436014393ed6SStefano Zampini       if (need_benign_correction) {
4361df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
436214393ed6SStefano Zampini         PetscScalar       *marr, *sums;
436314393ed6SStefano Zampini 
43649566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
43659566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(S_VVt, &marr));
4366df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
436714393ed6SStefano Zampini           const PetscScalar *vals;
436814393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
436914393ed6SStefano Zampini           PetscInt           n, j, nz;
437014393ed6SStefano Zampini 
43719566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
43729566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
437314393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
437414393ed6SStefano Zampini             PetscInt k;
437514393ed6SStefano Zampini             sums[j] = 0.;
437614393ed6SStefano Zampini             for (k = 0; k < nz; k++) sums[j] += work[idxs_zero[k] + j * lda_rhs];
437714393ed6SStefano Zampini           }
43789566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
437914393ed6SStefano Zampini           for (j = 0; j < n; j++) {
438014393ed6SStefano Zampini             PetscScalar val = vals[j];
438114393ed6SStefano Zampini             PetscInt    k;
4382ad540459SPierre Jolivet             for (k = 0; k < n_vertices; k++) marr[idxs[j] + k * n_vertices] += val * sums[k];
438314393ed6SStefano Zampini           }
43849566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
43859566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
438614393ed6SStefano Zampini         }
43879566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
43889566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(S_VVt, &marr));
43899566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
439014393ed6SStefano Zampini       }
43919566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RRmA_RV));
43929566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(n_vertices * n_vertices, &B_N));
43939566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(A_VV, &x));
43949566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(S_VVt, &y));
4395792fecdfSBarry Smith       PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, x, &B_one, y, &B_one));
43969566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(A_VV, &x));
43979566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(S_VVt, &y));
43989566063dSJacob Faibussowitsch       PetscCall(MatCopy(S_VVt, S_VV, SAME_NONZERO_PATTERN));
43999566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_VVt));
4400019a44ceSStefano Zampini     } else {
44019566063dSJacob Faibussowitsch       PetscCall(MatCopy(A_VV, S_VV, SAME_NONZERO_PATTERN));
4402d16cbb6bSStefano Zampini     }
44039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_VV));
4404d16cbb6bSStefano Zampini 
440506656605SStefano Zampini     /* coarse basis functions */
440606656605SStefano Zampini     for (i = 0; i < n_vertices; i++) {
4407ab2d12f3SJunchao Zhang       Vec         v;
4408ab2d12f3SJunchao Zhang       PetscScalar one = 1.0, zero = 0.0;
440916f15bc4SStefano Zampini 
44109566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
44119566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i, &v));
44129566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44139566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4414ab2d12f3SJunchao Zhang       if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4415ab2d12f3SJunchao Zhang         PetscMPIInt rank;
44169566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), &rank));
441708401ef6SPierre Jolivet         PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4418ab2d12f3SJunchao Zhang       }
44199566063dSJacob Faibussowitsch       PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
44209566063dSJacob Faibussowitsch       PetscCall(VecAssemblyBegin(v)); /* If v is on device, hope VecSetValues() eventually implemented by a host to device memcopy */
44219566063dSJacob Faibussowitsch       PetscCall(VecAssemblyEnd(v));
44229566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i, &v));
442306656605SStefano Zampini 
442406656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
44254f1b2e48SStefano Zampini         PetscInt j;
44264f1b2e48SStefano Zampini 
44279566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i, &v));
44289566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44299566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4430ab2d12f3SJunchao Zhang         if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4431ab2d12f3SJunchao Zhang           PetscMPIInt rank;
44329566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), &rank));
443308401ef6SPierre Jolivet           PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4434ab2d12f3SJunchao Zhang         }
44359566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
44369566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
44379566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
44389566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i, &v));
443906656605SStefano Zampini       }
44409566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
444106656605SStefano Zampini     }
444204708bb6SStefano Zampini     /* if n_R == 0 the object is not destroyed */
44439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_RV));
444406656605SStefano Zampini   }
44459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
444606656605SStefano Zampini 
444706656605SStefano Zampini   if (n_constraints) {
444806656605SStefano Zampini     Mat B;
444906656605SStefano Zampini 
44509566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &B));
44519566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
44529566063dSJacob Faibussowitsch     PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CC, NULL, B));
44539566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
44549566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
44559566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
44569566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
4457a961b312SStefano Zampini 
44589566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
445906656605SStefano Zampini     if (n_vertices) {
446003dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
44617fb60732SBarry Smith         PetscCall(MatTransposeSetPrecursor(S_CV, S_VC));
44629566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_CV, MAT_REUSE_MATRIX, &S_VC));
446380677318SStefano Zampini       } else {
446480677318SStefano Zampini         Mat S_VCt;
446580677318SStefano Zampini 
4466ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
44679566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&B));
44689566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_constraints, work, &B));
44699566063dSJacob Faibussowitsch           PetscCall(MatDenseSetLDA(B, lda_rhs));
4470ffd830a3SStefano Zampini         }
44719566063dSJacob Faibussowitsch         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VCt));
44729566063dSJacob Faibussowitsch         PetscCall(MatCopy(S_VCt, S_VC, SAME_NONZERO_PATTERN));
44739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCt));
447480677318SStefano Zampini       }
447506656605SStefano Zampini     }
44769566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
447706656605SStefano Zampini     /* coarse basis functions */
447806656605SStefano Zampini     for (i = 0; i < n_constraints; i++) {
4479ab2d12f3SJunchao Zhang       Vec v;
448006656605SStefano Zampini 
44819566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
44829566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
44839566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44849566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44859566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
448606656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
44874f1b2e48SStefano Zampini         PetscInt    j;
4488ab2d12f3SJunchao Zhang         PetscScalar zero = 0.0;
44899566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
44909566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44919566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44929566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
44939566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
44949566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
44959566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
449606656605SStefano Zampini       }
44979566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
449806656605SStefano Zampini     }
449906656605SStefano Zampini   }
450048a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&local_auxmat2_R));
45019566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
450272b8c272SStefano Zampini 
450372b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
450472b8c272SStefano Zampini   if (pcbddc->benign_n) {
450572b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
450672b8c272SStefano Zampini     IS                 is_dummy;
45071683a169SBarry Smith     const PetscScalar *data;
450872b8c272SStefano Zampini     PetscInt           j;
450972b8c272SStefano Zampini 
45109566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
45119566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
45129566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
45139566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
45149566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
45159566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
451672b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
451772b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
451872b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
451972b8c272SStefano Zampini         coarse_submat_vals[primal_idx * pcbddc->local_primal_size + i] = data[i * pcbddc->benign_n + j];
452072b8c272SStefano Zampini         coarse_submat_vals[i * pcbddc->local_primal_size + primal_idx] = data[i * pcbddc->benign_n + j];
452172b8c272SStefano Zampini       }
452272b8c272SStefano Zampini     }
45239566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
45249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
45259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
452672b8c272SStefano Zampini   }
4527019a44ceSStefano Zampini 
452806656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
45293301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
4530ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
4531ffd830a3SStefano Zampini     PetscScalar *marray;
453206656605SStefano Zampini 
453306656605SStefano Zampini     if (n_constraints) {
4534ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
453506656605SStefano Zampini 
45369566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
45379566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
45389566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_C));
45399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
454006656605SStefano Zampini       if (n_vertices) {
4541ffd830a3SStefano Zampini         Mat S_VCT;
454206656605SStefano Zampini 
45439566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
45449566063dSJacob Faibussowitsch         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_V));
45459566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
454606656605SStefano Zampini       }
45479566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
45485b782168SStefano Zampini     } else {
45499566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
455006656605SStefano Zampini     }
455116f15bc4SStefano Zampini     if (n_vertices && n_R) {
4552ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
4553ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
4554ffd830a3SStefano Zampini       PetscInt        n;
4555ffd830a3SStefano Zampini       PetscBool       flg_row;
455606656605SStefano Zampini 
4557ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
45589566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
45599566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
45609566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
45619566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4562ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
4563ffd830a3SStefano Zampini         PetscInt j;
4564ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
4565ffd830a3SStefano Zampini       }
45669566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
45679566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
45689566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
456906656605SStefano Zampini     }
457006656605SStefano Zampini 
4571ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
4572abc8f43dSstefano_zampini     if (n_vertices) {
45739566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4574ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
45759566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
45769566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
45779566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
45789566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
45799566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
45809566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
458106656605SStefano Zampini       }
45829566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
4583abc8f43dSstefano_zampini     }
45845b782168SStefano Zampini     if (B_C) {
45859566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
4586ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
45879566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
45889566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
45899566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
45909566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
45919566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
45929566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
459306656605SStefano Zampini       }
45949566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
45955b782168SStefano Zampini     }
459606656605SStefano Zampini     /* coarse basis functions */
459706656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
4598ab2d12f3SJunchao Zhang       Vec v;
459906656605SStefano Zampini 
46009566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
46019566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
46029566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
46039566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
460406656605SStefano Zampini       if (i < n_vertices) {
4605ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
46069566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
46079566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
46089566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
460906656605SStefano Zampini       }
46109566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
461106656605SStefano Zampini 
461206656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
46139566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
46149566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
46159566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
46169566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
461706656605SStefano Zampini       }
46189566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
461906656605SStefano Zampini     }
46209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
46219566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
462206656605SStefano Zampini   }
4623a6e023c1Sstefano_zampini 
4624d62866d3SStefano Zampini   /* free memory */
46259566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
46269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VV));
46279566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
46289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
46299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
46309566063dSJacob Faibussowitsch   PetscCall(PetscFree(work));
463148a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
463248a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
46339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
46348ead10e4SStefano Zampini 
4635da81f932SPierre Jolivet   /* Checking coarse_sub_mat and coarse basis functions */
463688ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
463788ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
4638d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
463988ebb749SStefano Zampini     Mat       coarse_sub_mat;
464025084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
464188ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
464288ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
464388ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
46448bec7fa6SStefano Zampini     Mat       C_B, CPHI;
46458bec7fa6SStefano Zampini     IS        is_dummy;
46468bec7fa6SStefano Zampini     Vec       mones;
464788ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
464888ebb749SStefano Zampini     PetscReal real_value;
464988ebb749SStefano Zampini 
4650a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
4651a3df083aSStefano Zampini       Mat A;
46529566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
46539566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
46549566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
46559566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
46569566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
46579566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
4658a3df083aSStefano Zampini     } else {
46599566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
46609566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
46619566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
46629566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
4663a3df083aSStefano Zampini     }
46649566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
46659566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
4666ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
46679566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
46689566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
466988ebb749SStefano Zampini     }
46709566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_sub_mat));
467188ebb749SStefano Zampini 
46729566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
46739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
46749566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
4675ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
46769566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46779566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
46789566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46799566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46809566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
46819566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46829566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46839566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
46849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46859566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46869566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
46879566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
468888ebb749SStefano Zampini     } else {
46899566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
46909566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
46919566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46929566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
46939566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46949566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46959566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
46969566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
469788ebb749SStefano Zampini     }
46989566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
46999566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
47009566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
47019566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
47024f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
4703fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
47041683a169SBarry Smith       const PetscScalar *data2;
47051683a169SBarry Smith       PetscScalar       *data;
47064f1b2e48SStefano Zampini       PetscInt           j;
4707d12edf2fSStefano Zampini 
47089566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
47099566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
47109566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
47119566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
47129566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
47139566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
47144f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
47154f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
4716d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
47174f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
47184f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
47194f1b2e48SStefano Zampini         }
4720d12edf2fSStefano Zampini       }
47219566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
47229566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
47239566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
47249566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
47259566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
4726d12edf2fSStefano Zampini     }
4727d12edf2fSStefano Zampini #if 0
4728d12edf2fSStefano Zampini   {
4729d12edf2fSStefano Zampini     PetscViewer viewer;
4730d12edf2fSStefano Zampini     char filename[256];
4731a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level));
47329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
47339566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
47349566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coarse_sub_mat,"computed"));
47359566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_sub_mat,viewer));
47369566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)TM1,"projected"));
47379566063dSJacob Faibussowitsch     PetscCall(MatView(TM1,viewer));
4738a7414863SStefano Zampini     if (pcbddc->coarse_phi_B) {
47399566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
47409566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
474172b8c272SStefano Zampini     }
4742ffd830a3SStefano Zampini     if (pcbddc->coarse_phi_D) {
47439566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
47449566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
4745ffd830a3SStefano Zampini     }
4746ffd830a3SStefano Zampini     if (pcbddc->coarse_psi_B) {
47479566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
47489566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
4749ffd830a3SStefano Zampini     }
475072b8c272SStefano Zampini     if (pcbddc->coarse_psi_D) {
47519566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
47529566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
4753ffd830a3SStefano Zampini     }
47549566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
47559566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->local_mat,viewer));
47569566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
47579566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
47589566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
47599566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_I_local,viewer));
47609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
47619566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_B_local,viewer));
47629566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
47639566063dSJacob Faibussowitsch     PetscCall(ISView(pcbddc->is_R_local,viewer));
4764cd791dc2SBarry Smith     PetscCall(PetscOptionsRestoreViewer(&viewer));
4765d12edf2fSStefano Zampini   }
4766d12edf2fSStefano Zampini #endif
47679566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, m_one, coarse_sub_mat, DIFFERENT_NONZERO_PATTERN));
47689566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
47699566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
477063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
47718bec7fa6SStefano Zampini 
47728bec7fa6SStefano Zampini     /* check constraints */
47739566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
47749566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
47754f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
47769566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
4777a00504b5SStefano Zampini     } else {
4778a00504b5SStefano Zampini       PetscScalar *data;
4779a00504b5SStefano Zampini       Mat          tmat;
47809566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
47819566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
47829566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
47839566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
47849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
4785a00504b5SStefano Zampini     }
47869566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
47879566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
47889566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
47899566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
479063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
4791ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
47929566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
47939566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
47949566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
47959566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
479663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
479788ebb749SStefano Zampini     }
47989566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
47999566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
48009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
48019566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
48029566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
48039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
48049566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
48059566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
48069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
48079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
48089566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
48099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
48109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
48119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
48129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
4813ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
48149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
48159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
481688ebb749SStefano Zampini     }
48179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_sub_mat));
481888ebb749SStefano Zampini   }
48197ebab0bbSStefano Zampini   /* FINAL CUDA support (we cannot currently mix viennacl and cuda vectors */
48207ebab0bbSStefano Zampini   {
48217ebab0bbSStefano Zampini     PetscBool gpu;
48227ebab0bbSStefano Zampini 
48239566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcis->vec1_N, VECSEQCUDA, &gpu));
48247ebab0bbSStefano Zampini     if (gpu) {
482548a46eb9SPierre Jolivet       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
482648a46eb9SPierre Jolivet       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
482748a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
482848a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
482948a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
483048a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
48317ebab0bbSStefano Zampini     }
48327ebab0bbSStefano Zampini   }
48338629588bSStefano Zampini   /* get back data */
48348629588bSStefano Zampini   *coarse_submat_vals_n = coarse_submat_vals;
48353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
483688ebb749SStefano Zampini }
483788ebb749SStefano Zampini 
4838d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B)
4839d71ae5a4SJacob Faibussowitsch {
4840d65f70fdSStefano Zampini   Mat      *work_mat;
4841d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
4842d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
4843c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
4844aa0d41d4SStefano Zampini 
4845aa0d41d4SStefano Zampini   PetscFunctionBegin;
48469566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
48479566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
48489566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
48499566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
4850aa0d41d4SStefano Zampini 
4851d65f70fdSStefano Zampini   if (!rsorted) {
4852906d46d4SStefano Zampini     const PetscInt *idxs;
4853906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
4854aa0d41d4SStefano Zampini 
48559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
48569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
4857ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_perm_r[i] = i;
48589566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
48599566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
4860ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_sorted[i] = idxs[idxs_perm_r[i]];
48619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
48629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
4863d65f70fdSStefano Zampini   } else {
48649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
4865d65f70fdSStefano Zampini     isrow_s = isrow;
4866aa0d41d4SStefano Zampini   }
4867906d46d4SStefano Zampini 
4868d65f70fdSStefano Zampini   if (!csorted) {
4869d65f70fdSStefano Zampini     if (isrow == iscol) {
48709566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
4871d65f70fdSStefano Zampini       iscol_s = isrow_s;
4872d65f70fdSStefano Zampini     } else {
4873d65f70fdSStefano Zampini       const PetscInt *idxs;
4874d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
4875906d46d4SStefano Zampini 
48769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
48779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
4878ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_perm_c[i] = i;
48799566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
48809566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
4881ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_sorted[i] = idxs[idxs_perm_c[i]];
48829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
48839566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
4884d65f70fdSStefano Zampini     }
4885d65f70fdSStefano Zampini   } else {
48869566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
4887d65f70fdSStefano Zampini     iscol_s = iscol;
4888d65f70fdSStefano Zampini   }
4889d65f70fdSStefano Zampini 
48909566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
4891d65f70fdSStefano Zampini 
4892d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
4893906d46d4SStefano Zampini     Mat new_mat;
4894d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
4895906d46d4SStefano Zampini 
4896d65f70fdSStefano Zampini     if (!rsorted) {
4897d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
48989566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
4899ad540459SPierre Jolivet       for (i = 0; i < rsize; i++) idxs_r[idxs_perm_r[i]] = i;
49009566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
49019566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
4902d65f70fdSStefano Zampini     } else {
49039566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
4904906d46d4SStefano Zampini     }
49059566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
4906d65f70fdSStefano Zampini 
4907d65f70fdSStefano Zampini     if (!csorted) {
4908d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
49099566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
4910d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
4911d65f70fdSStefano Zampini       } else {
4912d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
491328b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
49149566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
4915ad540459SPierre Jolivet         for (i = 0; i < csize; i++) idxs_c[idxs_perm_c[i]] = i;
49169566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
49179566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
4918d65f70fdSStefano Zampini       }
4919d65f70fdSStefano Zampini     } else {
49209566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
4921d65f70fdSStefano Zampini     }
49229566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
4923d65f70fdSStefano Zampini 
49249566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
49259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
4926d65f70fdSStefano Zampini     work_mat[0] = new_mat;
49279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
49289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
4929d65f70fdSStefano Zampini   }
4930d65f70fdSStefano Zampini 
49319566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
4932d65f70fdSStefano Zampini   *B = work_mat[0];
49339566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
49349566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
49359566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
49363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4937d65f70fdSStefano Zampini }
4938d65f70fdSStefano Zampini 
4939d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
4940d71ae5a4SJacob Faibussowitsch {
4941aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
49425e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
4943022d8d2bSstefano_zampini   Mat       new_mat, lA;
49445e8657edSStefano Zampini   IS        is_local, is_global;
4945d65f70fdSStefano Zampini   PetscInt  local_size;
4946b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
4947aa0d41d4SStefano Zampini 
4948aa0d41d4SStefano Zampini   PetscFunctionBegin;
49499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
49509566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
49519566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
49529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
49539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_local));
49549566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
49559566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_global));
4956906d46d4SStefano Zampini 
4957906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
4958906d46d4SStefano Zampini     Vec       x, x_change;
4959906d46d4SStefano Zampini     PetscReal error;
4960906d46d4SStefano Zampini 
49619566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
49629566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
49639566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
49649566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
49659566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
49669566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
496788428137SStefano Zampini     if (!pcbddc->change_interior) {
496888428137SStefano Zampini       const PetscScalar *x, *y, *v;
496988428137SStefano Zampini       PetscReal          lerror = 0.;
497088428137SStefano Zampini       PetscInt           i;
497188428137SStefano Zampini 
49729566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
49739566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
49749566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
497588428137SStefano Zampini       for (i = 0; i < local_size; i++)
49769371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
49779566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
49789566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
49799566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
49801c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
4981637e8532SStefano Zampini       if (error > PETSC_SMALL) {
4982637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
498363a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
4984637e8532SStefano Zampini         } else {
498563a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
4986637e8532SStefano Zampini         }
4987637e8532SStefano Zampini       }
498888428137SStefano Zampini     }
49899566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
49909566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
49919566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
49929566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
4993637e8532SStefano Zampini     if (error > PETSC_SMALL) {
4994637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
499563a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
4996637e8532SStefano Zampini       } else {
499763a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
4998637e8532SStefano Zampini       }
4999637e8532SStefano Zampini     }
50009566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
50019566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
5002906d46d4SStefano Zampini   }
5003906d46d4SStefano Zampini 
5004022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
50059566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
5006022d8d2bSstefano_zampini 
500722d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
50089566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
500922d5777bSStefano Zampini   if (isseqaij) {
50109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
50119566063dSJacob Faibussowitsch     PetscCall(MatPtAP(matis->A, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
5012022d8d2bSstefano_zampini     if (lA) {
5013022d8d2bSstefano_zampini       Mat work;
50149566063dSJacob Faibussowitsch       PetscCall(MatPtAP(lA, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
50159566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
50169566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5017022d8d2bSstefano_zampini     }
5018aa0d41d4SStefano Zampini   } else {
5019a00504b5SStefano Zampini     Mat work_mat;
50201cf9b237SStefano Zampini 
50219566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
50229566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
50239566063dSJacob Faibussowitsch     PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
50249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
5025022d8d2bSstefano_zampini     if (lA) {
5026022d8d2bSstefano_zampini       Mat work;
50279566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
50289566063dSJacob Faibussowitsch       PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
50299566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
50309566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5031022d8d2bSstefano_zampini     }
5032aa0d41d4SStefano Zampini   }
5033b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
5034b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
50359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
50363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5037aa0d41d4SStefano Zampini }
5038aa0d41d4SStefano Zampini 
5039d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
5040d71ae5a4SJacob Faibussowitsch {
5041*f4f49eeaSPierre Jolivet   PC_IS          *pcis        = (PC_IS *)pc->data;
5042a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
5043d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
504453892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
50453a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
50463a50541eSStefano Zampini   PetscInt        vbs, bs;
50476816873aSStefano Zampini   PetscBT         bitmask = NULL;
5048a64d13efSStefano Zampini 
5049a64d13efSStefano Zampini   PetscFunctionBegin;
5050b23d619eSStefano Zampini   /*
5051b23d619eSStefano Zampini     No need to setup local scatters if
5052b23d619eSStefano Zampini       - primal space is unchanged
5053b23d619eSStefano Zampini         AND
5054b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
5055b23d619eSStefano Zampini         AND
5056b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
5057b23d619eSStefano Zampini   */
50583ba16761SJacob Faibussowitsch   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) PetscFunctionReturn(PETSC_SUCCESS);
5059f4ddd8eeSStefano Zampini   /* destroy old objects */
50609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
50619566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
50629566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
5063a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
5064b371cd4fSStefano Zampini   n_B        = pcis->n_B;
5065b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
5066b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
50673a50541eSStefano Zampini 
5068e602f447SPierre Jolivet   /* Dohrmann's notation: dofs split in R (Remaining: all dofs but the vertices) and V (Vertices) */
50696816873aSStefano Zampini 
507053892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
5071b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
50729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
50739566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
507448a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
50754641a718SStefano Zampini 
5076a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
5077ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, i)) idx_R_local[n_R++] = i;
5078a64d13efSStefano Zampini     }
5079df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5080df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
50816816873aSStefano Zampini 
50829566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
50839566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
50846816873aSStefano Zampini   }
50853a50541eSStefano Zampini 
50863a50541eSStefano Zampini   /* Block code */
50873a50541eSStefano Zampini   vbs = 1;
50889566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
50893a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
50903a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
50913a50541eSStefano Zampini     PetscInt *vary;
5092b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
50939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
50949566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
5095d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5096d3df7717SStefano Zampini       /* 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 */
50970e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5098d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
50993a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
51003a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
51013a50541eSStefano Zampini           break;
51023a50541eSStefano Zampini         }
51033a50541eSStefano Zampini       }
51049566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5105d3df7717SStefano Zampini     } else {
5106d3df7717SStefano Zampini       /* Verify directly the R set */
5107d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5108d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5109d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5110d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5111d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5112d3df7717SStefano Zampini             break;
5113d3df7717SStefano Zampini           }
5114d3df7717SStefano Zampini         }
5115d3df7717SStefano Zampini       }
5116d3df7717SStefano Zampini     }
51173a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
51183a50541eSStefano Zampini       vbs = bs;
5119ad540459SPierre Jolivet       for (i = 0; i < n_R / vbs; i++) idx_R_local[i] = idx_R_local[vbs * i] / vbs;
51203a50541eSStefano Zampini     }
51213a50541eSStefano Zampini   }
51229566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5123b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5124df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
512553892102SStefano Zampini 
51269566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
51279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
51289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5129df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
513053892102SStefano Zampini   } else {
51319566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
513253892102SStefano Zampini   }
5133a64d13efSStefano Zampini 
5134a64d13efSStefano Zampini   /* print some info if requested */
5135a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
51369566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
51379566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
51389566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
51399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
514063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "local_size = %" PetscInt_FMT ", dirichlet_size = %" PetscInt_FMT ", boundary_size = %" PetscInt_FMT "\n", pcis->n, n_D, n_B));
51419371c9d4SSatish Balay     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "r_size = %" PetscInt_FMT ", v_size = %" PetscInt_FMT ", constraints = %" PetscInt_FMT ", local_primal_size = %" PetscInt_FMT "\n", n_R, n_vertices,
51429371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
51439566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5144a64d13efSStefano Zampini   }
5145a64d13efSStefano Zampini 
5146a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5147b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
51486816873aSStefano Zampini     IS        is_aux1, is_aux2;
51496816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
51506816873aSStefano Zampini 
51519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
51529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
51539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
51549566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
515548a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
51569566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5157a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
5158ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5159a64d13efSStefano Zampini     }
51609566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
51619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5162a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
5163ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, is_indices[i])) aux_array2[j++] = i;
5164a64d13efSStefano Zampini     }
51659566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
51669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
51679566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
51689566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
51699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5170a64d13efSStefano Zampini 
51718eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
51729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5173a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
5174ad540459SPierre Jolivet         if (PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5175a64d13efSStefano Zampini       }
51769566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
51779566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
51789566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5179a64d13efSStefano Zampini     }
51809566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
51819566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5182d62866d3SStefano Zampini   } else {
5183df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
51846816873aSStefano Zampini     IS                 tis;
51856816873aSStefano Zampini     PetscInt           schur_size;
51866816873aSStefano Zampini 
51879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
51889566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
51899566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
51909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
51916816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
51929566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
51939566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
51949566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5195d62866d3SStefano Zampini     }
5196d62866d3SStefano Zampini   }
51973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5198a64d13efSStefano Zampini }
5199a64d13efSStefano Zampini 
5200d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B)
5201d71ae5a4SJacob Faibussowitsch {
520292cccca0SStefano Zampini   MatNullSpace   NullSpace;
520392cccca0SStefano Zampini   Mat            dmat;
520492cccca0SStefano Zampini   const Vec     *nullvecs;
520592cccca0SStefano Zampini   Vec            v, v2, *nullvecs2;
52066d9e27e4SStefano Zampini   VecScatter     sct = NULL;
5207eb06acf8SStefano Zampini   PetscContainer c;
5208eb06acf8SStefano Zampini   PetscScalar   *ddata;
5209295df10fSStefano Zampini   PetscInt       k, nnsp_size, bsiz, bsiz2, n, N, bs;
521092cccca0SStefano Zampini   PetscBool      nnsp_has_cnst;
521192cccca0SStefano Zampini 
521292cccca0SStefano Zampini   PetscFunctionBegin;
52136d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
52146d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
52156d9e27e4SStefano Zampini 
521648a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
52176d9e27e4SStefano Zampini     sct = matis->cctx;
52189566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
52196d9e27e4SStefano Zampini   } else {
52209566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
522148a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
52223ba16761SJacob Faibussowitsch     if (NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
52236d9e27e4SStefano Zampini   }
52249566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
522548a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
52263ba16761SJacob Faibussowitsch   if (!NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
52276d9e27e4SStefano Zampini 
52289566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
52299566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
523048a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
52319566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, (const Vec **)&nullvecs));
5232295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
52339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
52349566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
52359566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
52369566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
52379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
523892cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
52399566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
52409566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
52419566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
524292cccca0SStefano Zampini   }
524392cccca0SStefano Zampini   if (nnsp_has_cnst) {
52449566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
52459566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
524692cccca0SStefano Zampini   }
52479566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
52489566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5249295df10fSStefano Zampini 
52509566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
52519566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)B), &c));
52529566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ddata));
52539566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
52549566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", (PetscObject)c));
52559566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
52569566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
52579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5258eb06acf8SStefano Zampini 
525948a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
52609566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
52619566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
52629566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
52639566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
52649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
52659566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
52663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
526792cccca0SStefano Zampini }
5268304d26faSStefano Zampini 
5269d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5270d71ae5a4SJacob Faibussowitsch {
5271304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5272304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5273304d26faSStefano Zampini   PC           pc_temp;
5274304d26faSStefano Zampini   Mat          A_RR;
527592cccca0SStefano Zampini   MatNullSpace nnsp;
5276f4ddd8eeSStefano Zampini   MatReuse     reuse;
5277304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5278304d26faSStefano Zampini   PetscReal    value;
527904708bb6SStefano Zampini   PetscInt     n_D, n_R;
5280b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
52810a545947SLisandro Dalcin   void (*f)(void) = NULL;
5282312be037SStefano Zampini   char   dir_prefix[256], neu_prefix[256], str_level[16];
5283e604994aSStefano Zampini   size_t len;
5284304d26faSStefano Zampini 
5285304d26faSStefano Zampini   PetscFunctionBegin;
52869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
52876d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
52886d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
52896d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
52906d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
52916d9e27e4SStefano Zampini 
52929566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
52939566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
52949566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
52956d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
52961c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lhas, &ghas, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
529748a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
52986d9e27e4SStefano Zampini   }
52996d9e27e4SStefano Zampini 
5300e604994aSStefano Zampini   /* compute prefixes */
5301c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(dir_prefix, "", sizeof(dir_prefix)));
5302c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(neu_prefix, "", sizeof(neu_prefix)));
5303e604994aSStefano Zampini   if (!pcbddc->current_level) {
53049566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
53059566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
53069566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
53079566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5308e604994aSStefano Zampini   } else {
5309*f4f49eeaSPierre Jolivet     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)pcbddc->current_level));
53109566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
5311e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
5312312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
5313312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
5314a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
53159566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
53169566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
53179566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
53189566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
53199566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
53209566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
5321e604994aSStefano Zampini   }
5322e604994aSStefano Zampini 
5323304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
5324684f6988SStefano Zampini   if (dirichlet) {
5325d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5326450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
53277827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
5328450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
5329a3df083aSStefano Zampini         Mat A_IIn;
5330a3df083aSStefano Zampini 
53319566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
53329566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
5333a3df083aSStefano Zampini         pcis->A_II = A_IIn;
5334a3df083aSStefano Zampini       }
5335450f8f5eSStefano Zampini     }
5336b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5337b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
5338b94d7dedSBarry Smith 
5339ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
5340964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
534192cccca0SStefano Zampini     opts = PETSC_FALSE;
5342304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
534392cccca0SStefano Zampini       opts = PETSC_TRUE;
53449566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
53453821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_D, pc->kspnestlevel));
53469566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
5347304d26faSStefano Zampini       /* default */
53489566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
53499566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
53509566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
53519566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
53529577ea80SStefano Zampini       if (issbaij) {
53539566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
53549577ea80SStefano Zampini       } else {
53559566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
53569577ea80SStefano Zampini       }
53579566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
535892cccca0SStefano Zampini     }
53599566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
53609566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
5361304d26faSStefano Zampini     /* Allow user's customization */
53621baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
53639566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
53646d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
53659566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
536692cccca0SStefano Zampini     }
53679566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
53689566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
53699566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
537092cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5371cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5372cd18cfedSStefano Zampini       const PetscInt *idxs;
5373cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5374cd18cfedSStefano Zampini 
53759566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
53769566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
53779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5378cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5379ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5380cd18cfedSStefano Zampini       }
53819566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
53829566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
53839566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5384cd18cfedSStefano Zampini     }
5385b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
5386df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5387d62866d3SStefano Zampini 
53889566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
5389d5574798SStefano Zampini     }
539092cccca0SStefano Zampini 
5391304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5392304d26faSStefano Zampini     if (!n_D) {
53939566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
53949566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5395304d26faSStefano Zampini     }
53969566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
5397304d26faSStefano Zampini     /* set ksp_D into pcis data */
53989566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
53999566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
5400304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
5401684f6988SStefano Zampini   }
5402304d26faSStefano Zampini 
5403304d26faSStefano Zampini   /* NEUMANN PROBLEM */
54040a545947SLisandro Dalcin   A_RR = NULL;
5405684f6988SStefano Zampini   if (neumann) {
5406d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
540704708bb6SStefano Zampini     PetscInt        ibs, mbs;
5408b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
540904708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
54100aa714b2SStefano Zampini 
54110aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
54120aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
54130aa714b2SStefano Zampini       IS iP;
54140aa714b2SStefano Zampini 
54150aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
54169566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
54170aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
54180aa714b2SStefano Zampini     }
5419f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
54209566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
5421f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
5422f4ddd8eeSStefano Zampini       PetscInt nn_R;
54239566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
54249566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
54259566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
5426f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
54279566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
54289566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5429f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5430f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5431727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
54329566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
5433f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
5434f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
5435f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
5436f4ddd8eeSStefano Zampini         }
5437f4ddd8eeSStefano Zampini       }
5438f4ddd8eeSStefano Zampini       /* last check */
5439d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
54409566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5441f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5442f4ddd8eeSStefano Zampini       }
5443f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
5444f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
5445f4ddd8eeSStefano Zampini     }
5446365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
5447365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
54489566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
54499566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
54509566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
545104708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
545204708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
54539566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
54549566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
5455af732b37SStefano Zampini       } else {
54569566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
54576816873aSStefano Zampini       }
54584cf0e950SBarry Smith     } else if (issbaij) { /* need to convert to BAIJ to get off-diagonal blocks */
545904708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
54609566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
54619566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
546204708bb6SStefano Zampini       } else {
54639566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
546404708bb6SStefano Zampini       }
546504708bb6SStefano Zampini     }
5466a00504b5SStefano Zampini     /* extract A_RR */
54670aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5468a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5469a00504b5SStefano Zampini 
5470a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
54719566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5472a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
54739566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
547416e386b8SStefano Zampini         } else {
54759566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
5476a00504b5SStefano Zampini         }
5477a00504b5SStefano Zampini       } else {
54789566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
54799566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
54809566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
5481a00504b5SStefano Zampini       }
5482a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
54839566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
548416e386b8SStefano Zampini     }
5485b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5486b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
548792cccca0SStefano Zampini     opts = PETSC_FALSE;
5488f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
548992cccca0SStefano Zampini       opts = PETSC_TRUE;
54909566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
54913821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_R, pc->kspnestlevel));
54929566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
5493304d26faSStefano Zampini       /* default */
54949566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
54959566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
54969566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54979566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
54989577ea80SStefano Zampini       if (issbaij) {
54999566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
55009577ea80SStefano Zampini       } else {
55019566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
55029577ea80SStefano Zampini       }
55039566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
550492cccca0SStefano Zampini     }
55059566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
55069566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
550792cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
55089566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
550992cccca0SStefano Zampini     }
55109566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
55116d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
55129566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
551392cccca0SStefano Zampini     }
55149566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
55159566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
55169566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
551792cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5518cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5519cd18cfedSStefano Zampini       const PetscInt *idxs;
5520cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5521cd18cfedSStefano Zampini 
55229566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
55239566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
55249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5525cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5526ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5527cd18cfedSStefano Zampini       }
55289566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
55299566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
55309566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5531cd18cfedSStefano Zampini     }
553292cccca0SStefano Zampini 
5533304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5534304d26faSStefano Zampini     if (!n_R) {
55359566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
55369566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5537304d26faSStefano Zampini     }
5538df4d28bfSStefano Zampini     /* Reuse solver if it is present */
55390aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5540df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5541d62866d3SStefano Zampini 
55429566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
5543d62866d3SStefano Zampini     }
55449566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
5545684f6988SStefano Zampini   }
5546304d26faSStefano Zampini 
5547684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
55489566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
55499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
55509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
5551684f6988SStefano Zampini   }
55529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
5553c7017625SStefano Zampini 
5554c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
555548a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
555648a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
555748a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
5558c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
5559c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
5560684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
55619566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
55629566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
55639566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
55649566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
55659566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
55669566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
5567*f4f49eeaSPierre Jolivet       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Dirichlet solve (%s) = % 1.14e \n", PetscGlobalRank, ((PetscObject)pcbddc->ksp_D)->prefix, (double)value));
55689566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5569304d26faSStefano Zampini     }
5570684f6988SStefano Zampini     if (neumann) { /* Neumann */
55719566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
55729566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
55739566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
55749566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
55759566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
55769566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
5577*f4f49eeaSPierre Jolivet       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Neumann solve (%s) = % 1.14e\n", PetscGlobalRank, ((PetscObject)pcbddc->ksp_R)->prefix, (double)value));
55789566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5579304d26faSStefano Zampini     }
5580684f6988SStefano Zampini   }
55815cbda25cSStefano Zampini   /* free Neumann problem's matrix */
55829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
55833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5584304d26faSStefano Zampini }
5585304d26faSStefano Zampini 
5586d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
5587d71ae5a4SJacob Faibussowitsch {
5588*f4f49eeaSPierre Jolivet   PC_BDDC        *pcbddc       = (PC_BDDC *)pc->data;
5589be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
5590b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
5591674ae819SStefano Zampini 
5592674ae819SStefano Zampini   PetscFunctionBegin;
559348a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
559480677318SStefano Zampini   if (!pcbddc->switch_static) {
559580677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
55969566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
55979566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
559820c7b377SStefano Zampini     }
5599b334f244SStefano Zampini     if (!reuse_solver) {
56009566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
56019566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
560220c7b377SStefano Zampini     } else {
5603df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5604be83ff47SStefano Zampini 
56059566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
56069566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
560720c7b377SStefano Zampini     }
5608be83ff47SStefano Zampini   } else {
56099566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
56109566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
56119566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
56129566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
561380677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
56149566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
56159566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
56169566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
56179566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
5618674ae819SStefano Zampini     }
5619674ae819SStefano Zampini   }
56209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
5621b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
562280677318SStefano Zampini     if (applytranspose) {
56239566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
562480677318SStefano Zampini     } else {
56259566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
562680677318SStefano Zampini     }
56279566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
5628be83ff47SStefano Zampini   } else {
5629df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5630be83ff47SStefano Zampini 
5631be83ff47SStefano Zampini     if (applytranspose) {
56329566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5633be83ff47SStefano Zampini     } else {
56349566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5635be83ff47SStefano Zampini     }
5636be83ff47SStefano Zampini   }
56379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
56389566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
563980677318SStefano Zampini   if (!pcbddc->switch_static) {
5640b334f244SStefano Zampini     if (!reuse_solver) {
56419566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
56429566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
5643be83ff47SStefano Zampini     } else {
5644df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5645be83ff47SStefano Zampini 
56469566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
56479566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
5648be83ff47SStefano Zampini     }
564980677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
56509566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
56519566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
565280677318SStefano Zampini     }
565380677318SStefano Zampini   } else {
56549566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
56559566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
56569566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
56579566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
565880677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
56599566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
56609566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
566180677318SStefano Zampini     }
56629566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
56639566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
56649566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
56659566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
5666674ae819SStefano Zampini   }
56673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5668674ae819SStefano Zampini }
5669674ae819SStefano Zampini 
5670dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
5671d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
5672d71ae5a4SJacob Faibussowitsch {
5673*f4f49eeaSPierre Jolivet   PC_BDDC          *pcbddc = (PC_BDDC *)pc->data;
5674*f4f49eeaSPierre Jolivet   PC_IS            *pcis   = (PC_IS *)pc->data;
5675674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
5676674ae819SStefano Zampini 
5677674ae819SStefano Zampini   PetscFunctionBegin;
5678dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
56794fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5680dc359a40SStefano Zampini     if (applytranspose) {
56819566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
56829566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
5683dc359a40SStefano Zampini     } else {
56849566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
56859566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
568615aaf578SStefano Zampini     }
56874fee134fSStefano Zampini   } else {
56889566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
56894fee134fSStefano Zampini   }
5690efc2fbd9SStefano Zampini 
5691efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
56924f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
5693efc2fbd9SStefano Zampini     PetscScalar *array;
56944f1b2e48SStefano Zampini     PetscInt     j;
5695efc2fbd9SStefano Zampini 
56969566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
56974f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
56989566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5699efc2fbd9SStefano Zampini   }
5700efc2fbd9SStefano Zampini 
570112edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
57029566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
57039566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
57049566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
570512edc857SStefano Zampini 
57069f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
5707a1cb837bSStefano Zampini   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
570812edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
570951694757SStefano Zampini     Mat          coarse_mat;
5710964fefecSStefano Zampini     Vec          rhs, sol;
571151694757SStefano Zampini     MatNullSpace nullsp;
571227b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
5713964fefecSStefano Zampini 
571427b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
571527b6a85dSStefano Zampini       PC coarse_pc;
571627b6a85dSStefano Zampini 
57179566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
57189566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
571927b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
572027b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
5721*f4f49eeaSPierre Jolivet         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)coarse_pc->data;
572227b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
57233bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
572427b6a85dSStefano Zampini       }
572527b6a85dSStefano Zampini     }
57269566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
57279566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
57289566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
572912edc857SStefano Zampini     if (applytranspose) {
573028b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
57319566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
57329566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
57339566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
57341baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
57352701bc32SStefano Zampini     } else {
57369566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
57371f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
57382701bc32SStefano Zampini         PC coarse_pc;
57392701bc32SStefano Zampini 
57401baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
57419566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
57429566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
57439566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
57449566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
574512edc857SStefano Zampini       } else {
57469566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
57479566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
57481baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
574912edc857SStefano Zampini       }
57502701bc32SStefano Zampini     }
57511d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
575227b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
575327b6a85dSStefano Zampini       PC       coarse_pc;
575427b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
575527b6a85dSStefano Zampini 
57569566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
5757*f4f49eeaSPierre Jolivet       coarsepcbddc                           = (PC_BDDC *)coarse_pc->data;
575827b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
57593bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
576027b6a85dSStefano Zampini     }
576112edc857SStefano Zampini   }
5762a1cb837bSStefano Zampini   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
5763674ae819SStefano Zampini 
5764674ae819SStefano Zampini   /* Local solution on R nodes */
5765a1cb837bSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
57669f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
57679566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
57689566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
5769674ae819SStefano Zampini 
57704fee134fSStefano Zampini   /* Sum contributions from the two levels */
57714fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5772dc359a40SStefano Zampini     if (applytranspose) {
57739566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
57749566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5775dc359a40SStefano Zampini     } else {
57769566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
57779566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5778dc359a40SStefano Zampini     }
5779efc2fbd9SStefano Zampini     /* store p0 */
57804f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5781efc2fbd9SStefano Zampini       PetscScalar *array;
57824f1b2e48SStefano Zampini       PetscInt     j;
5783efc2fbd9SStefano Zampini 
57849566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
57854f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
57869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5787efc2fbd9SStefano Zampini     }
57884fee134fSStefano Zampini   } else { /* expand the coarse solution */
57894fee134fSStefano Zampini     if (applytranspose) {
57909566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
57914fee134fSStefano Zampini     } else {
57929566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
57934fee134fSStefano Zampini     }
57944fee134fSStefano Zampini   }
57953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5796674ae819SStefano Zampini }
5797674ae819SStefano Zampini 
5798d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode)
5799d71ae5a4SJacob Faibussowitsch {
5800*f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
580112edc857SStefano Zampini   Vec                from, to;
58027ebab0bbSStefano Zampini   const PetscScalar *array;
5803674ae819SStefano Zampini 
5804674ae819SStefano Zampini   PetscFunctionBegin;
580512edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
580612edc857SStefano Zampini     from = pcbddc->coarse_vec;
580712edc857SStefano Zampini     to   = pcbddc->vec1_P;
580812edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
580912edc857SStefano Zampini       Vec tvec;
581058da7f69SStefano Zampini 
58119566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
58129566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
58139566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
58149566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
58159566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
58169566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
581712edc857SStefano Zampini     }
581812edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
581912edc857SStefano Zampini     from = pcbddc->vec1_P;
582012edc857SStefano Zampini     to   = pcbddc->coarse_vec;
582112edc857SStefano Zampini   }
58229566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
58233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5824674ae819SStefano Zampini }
5825674ae819SStefano Zampini 
5826d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
5827d71ae5a4SJacob Faibussowitsch {
5828*f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
582912edc857SStefano Zampini   Vec                from, to;
58307ebab0bbSStefano Zampini   const PetscScalar *array;
5831674ae819SStefano Zampini 
5832674ae819SStefano Zampini   PetscFunctionBegin;
583312edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
583412edc857SStefano Zampini     from = pcbddc->coarse_vec;
583512edc857SStefano Zampini     to   = pcbddc->vec1_P;
583612edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
583712edc857SStefano Zampini     from = pcbddc->vec1_P;
583812edc857SStefano Zampini     to   = pcbddc->coarse_vec;
583912edc857SStefano Zampini   }
58409566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
584112edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
584212edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
584312edc857SStefano Zampini       Vec tvec;
584458da7f69SStefano Zampini 
58459566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
58469566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
58479566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
58489566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
584958da7f69SStefano Zampini     }
585058da7f69SStefano Zampini   } else {
585158da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
58529566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
585312edc857SStefano Zampini     }
585412edc857SStefano Zampini   }
58553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5856674ae819SStefano Zampini }
5857674ae819SStefano Zampini 
5858d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
5859d71ae5a4SJacob Faibussowitsch {
5860*f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
5861674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
5862674ae819SStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
5863984c4197SStefano Zampini   /* one and zero */
5864984c4197SStefano Zampini   PetscScalar one = 1.0, zero = 0.0;
5865984c4197SStefano Zampini   /* space to store constraints and their local indices */
58669162d606SStefano Zampini   PetscScalar *constraints_data;
58679162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
58689162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
58699162d606SStefano Zampini   PetscInt    *constraints_n;
5870984c4197SStefano Zampini   /* iterators */
5871b3d85658SStefano Zampini   PetscInt i, j, k, total_counts, total_counts_cc, cum;
5872984c4197SStefano Zampini   /* BLAS integers */
5873e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
5874e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
5875c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
5876727cdba6SStefano Zampini   /* reuse */
58770e6343abSStefano Zampini   PetscInt  olocal_primal_size, olocal_primal_size_cc;
58780e6343abSStefano Zampini   PetscInt *olocal_primal_ref_node, *olocal_primal_ref_mult;
5879984c4197SStefano Zampini   /* change of basis */
5880b3d85658SStefano Zampini   PetscBool qr_needed;
58819162d606SStefano Zampini   PetscBT   change_basis, qr_needed_idx;
5882984c4197SStefano Zampini   /* auxiliary stuff */
588364efe560SStefano Zampini   PetscInt *nnz, *is_indices;
58848a0068c3SStefano Zampini   PetscInt  ncc;
5885984c4197SStefano Zampini   /* some quantities */
588645a1bb75SStefano Zampini   PetscInt  n_vertices, total_primal_vertices, valid_constraints;
5887a58a30b4SStefano Zampini   PetscInt  size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
588857715f18SStefano Zampini   PetscReal tol; /* tolerance for retaining eigenmodes */
5889984c4197SStefano Zampini 
5890674ae819SStefano Zampini   PetscFunctionBegin;
589157715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
58928e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
58939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
58949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
58959566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
5896088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
5897088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
58980e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
58999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
59009566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
59019566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
59029566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
59039566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
5904cf5a6209SStefano Zampini 
5905cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
59069162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
5907cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
5908cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
5909cf5a6209SStefano Zampini     Vec         *localnearnullsp;
5910cf5a6209SStefano Zampini     PetscScalar *array;
591132fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
5912cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
5913674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
5914b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
5915674ae819SStefano Zampini     PetscScalar *work;
5916674ae819SStefano Zampini     PetscReal   *singular_vals;
5917674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
5918674ae819SStefano Zampini     PetscReal *rwork;
5919674ae819SStefano Zampini #endif
592055080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
5921964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
5922964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
592355080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
5924674ae819SStefano Zampini 
592555080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
5926b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
592755080a34SStefano Zampini     use_pod = PETSC_TRUE;
592855080a34SStefano Zampini #endif
5929674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
59309566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
593132fe681dSStefano Zampini     o_nf       = n_ISForFaces;
593232fe681dSStefano Zampini     o_ne       = n_ISForEdges;
593332fe681dSStefano Zampini     n_vertices = 0;
593432fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
5935e4d548c7SStefano Zampini     /* print some info */
59365c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
593732fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
59389566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
59399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
59409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
594132fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
594263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
594363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
59449566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
59459566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
5946e4d548c7SStefano Zampini     }
5947e4d548c7SStefano Zampini 
594832fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
594932fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
595032fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
595170022509SStefano Zampini 
5952674ae819SStefano Zampini     /* check if near null space is attached to global mat */
59536d9e27e4SStefano Zampini     if (pcbddc->use_nnsp) {
59549566063dSJacob Faibussowitsch       PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
59556d9e27e4SStefano Zampini     } else nearnullsp = NULL;
59566d9e27e4SStefano Zampini 
5957674ae819SStefano Zampini     if (nearnullsp) {
59589566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
5959f4ddd8eeSStefano Zampini       /* remove any stored info */
59609566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
59619566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
5962f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
59639566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
5964f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
59659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
596648a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
5967984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
5968984c4197SStefano Zampini       nnsp_size     = 0;
5969674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
5970674ae819SStefano Zampini     }
5971984c4197SStefano Zampini     /* get max number of constraints on a single cc */
5972984c4197SStefano Zampini     max_constraints = nnsp_size;
5973984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
5974984c4197SStefano Zampini 
5975674ae819SStefano Zampini     /*
5976674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
59779162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
59789162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
59799162d606SStefano Zampini          There can be multiple constraints per connected component
5980674ae819SStefano Zampini                                                                                                                                                            */
59819162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
59829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
59839162d606SStefano Zampini 
59849162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
59859162d606SStefano Zampini     total_counts *= max_constraints;
5986674ae819SStefano Zampini     total_counts += n_vertices;
59879566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
59889162d606SStefano Zampini 
5989674ae819SStefano Zampini     total_counts           = 0;
5990674ae819SStefano Zampini     max_size_of_constraint = 0;
5991674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
59929162d606SStefano Zampini       IS used_is;
5993674ae819SStefano Zampini       if (i < n_ISForEdges) {
59949162d606SStefano Zampini         used_is = ISForEdges[i];
5995674ae819SStefano Zampini       } else {
59969162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
5997674ae819SStefano Zampini       }
59989566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
5999674ae819SStefano Zampini       total_counts += j;
6000674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
6001674ae819SStefano Zampini     }
60029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
60039162d606SStefano Zampini 
6004984c4197SStefano Zampini     /* get local part of global near null space vectors */
60059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
6006984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
60079566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
60089566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
60099566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
6010984c4197SStefano Zampini     }
6011674ae819SStefano Zampini 
6012242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
6013242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
6014a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
6015242a89d7SStefano Zampini 
6016984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
6017a773dcb8SStefano Zampini     if (!skip_lapack) {
6018674ae819SStefano Zampini       PetscScalar temp_work;
6019911cabfeSStefano Zampini 
602055080a34SStefano Zampini       if (use_pod) {
6021984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
60229566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
60239566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
60249566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
6025674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
60269566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
6027674ae819SStefano Zampini #endif
6028674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
60299566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
60309566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
6031674ae819SStefano Zampini         lwork = -1;
60329566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6033674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6034792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
6035674ae819SStefano Zampini #else
6036792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
6037674ae819SStefano Zampini #endif
60389566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
603928b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %d", (int)lierr);
604055080a34SStefano Zampini       } else {
604155080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
6042674ae819SStefano Zampini         /* SVD */
6043674ae819SStefano Zampini         PetscInt max_n, min_n;
6044674ae819SStefano Zampini         max_n = max_size_of_constraint;
6045984c4197SStefano Zampini         min_n = max_constraints;
6046984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
6047674ae819SStefano Zampini           min_n = max_size_of_constraint;
6048984c4197SStefano Zampini           max_n = max_constraints;
6049674ae819SStefano Zampini         }
60509566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
6051674ae819SStefano Zampini   #if defined(PETSC_USE_COMPLEX)
60529566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
6053674ae819SStefano Zampini   #endif
6054674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
6055674ae819SStefano Zampini         lwork = -1;
60569566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
60579566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
60589566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
60599566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6060674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6061792fecdfSBarry Smith         PetscCallBLAS("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));
6062674ae819SStefano Zampini   #else
6063792fecdfSBarry Smith         PetscCallBLAS("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));
6064674ae819SStefano Zampini   #endif
60659566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
606628b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %d", (int)lierr);
606755080a34SStefano Zampini #else
606855080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6069984c4197SStefano Zampini #endif /* on missing GESVD */
607055080a34SStefano Zampini       }
6071674ae819SStefano Zampini       /* Allocate optimal workspace */
60729566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
60739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
6074674ae819SStefano Zampini     }
6075674ae819SStefano Zampini     /* Now we can loop on constraining sets */
6076674ae819SStefano Zampini     total_counts            = 0;
60779162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
60789162d606SStefano Zampini     constraints_data_ptr[0] = 0;
6079674ae819SStefano Zampini     /* vertices */
60809162d606SStefano Zampini     if (n_vertices) {
60819566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
60829566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
6083674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
60849162d606SStefano Zampini         constraints_n[total_counts]            = 1;
60859162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
60869162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
60879162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
6088674ae819SStefano Zampini         total_counts++;
6089674ae819SStefano Zampini       }
60909566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
6091674ae819SStefano Zampini     }
6092984c4197SStefano Zampini 
6093674ae819SStefano Zampini     /* edges and faces */
60949162d606SStefano Zampini     total_counts_cc = total_counts;
6095911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
60969162d606SStefano Zampini       IS        used_is;
60979162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
60989162d606SStefano Zampini 
6099911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
61009162d606SStefano Zampini         used_is       = ISForEdges[ncc];
6101984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
6102674ae819SStefano Zampini       } else {
61039162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6104984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6105674ae819SStefano Zampini       }
6106674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
61079162d606SStefano Zampini 
61089566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
610932fe681dSStefano Zampini       if (!size_of_constraint) continue;
61109566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6111984c4197SStefano Zampini       /* change of basis should not be performed on local periodic nodes */
6112984c4197SStefano Zampini       if (pcbddc->mat_graph->mirrors && pcbddc->mat_graph->mirrors[is_indices[0]]) boolforchange = PETSC_FALSE;
6113674ae819SStefano Zampini       if (nnsp_has_cnst) {
61145b08dc53SStefano Zampini         PetscScalar quad_value;
61159162d606SStefano Zampini 
61169566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
61179162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
61189162d606SStefano Zampini 
6119a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6120674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6121a773dcb8SStefano Zampini         } else {
6122a773dcb8SStefano Zampini           quad_value = 1.0;
6123a773dcb8SStefano Zampini         }
6124ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value;
61259162d606SStefano Zampini         temp_constraints++;
6126674ae819SStefano Zampini         total_counts++;
6127674ae819SStefano Zampini       }
6128674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6129984c4197SStefano Zampini         PetscReal    real_value;
61309162d606SStefano Zampini         PetscScalar *ptr_to_data;
61319162d606SStefano Zampini 
61329566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
61339162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
6134ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) ptr_to_data[j] = array[is_indices[j]];
61359566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6136984c4197SStefano Zampini         /* check if array is null on the connected component */
61379566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6138792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
613957715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6140674ae819SStefano Zampini           temp_constraints++;
6141674ae819SStefano Zampini           total_counts++;
61429162d606SStefano Zampini           if (!idxs_copied) {
61439566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
61449162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6145674ae819SStefano Zampini           }
6146674ae819SStefano Zampini         }
61479162d606SStefano Zampini       }
61489566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
614945a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6150eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6151a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
61529162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
61539162d606SStefano Zampini 
61549162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
61559566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6156792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6157a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6158792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6159a773dcb8SStefano Zampini         } else { /* perform SVD */
61609162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6161674ae819SStefano Zampini 
616255080a34SStefano Zampini           if (use_pod) {
6163984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6164984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6165984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6166984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6167984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6168984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6169984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
61709566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6171674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
61729566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
61739566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6174674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
617548a46eb9SPierre Jolivet               for (k = 0; k < j + 1; k++) PetscCallBLAS("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));
6176674ae819SStefano Zampini             }
6177e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
61789566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61799566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6180674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6181792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6182674ae819SStefano Zampini #else
6183792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6184674ae819SStefano Zampini #endif
61859566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
618628b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %d", (int)lierr);
6187984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6188674ae819SStefano Zampini             j = 0;
618987b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6190674ae819SStefano Zampini             total_counts      = total_counts - j;
619145a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6192e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
61939566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
61949566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61959566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
61969566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
61979566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
61989566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6199674ae819SStefano Zampini             if (j < temp_constraints) {
6200984c4197SStefano Zampini               PetscInt ii;
6201984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
62029566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6203792fecdfSBarry Smith               PetscCallBLAS("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));
62049566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6205984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
6206ad540459SPierre Jolivet                 for (ii = 0; ii < size_of_constraint; ii++) ptr_to_data[k * size_of_constraint + ii] = singular_vals[temp_constraints - 1 - k] * temp_basis[(temp_constraints - 1 - k) * size_of_constraint + ii];
6207674ae819SStefano Zampini               }
6208674ae819SStefano Zampini             }
620955080a34SStefano Zampini           } else {
621055080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
62119566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
62129566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
62139566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
62149566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6215674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6216792fecdfSBarry Smith             PetscCallBLAS("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));
6217674ae819SStefano Zampini   #else
6218792fecdfSBarry Smith             PetscCallBLAS("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));
6219674ae819SStefano Zampini   #endif
622028b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
62219566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6222984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6223e310c8b4SStefano Zampini             k = temp_constraints;
6224e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6225674ae819SStefano Zampini             j = 0;
622687b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
622745a1bb75SStefano Zampini             valid_constraints = k - j;
6228911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
622955080a34SStefano Zampini #else
623055080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6231984c4197SStefano Zampini #endif /* on missing GESVD */
6232674ae819SStefano Zampini           }
6233a773dcb8SStefano Zampini         }
623455080a34SStefano Zampini       }
62359162d606SStefano Zampini       /* update pointers information */
62369162d606SStefano Zampini       if (valid_constraints) {
62379162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
62389162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
62399162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
62409162d606SStefano Zampini         /* set change_of_basis flag */
62413ba16761SJacob Faibussowitsch         if (boolforchange) PetscCall(PetscBTSet(change_basis, total_counts_cc));
6242b3d85658SStefano Zampini         total_counts_cc++;
624345a1bb75SStefano Zampini       }
624445a1bb75SStefano Zampini     }
6245984c4197SStefano Zampini     /* free workspace */
62468f1c130eSStefano Zampini     if (!skip_lapack) {
62479566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6248984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
62499566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6250984c4197SStefano Zampini #endif
62519566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
62529566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
62539566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6254984c4197SStefano Zampini     }
625548a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
62569566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6257cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
625832fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
625908122e43SStefano Zampini   } else {
626008122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6261984c4197SStefano Zampini 
626208122e43SStefano Zampini     total_counts = 0;
626308122e43SStefano Zampini     n_vertices   = 0;
626448a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
626508122e43SStefano Zampini     max_constraints = 0;
62669162d606SStefano Zampini     total_counts_cc = 0;
626708122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
626808122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
62699162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
627008122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
627108122e43SStefano Zampini     }
62729162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
62739162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
62749162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
62759162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
627674d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
62779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
62789162d606SStefano Zampini     total_counts_cc = 0;
62799162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
6280ad540459SPierre Jolivet       if (pcbddc->adaptive_constraints_n[i]) constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
628108122e43SStefano Zampini     }
628208122e43SStefano Zampini 
62838bec7fa6SStefano Zampini     max_size_of_constraint = 0;
62849162d606SStefano Zampini     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]);
62859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
628608122e43SStefano Zampini     /* Change of basis */
62879566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
628808122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
628908122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
629048a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
629108122e43SStefano Zampini       }
629208122e43SStefano Zampini     }
629308122e43SStefano Zampini   }
6294984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
62959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
629608122e43SStefano Zampini 
62979162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
629832fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
62999566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
630063a3b9bcSJacob Faibussowitsch     PetscCheck(i == constraints_idxs_ptr[total_counts_cc], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error in boundary numbering for constraints indices %" PetscInt_FMT " != %" PetscInt_FMT, constraints_idxs_ptr[total_counts_cc], i);
630132fe681dSStefano Zampini   }
6302674ae819SStefano Zampini 
6303674ae819SStefano Zampini   /* Create constraint matrix */
63049566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
63059566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
63069566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6307984c4197SStefano Zampini 
6308984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6309a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
63105a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
63119566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
6312984c4197SStefano Zampini   total_primal_vertices        = 0;
6313b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
63149162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
63159162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
631672b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
63179162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6318b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
631964efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
6320ad540459SPierre Jolivet       for (k = 0; k < constraints_n[i]; k++) pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k];
6321b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
632291af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
63233ba16761SJacob Faibussowitsch         PetscCall(PetscBTSet(qr_needed_idx, i));
6324a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
6325a717540cSStefano Zampini       }
6326fa434743SStefano Zampini     } else {
6327b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
6328fa434743SStefano Zampini     }
6329a717540cSStefano Zampini   }
6330b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6331b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
6332674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
63339566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
63349566063dSJacob Faibussowitsch   PetscCall(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));
63359566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
63360e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
6337984c4197SStefano Zampini 
6338984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
633974d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
63409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
6341984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
634274d5cdf7SStefano Zampini 
6343984c4197SStefano Zampini   j            = total_primal_vertices;
634474d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
6345b3d85658SStefano Zampini   cum          = total_primal_vertices;
63469162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
63474641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
6348b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6349b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6350b3d85658SStefano Zampini       cum++;
63519162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
635274d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
635374d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
635474d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
635574d5cdf7SStefano Zampini       }
63569162d606SStefano Zampini       j += constraints_n[i];
6357674ae819SStefano Zampini     }
6358674ae819SStefano Zampini   }
63599566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
63609566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
63619566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
6362088faed8SStefano Zampini 
6363674ae819SStefano Zampini   /* set values in constraint matrix */
636448a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
6365984c4197SStefano Zampini   total_counts = total_primal_vertices;
63669162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
63674641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
63689162d606SStefano Zampini       PetscInt *cols;
63699162d606SStefano Zampini 
63709162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
63719162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
63729162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
63739162d606SStefano Zampini         PetscInt     row = total_counts + k;
63749162d606SStefano Zampini         PetscScalar *vals;
63759162d606SStefano Zampini 
63769162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
63779566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
63789162d606SStefano Zampini       }
63799162d606SStefano Zampini       total_counts += constraints_n[i];
6380674ae819SStefano Zampini     }
6381674ae819SStefano Zampini   }
6382674ae819SStefano Zampini   /* assembling */
63839566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
63849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
63859566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
6386088faed8SStefano Zampini 
6387674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6388674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
6389026de310SStefano Zampini     /* dual and primal dofs on a single cc */
6390984c4197SStefano Zampini     PetscInt dual_dofs, primal_dofs;
6391984c4197SStefano Zampini     /* working stuff for GEQRF */
63925a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
6393984c4197SStefano Zampini     PetscBLASInt lqr_work;
6394984c4197SStefano Zampini     /* working stuff for UNGQR */
63953c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
6396984c4197SStefano Zampini     PetscBLASInt lgqr_work;
6397984c4197SStefano Zampini     /* working stuff for TRTRS */
63985a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
63993f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
6400984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
6401984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
6402984c4197SStefano Zampini     PetscScalar *start_vals;
6403984c4197SStefano Zampini     /* working stuff for values insertion */
64044641a718SStefano Zampini     PetscBT   is_primal;
640564efe560SStefano Zampini     PetscInt *aux_primal_numbering_B;
6406906d46d4SStefano Zampini     /* matrix sizes */
6407906d46d4SStefano Zampini     PetscInt global_size, local_size;
6408906d46d4SStefano Zampini     /* temporary change of basis */
6409906d46d4SStefano Zampini     Mat localChangeOfBasisMatrix;
6410cf5a6209SStefano Zampini     /* extra space for debugging */
64115a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
6412984c4197SStefano Zampini 
64139566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
64149566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
64159566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
6416906d46d4SStefano Zampini     /* nonzeros for local mat */
64179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
64181dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6419bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
64201dd7afcfSStefano Zampini     } else {
64211dd7afcfSStefano Zampini       const PetscInt *ii;
64221dd7afcfSStefano Zampini       PetscInt        n;
64231dd7afcfSStefano Zampini       PetscBool       flg_row;
64249566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
64251dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
64269566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
64271dd7afcfSStefano Zampini     }
64289162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
6429a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
64309162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
6431a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
64329162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
6433a717540cSStefano Zampini         } else {
64349162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
64359162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
6436a717540cSStefano Zampini         }
6437a717540cSStefano Zampini       }
6438a717540cSStefano Zampini     }
64399566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
64409566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
64419566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
64421dd7afcfSStefano Zampini     /* Set interior change in the matrix */
64431dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
644448a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
64451dd7afcfSStefano Zampini     } else {
64461dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
64471dd7afcfSStefano Zampini       PetscScalar    *aa;
64481dd7afcfSStefano Zampini       PetscInt        n;
64491dd7afcfSStefano Zampini       PetscBool       flg_row;
64509566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
64519566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
645248a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValues(localChangeOfBasisMatrix, 1, &i, ii[i + 1] - ii[i], jj + ii[i], aa + ii[i], INSERT_VALUES));
64539566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
64549566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
64551dd7afcfSStefano Zampini     }
6456a717540cSStefano Zampini 
6457a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
64589566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
64599566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
6460a717540cSStefano Zampini     }
6461a717540cSStefano Zampini 
6462a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
6463a717540cSStefano Zampini     /*
6464a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
6465a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
6466a717540cSStefano Zampini 
64677c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
6468a717540cSStefano Zampini 
64697c625d9fSStefano Zampini           - By using the following block transformation if there is only a primal dof on the cc (and -pc_bddc_use_qr_single is not specified)
6470a6b551f4SStefano Zampini 
6471a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
6472a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
6473a717540cSStefano Zampini             |              ...                        |
6474a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
6475a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
6476a717540cSStefano Zampini 
6477a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
6478a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
6479a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
6480a6b551f4SStefano Zampini 
6481a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
6482a717540cSStefano Zampini     */
64835a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
6484984c4197SStefano Zampini       /* space to store Q */
64859566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
64864e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
64879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
6488984c4197SStefano Zampini       /* first we issue queries for optimal work */
64899566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
64909566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
64919566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
6492984c4197SStefano Zampini       lqr_work = -1;
6493792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
649428b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %d", (int)lierr);
64959566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
649659b05608SBarry Smith       PetscCall(PetscMalloc1(lqr_work, &qr_work));
6497984c4197SStefano Zampini       lgqr_work = -1;
64989566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
64999566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
65009566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
65019566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
65023f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
6503792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
650428b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %d", (int)lierr);
65059566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
650659b05608SBarry Smith       PetscCall(PetscMalloc1(lgqr_work, &gqr_work));
6507984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
65089566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
6509a717540cSStefano Zampini       /* allocating workspace for check */
651048a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
6511a717540cSStefano Zampini     }
6512984c4197SStefano Zampini     /* array to store whether a node is primal or not */
65139566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
65149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
65159566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
651663a3b9bcSJacob Faibussowitsch     PetscCheck(i == total_primal_vertices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error in boundary numbering for BDDC vertices! %" PetscInt_FMT " != %" PetscInt_FMT, total_primal_vertices, i);
651748a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
65189566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
6519984c4197SStefano Zampini 
6520a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
65219162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
65229162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
65234641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
6524984c4197SStefano Zampini         /* get constraint info */
65259162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
6526984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
6527984c4197SStefano Zampini 
652848a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Constraints %" PetscInt_FMT ": %" PetscInt_FMT " need a change of basis (size %" PetscInt_FMT ")\n", total_counts, primal_dofs, size_of_constraint));
6529984c4197SStefano Zampini 
6530fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
6531a717540cSStefano Zampini 
6532a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
653348a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6534984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
65359566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6536984c4197SStefano Zampini 
6537984c4197SStefano Zampini           /* compute QR decomposition of constraints */
65389566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
65399566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
65409566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65419566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6542792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
654328b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %d", (int)lierr);
65449566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6545984c4197SStefano Zampini 
6546a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
65479566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
6548984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
65499566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
65509566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
65519566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65529566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
65539566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6554792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
655528b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %d", (int)lierr);
65569566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6557984c4197SStefano Zampini 
6558a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
65599566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
65609566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
65619566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
65629566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65639566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6564792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
656528b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %d", (int)lierr);
65669566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6567984c4197SStefano Zampini 
6568984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
6569984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
6570984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
65719566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
65729566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
65739566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
65749566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65759566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
65769566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
65779566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6578792fecdfSBarry Smith           PetscCallBLAS("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));
65799566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
65809566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6581984c4197SStefano Zampini 
6582984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
65839162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
6584984c4197SStefano Zampini           /* insert cols for primal dofs */
6585984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
6586984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
65879162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
65889566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6589984c4197SStefano Zampini           }
6590984c4197SStefano Zampini           /* insert cols for dual dofs */
6591984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
65929162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
6593984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
65949162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
65959566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6596984c4197SStefano Zampini               j++;
6597674ae819SStefano Zampini             }
6598674ae819SStefano Zampini           }
6599984c4197SStefano Zampini 
6600984c4197SStefano Zampini           /* check change of basis */
6601984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
6602984c4197SStefano Zampini             PetscInt  ii, jj;
6603984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
66049566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
66059566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
66069566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
66079566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
66089566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
66099566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
66109566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6611792fecdfSBarry Smith             PetscCallBLAS("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));
66129566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6613984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
6614984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
6615cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
6616c068d9bbSLisandro Dalcin                 if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) valid_qr = PETSC_FALSE;
6617674ae819SStefano Zampini               }
6618674ae819SStefano Zampini             }
6619984c4197SStefano Zampini             if (!valid_qr) {
66209566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
6621984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
6622984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
6623cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
662463a3b9bcSJacob Faibussowitsch                     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\tQr basis function %" PetscInt_FMT " is not orthogonal to constraint %" PetscInt_FMT " (%1.14e)!\n", jj, ii, (double)PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii])));
6625674ae819SStefano Zampini                   }
6626c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
662763a3b9bcSJacob Faibussowitsch                     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\tQr basis function %" PetscInt_FMT " is not unitary w.r.t constraint %" PetscInt_FMT " (%1.14e)!\n", jj, ii, (double)PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii])));
6628984c4197SStefano Zampini                   }
6629984c4197SStefano Zampini                 }
6630984c4197SStefano Zampini               }
6631674ae819SStefano Zampini             } else {
66329566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
6633674ae819SStefano Zampini             }
6634674ae819SStefano Zampini           }
6635a717540cSStefano Zampini         } else { /* simple transformation block */
6636a717540cSStefano Zampini           PetscInt    row, col;
6637a6b551f4SStefano Zampini           PetscScalar val, norm;
6638a6b551f4SStefano Zampini 
66399566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6640792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, constraints_data + constraints_data_ptr[total_counts], &Blas_one, constraints_data + constraints_data_ptr[total_counts], &Blas_one));
6641a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
66429162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
66439162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
6644bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
66459162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
66469566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
66479566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
6648a717540cSStefano Zampini             } else {
6649a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
66509162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
6651a717540cSStefano Zampini                 if (row != col) {
66529162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
6653a717540cSStefano Zampini                 } else {
66549162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
6655a717540cSStefano Zampini                 }
66569566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
6657a717540cSStefano Zampini               }
6658a717540cSStefano Zampini             }
6659a717540cSStefano Zampini           }
666048a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
6661a717540cSStefano Zampini         }
6662984c4197SStefano Zampini       } else {
666348a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Constraint %" PetscInt_FMT " does not need a change of basis (size %" PetscInt_FMT ")\n", total_counts, size_of_constraint));
6664674ae819SStefano Zampini       }
6665674ae819SStefano Zampini     }
6666a717540cSStefano Zampini 
6667a717540cSStefano Zampini     /* free workspace */
6668a717540cSStefano Zampini     if (qr_needed) {
66691baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
66709566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
66719566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
66729566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
66739566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
66749566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
6675674ae819SStefano Zampini     }
66769566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
66779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
66789566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
6679906d46d4SStefano Zampini 
6680906d46d4SStefano Zampini     /* assembling of global change of variable */
668188c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
6682bbb9e6c6SStefano Zampini       Mat      tmat;
668316f15bc4SStefano Zampini       PetscInt bs;
668416f15bc4SStefano Zampini 
66859566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
66869566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
66879566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
66889566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
66899566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
66909566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
66919566063dSJacob Faibussowitsch       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->ChangeOfBasisMatrix));
66929566063dSJacob Faibussowitsch       PetscCall(MatSetType(pcbddc->ChangeOfBasisMatrix, MATAIJ));
66939566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(pc->pmat, &bs));
66949566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(pcbddc->ChangeOfBasisMatrix, bs));
66959566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(pcbddc->ChangeOfBasisMatrix, local_size, local_size, global_size, global_size));
66969566063dSJacob Faibussowitsch       PetscCall(MatISSetMPIXAIJPreallocation_Private(tmat, pcbddc->ChangeOfBasisMatrix, PETSC_TRUE));
66979566063dSJacob Faibussowitsch       PetscCall(MatConvert(tmat, MATAIJ, MAT_REUSE_MATRIX, &pcbddc->ChangeOfBasisMatrix));
66989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
66999566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
67009566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
67019566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
67029566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
67039566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
67049566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
670588c03ad3SStefano Zampini 
6706906d46d4SStefano Zampini       /* check */
6707906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
6708906d46d4SStefano Zampini         PetscReal error;
6709906d46d4SStefano Zampini         Vec       x, x_change;
6710906d46d4SStefano Zampini 
67119566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
67129566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
67139566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
67149566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
67159566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
67169566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
67179566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
67189566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
67199566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
67209566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
67219566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
67229566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
6723049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
67249566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
67259566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
6726906d46d4SStefano Zampini       }
6727b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
6728b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
6729b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6730bf3a8328SStefano Zampini 
673108401ef6SPierre Jolivet         PetscCheck(!pcbddc->use_change_of_basis || !pcbddc->adaptive_userdefined, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot mix automatic change of basis, adaptive selection and user-defined constraints");
6732b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
6733ac632422SStefano Zampini           Mat S_new, tmat;
6734bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
6735bbb9e6c6SStefano Zampini 
67369566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
67379566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
6738bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6739bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
6740bf3a8328SStefano Zampini             IS                     is_V;
67419566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
67429566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
67439566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
67449566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
67459566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
6746bf3a8328SStefano Zampini           }
67479566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
67489566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
67499566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
67509566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
6751bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6752bf3a8328SStefano Zampini             const PetscScalar *array;
6753bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
6754bf3a8328SStefano Zampini             PetscInt           i, n_V;
6755bf3a8328SStefano Zampini 
67569566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
67579566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
67589566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
67599566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
67609566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
6761b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
6762b087196eSStefano Zampini               PetscScalar val;
6763b087196eSStefano Zampini               PetscInt    idx;
6764b087196eSStefano Zampini 
6765b087196eSStefano Zampini               idx = idxs_V[i];
6766b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
67679566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
6768b087196eSStefano Zampini             }
67699566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
67709566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
67719566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
67729566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
67739566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
6774bf3a8328SStefano Zampini           }
6775ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
67769566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
6777ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
67789566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
67799566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
67809566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
67811baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
6782ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
67839566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
6784ac632422SStefano Zampini           }
67859566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
67869566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
6787b96c3477SStefano Zampini         }
6788c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
6789b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
6790c9db6a07SStefano Zampini           PetscInt i;
6791c9db6a07SStefano Zampini 
679248a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
67939566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
6794c9db6a07SStefano Zampini         }
6795b96c3477SStefano Zampini       }
679616909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
679716909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
679816909a7fSStefano Zampini       } else {
67999566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
680016909a7fSStefano Zampini       }
68011dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
680227b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
680372b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
68049566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
680572b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
680672b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
680772b8c272SStefano Zampini     }
68081dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
680927b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
68109566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
6811b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
6812906d46d4SStefano Zampini     } else {
68131dd7afcfSStefano Zampini       Mat benign_global = NULL;
681427b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
68151dd7afcfSStefano Zampini         Mat M;
68161dd7afcfSStefano Zampini 
68179e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
68189566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
68199566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
68209566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
68219e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
68229566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
68239566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
6824906d46d4SStefano Zampini         } else {
68259566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
68269566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
6827906d46d4SStefano Zampini         }
68289566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
68299566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
68309566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
68319566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
68321dd7afcfSStefano Zampini       }
68331dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
68349566063dSJacob Faibussowitsch         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->ChangeOfBasisMatrix));
68359566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
683627b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
68371dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
68381dd7afcfSStefano Zampini       }
68391dd7afcfSStefano Zampini     }
684016909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
684116909a7fSStefano Zampini       IS              is_global;
684216909a7fSStefano Zampini       const PetscInt *gidxs;
684316909a7fSStefano Zampini 
68449566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
68459566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
68469566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
68479566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
68489566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
684916909a7fSStefano Zampini     }
68501dd7afcfSStefano Zampini   }
685148a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
6852a717540cSStefano Zampini 
685372b8c272SStefano Zampini   if (!pcbddc->fake_change) {
68544f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
68554f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
68564f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
68574f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
6858019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
6859019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
6860019a44ceSStefano Zampini       pcbddc->local_primal_size++;
6861019a44ceSStefano Zampini     }
6862019a44ceSStefano Zampini 
6863019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
6864727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
6865727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
68669566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6867c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
68680e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
68699566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6870727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
6871727cdba6SStefano Zampini       }
68720e6343abSStefano Zampini     }
6873727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
68741c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
687572b8c272SStefano Zampini   }
68769566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
6877727cdba6SStefano Zampini 
6878a717540cSStefano Zampini   /* flush dbg viewer */
68791baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6880a717540cSStefano Zampini 
6881e310c8b4SStefano Zampini   /* free workspace */
68829566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
68839566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
688408122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
68859566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
68869566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
688708122e43SStefano Zampini   } else {
6888d0609cedSBarry Smith     PetscCall(PetscFree5(pcbddc->adaptive_constraints_n, pcbddc->adaptive_constraints_idxs_ptr, pcbddc->adaptive_constraints_data_ptr, pcbddc->adaptive_constraints_idxs, pcbddc->adaptive_constraints_data));
68899566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
68909566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
689108122e43SStefano Zampini   }
68923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6893674ae819SStefano Zampini }
6894674ae819SStefano Zampini 
6895d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
6896d71ae5a4SJacob Faibussowitsch {
689771582508SStefano Zampini   ISLocalToGlobalMapping map;
6898674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
6899674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
690066da6bd7Sstefano_zampini   PetscInt               i, N;
690166da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
6902674ae819SStefano Zampini 
6903674ae819SStefano Zampini   PetscFunctionBegin;
69048af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
6905b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
69068e61c736SStefano Zampini     /* Reset previously computed graph */
69079566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
6908674ae819SStefano Zampini     /* Init local Graph struct */
69099566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
69109566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
69119566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
6912674ae819SStefano Zampini 
691348a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
6914575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
69159371c9d4SSatish Balay     PetscCheck(!pcbddc->mat_graph->nvtxs_csr || pcbddc->mat_graph->nvtxs_csr == pcbddc->mat_graph->nvtxs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid size of local CSR graph! Found %" PetscInt_FMT ", expected %" PetscInt_FMT, pcbddc->mat_graph->nvtxs_csr,
69169371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
69179577ea80SStefano Zampini 
6918674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
691966da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
69204d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
69214d379d7bSStefano Zampini       PetscInt  nvtxs;
6922e496cd5dSStefano Zampini       PetscBool flg_row = PETSC_FALSE;
6923674ae819SStefano Zampini 
69249566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
69252fffb893SStefano Zampini       if (flg_row) {
69269566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
6927b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
69282fffb893SStefano Zampini       }
69299566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
693066da6bd7Sstefano_zampini       rcsr = PETSC_TRUE;
6931674ae819SStefano Zampini     }
69321baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6933674ae819SStefano Zampini 
6934ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
6935ab8c8b98SStefano Zampini       PetscReal   *lcoords;
6936ab8c8b98SStefano Zampini       PetscInt     n;
6937ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
6938ab8c8b98SStefano Zampini 
69394f819b78SStefano Zampini       /* TODO: support for blocked */
694063a3b9bcSJacob Faibussowitsch       PetscCheck(pcbddc->mat_graph->cnloc == pc->pmat->rmap->n, PETSC_COMM_SELF, PETSC_ERR_USER, "Invalid number of local coordinates! Got %" PetscInt_FMT ", expected %" PetscInt_FMT, pcbddc->mat_graph->cnloc, pc->pmat->rmap->n);
69419566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
69429566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
69439566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_contiguous(pcbddc->mat_graph->cdim, MPIU_REAL, &dimrealtype));
69449566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
69459566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
69469566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
69479566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
69489566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
6949ab8c8b98SStefano Zampini 
6950ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
6951ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
6952ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
6953ab8c8b98SStefano Zampini     }
69549371c9d4SSatish Balay     PetscCheck(!pcbddc->mat_graph->cnloc || pcbddc->mat_graph->cnloc == pcbddc->mat_graph->nvtxs, PETSC_COMM_SELF, PETSC_ERR_USER, "Invalid number of local subdomain coordinates! Got %" PetscInt_FMT ", expected %" PetscInt_FMT, pcbddc->mat_graph->cnloc,
69559371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
6956625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
6957ab8c8b98SStefano Zampini 
6958674ae819SStefano Zampini     /* Setup of Graph */
69594b2aedd3SStefano Zampini     pcbddc->mat_graph->commsizelimit = 0; /* don't use the COMM_SELF variant of the graph */
69609566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
6961674ae819SStefano Zampini 
69624f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
69634f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
696420c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
69654f1b2e48SStefano Zampini 
69669566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
69679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
696820c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
69694f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
69704f1b2e48SStefano Zampini         const PetscInt *idxs;
69714f1b2e48SStefano Zampini         PetscInt        nl, j;
69724f1b2e48SStefano Zampini 
69739566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
69749566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
697571582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
69769566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
69774f1b2e48SStefano Zampini       }
697820c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
697920c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
69804f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
69814f1b2e48SStefano Zampini     }
69828af8fcf9SStefano Zampini   }
69834f1b2e48SStefano Zampini 
6984cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
6985674ae819SStefano Zampini     /* Graph's connected components analysis */
69869566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
698771582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
69884f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
69898af8fcf9SStefano Zampini   }
699066da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
69913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6992674ae819SStefano Zampini }
6993674ae819SStefano Zampini 
6994d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[])
6995d71ae5a4SJacob Faibussowitsch {
6996295df10fSStefano Zampini   PetscInt     i, j, n;
69979a7d3425SStefano Zampini   PetscScalar *alphas;
6998295df10fSStefano Zampini   PetscReal    norm, *onorms;
69999a7d3425SStefano Zampini 
70009a7d3425SStefano Zampini   PetscFunctionBegin;
7001295df10fSStefano Zampini   n = *nio;
70023ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
70039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
70049566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
700592cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
7006295df10fSStefano Zampini     onorms[0] = 0.0;
70079566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
7008295df10fSStefano Zampini   } else {
7009295df10fSStefano Zampini     onorms[0] = norm;
701092cccca0SStefano Zampini   }
7011295df10fSStefano Zampini 
70128c0031efSStefano Zampini   for (i = 1; i < n; i++) {
70139566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
70148c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
70159566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
70169566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
701792cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
7018295df10fSStefano Zampini       onorms[i] = 0.0;
70199566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
7020295df10fSStefano Zampini     } else {
7021295df10fSStefano Zampini       onorms[i] = norm;
702292cccca0SStefano Zampini     }
70239a7d3425SStefano Zampini   }
7024295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
7025295df10fSStefano Zampini   for (i = 0; i < n; i++) {
7026295df10fSStefano Zampini     if (onorms[i] == 0.0) {
7027295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
7028295df10fSStefano Zampini         if (onorms[j] != 0.0) {
70299566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
7030295df10fSStefano Zampini           onorms[j] = 0.0;
7031295df10fSStefano Zampini         }
7032295df10fSStefano Zampini       }
7033295df10fSStefano Zampini     }
7034295df10fSStefano Zampini   }
7035295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
70369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
70373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70389a7d3425SStefano Zampini }
70399a7d3425SStefano Zampini 
7040ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void)
7041d71ae5a4SJacob Faibussowitsch {
7042e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
704357de7509SStefano Zampini   Mat                    A;
7044e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
7045e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
704652e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
704752e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
7048bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
704957de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
705027b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
705127b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
705227b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
705327b6a85dSStefano Zampini   MPI_Comm               subcomm;
7054a57a6d2fSStefano Zampini 
7055e7931f94SStefano Zampini   PetscFunctionBegin;
705657de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
70579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
705828b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot use %s on a matrix object which is not of type MATIS", PETSC_FUNCTION_NAME);
705957de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
706057de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
706163a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
706257de7509SStefano Zampini 
706357de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
70649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
70659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
70669566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
70679566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
7068bb360cb4SStefano Zampini   im_active = !!n;
70691c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
707057de7509SStefano Zampini   void_procs = size - active_procs;
707115229ffcSPierre Jolivet   /* get ranks of non-active processes in mat communicator */
707257de7509SStefano Zampini   if (void_procs) {
707357de7509SStefano Zampini     PetscInt ncand;
707457de7509SStefano Zampini 
707557de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
70769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
70779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
707857de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
7079ad540459SPierre Jolivet       if (!procs_candidates[i]) procs_candidates[ncand++] = i;
708057de7509SStefano Zampini     }
708157de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
708257de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
708357de7509SStefano Zampini   }
708457de7509SStefano Zampini 
7085bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
70869dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
70879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
7088bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
708914f0bfb9SStefano Zampini     PetscInt issize, isidx, dest;
709014f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
709114f0bfb9SStefano Zampini     else dest = rank;
709257de7509SStefano Zampini     if (im_active) {
709357de7509SStefano Zampini       issize = 1;
709457de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
709514f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
709657de7509SStefano Zampini       } else {
709714f0bfb9SStefano Zampini         isidx = dest;
709857de7509SStefano Zampini       }
709957de7509SStefano Zampini     } else {
710057de7509SStefano Zampini       issize = 0;
710157de7509SStefano Zampini       isidx  = -1;
710257de7509SStefano Zampini     }
7103bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
71049566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
71059566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
71063ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
710757de7509SStefano Zampini   }
71089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-matis_partitioning_use_vwgt", &use_vwgt, NULL));
71099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-matis_partitioning_threshold", &threshold, NULL));
711027b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7111e7931f94SStefano Zampini 
7112e7931f94SStefano Zampini   /* Get info on mapping */
71139566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
71149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7115e7931f94SStefano Zampini 
7116e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
71179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7118e7931f94SStefano Zampini   xadj[0] = 0;
7119e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
71209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
71219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
71229566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
712327b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
71249371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7125e7931f94SStefano Zampini 
712627b6a85dSStefano Zampini   xadj_count = 0;
71272b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
712827b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
712927b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7130d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7131d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7132d023bfaeSStefano Zampini         xadj_count++;
713327b6a85dSStefano Zampini         break;
713427b6a85dSStefano Zampini       }
7135e7931f94SStefano Zampini     }
7136e7931f94SStefano Zampini   }
7137d023bfaeSStefano Zampini   xadj[1] = xadj_count;
71389566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
71399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
71409566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7141e7931f94SStefano Zampini 
71429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7143e7931f94SStefano Zampini 
714427b6a85dSStefano Zampini   /* Restrict work on active processes only */
71459566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
714627b6a85dSStefano Zampini   if (void_procs) {
71479566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
71489566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
71499566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
715027b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
715127b6a85dSStefano Zampini   } else {
715227b6a85dSStefano Zampini     psubcomm = NULL;
715327b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
715427b6a85dSStefano Zampini   }
715527b6a85dSStefano Zampini 
715627b6a85dSStefano Zampini   v_wgt = NULL;
715727b6a85dSStefano Zampini   if (!color) {
71589566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
71599566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
71609566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7161c8587f34SStefano Zampini   } else {
716252e5ac9dSStefano Zampini     Mat             subdomain_adj;
716352e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
716452e5ac9dSStefano Zampini     MatPartitioning partitioner;
716527b6a85dSStefano Zampini     PetscInt        rstart = 0, rend = 0;
716652e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
716757de7509SStefano Zampini     PetscMPIInt     size;
7168b0c7d250SStefano Zampini     PetscBool       aggregate;
7169b0c7d250SStefano Zampini 
71709566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
717127b6a85dSStefano Zampini     if (void_procs) {
717227b6a85dSStefano Zampini       PetscInt prank = rank;
71739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
71749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
717548a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
71769566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
717727b6a85dSStefano Zampini     } else {
717827b6a85dSStefano Zampini       oldranks = NULL;
717927b6a85dSStefano Zampini     }
7180b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
718127b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7182b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7183b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7184b0c7d250SStefano Zampini       PetscScalar *vals;
7185b0c7d250SStefano Zampini 
71869566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7187b0c7d250SStefano Zampini       lrows = 0;
7188b0c7d250SStefano Zampini       if (nrank < redprocs) {
7189b0c7d250SStefano Zampini         lrows = size / redprocs;
7190b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7191b0c7d250SStefano Zampini       }
71929566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
71939566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
71949566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
71959566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7196b0c7d250SStefano Zampini       row   = nrank;
7197b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7198b0c7d250SStefano Zampini       cols  = adjncy;
71999566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7200b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
72019566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
72029566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
72039566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
72049566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
72059566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
72069566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
72079566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
720827b6a85dSStefano Zampini       if (use_vwgt) {
720927b6a85dSStefano Zampini         Vec                v;
721027b6a85dSStefano Zampini         const PetscScalar *array;
721127b6a85dSStefano Zampini         PetscInt           nl;
721227b6a85dSStefano Zampini 
72139566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
72149566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
72159566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
72169566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
72179566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
72189566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
72199566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
722022db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
72219566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
72229566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
722327b6a85dSStefano Zampini       }
7224b0c7d250SStefano Zampini     } else {
72259566063dSJacob Faibussowitsch       PetscCall(MatCreateMPIAdj(subcomm, 1, (PetscInt)size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
722627b6a85dSStefano Zampini       if (use_vwgt) {
72279566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7228bb360cb4SStefano Zampini         v_wgt[0] = n;
722927b6a85dSStefano Zampini       }
7230b0c7d250SStefano Zampini     }
72319566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7232e7931f94SStefano Zampini 
7233e7931f94SStefano Zampini     /* Partition */
72349566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7235ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
72369566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7237ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
72389566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7239ce64c636SStefano Zampini #else
72409566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7241ce64c636SStefano Zampini #endif
72429566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
72431baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
724457de7509SStefano Zampini     *n_subdomains = PetscMin((PetscInt)size, *n_subdomains);
72459566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
72469566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
72479566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
72489566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7249e7931f94SStefano Zampini 
725052e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
72519566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
72529566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
72539566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
725457de7509SStefano Zampini     if (!aggregate) {
725557de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
72566bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
725757de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
725827b6a85dSStefano Zampini       } else if (oldranks) {
7259b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
726027b6a85dSStefano Zampini       } else {
726127b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
726257de7509SStefano Zampini       }
726328143c3dSStefano Zampini     } else {
72647fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7265b0c7d250SStefano Zampini       PetscMPIInt  tag;
7266b0c7d250SStefano Zampini       MPI_Request *reqs;
7267b0c7d250SStefano Zampini 
72689566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
72699566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
727048a46eb9SPierre Jolivet       for (i = rstart; i < rend; i++) PetscCallMPI(MPI_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
72719566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
72729566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Waitall(rend - rstart, reqs, MPI_STATUSES_IGNORE));
72739566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
727457de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
72756bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
72767fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
727727b6a85dSStefano Zampini       } else if (oldranks) {
72787fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
727927b6a85dSStefano Zampini       } else {
72807fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
728128143c3dSStefano Zampini       }
728257de7509SStefano Zampini     }
72839566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7284e7931f94SStefano Zampini     /* clean up */
72859566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
72869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
72879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
72889566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
7289e7931f94SStefano Zampini   }
72909566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
72919566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
7292e7931f94SStefano Zampini 
7293e7931f94SStefano Zampini   /* assemble parallel IS for sends */
7294e7931f94SStefano Zampini   i = 1;
729527b6a85dSStefano Zampini   if (!color) i = 0;
72969566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
72973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7298e7931f94SStefano Zampini }
7299e7931f94SStefano Zampini 
73009371c9d4SSatish Balay typedef enum {
73019371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
73029371c9d4SSatish Balay   MATAIJ_PRIVATE,
73039371c9d4SSatish Balay   MATBAIJ_PRIVATE,
73049371c9d4SSatish Balay   MATSBAIJ_PRIVATE
73059371c9d4SSatish Balay } MatTypePrivate;
7306e7931f94SStefano Zampini 
7307ba38deedSJacob Faibussowitsch static 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[])
7308d71ae5a4SJacob Faibussowitsch {
730970cf5478SStefano Zampini   Mat                    local_mat;
7310e7931f94SStefano Zampini   IS                     is_sends_internal;
73119d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
73121ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
73139d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
7314e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
7315e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
7316e7931f94SStefano Zampini   const PetscInt        *is_indices;
7317e7931f94SStefano Zampini   MatType                new_local_type;
7318e7931f94SStefano Zampini   /* buffers */
7319e7931f94SStefano Zampini   PetscInt          *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
732028143c3dSStefano Zampini   PetscInt          *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
73219d30be91SStefano Zampini   PetscInt          *recv_buffer_idxs_local;
73221683a169SBarry Smith   PetscScalar       *ptr_vals, *recv_buffer_vals;
73231683a169SBarry Smith   const PetscScalar *send_buffer_vals;
73241ae86dd6SStefano Zampini   PetscScalar       *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
7325e7931f94SStefano Zampini   /* MPI */
732628143c3dSStefano Zampini   MPI_Comm     comm, comm_n;
732728143c3dSStefano Zampini   PetscSubcomm subcomm;
7328e569e4e1SStefano Zampini   PetscMPIInt  n_sends, n_recvs, size;
732928143c3dSStefano Zampini   PetscMPIInt *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
733028143c3dSStefano Zampini   PetscMPIInt *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
73311ae86dd6SStefano Zampini   PetscMPIInt  len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
73321ae86dd6SStefano Zampini   MPI_Request *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
73331ae86dd6SStefano Zampini   MPI_Request *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
7334e7931f94SStefano Zampini 
7335e7931f94SStefano Zampini   PetscFunctionBegin;
733657de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
73379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
73385f80ce2aSJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot use %s on a matrix object which is not of type MATIS", PETSC_FUNCTION_NAME);
733957de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
734057de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
734157de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
734257de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
734357de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
73441ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
73451ae86dd6SStefano Zampini   if (nvecs) {
734608401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
73471ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
73481ae86dd6SStefano Zampini   }
734957de7509SStefano Zampini   /* further checks */
73509566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
73519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
73525f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
73539566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
73545f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
735557de7509SStefano Zampini   if (reuse && *mat_n) {
735670cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
735757de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
73589566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
73595f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
73609566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
73619566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
736263a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
736363a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
736470cf5478SStefano Zampini   }
73659566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
7366064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
736757de7509SStefano Zampini 
7368e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
7369e7931f94SStefano Zampini   if (!is_sends) {
73705f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
73719566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
7372c8587f34SStefano Zampini   } else {
73739566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
7374e7931f94SStefano Zampini     is_sends_internal = is_sends;
7375c8587f34SStefano Zampini   }
7376e7931f94SStefano Zampini 
7377e7931f94SStefano Zampini   /* get comm */
73789566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7379e7931f94SStefano Zampini 
7380e7931f94SStefano Zampini   /* compute number of sends */
73819566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
73829566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
7383e7931f94SStefano Zampini 
7384e7931f94SStefano Zampini   /* compute number of receives */
73859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
73869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
73879566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
73889566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
7389e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
73909566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
73919566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
7392e7931f94SStefano Zampini 
739328143c3dSStefano Zampini   /* restrict comm if requested */
73940a545947SLisandro Dalcin   subcomm     = NULL;
739528143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
739628143c3dSStefano Zampini   if (restrict_comm) {
7397779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
7398779c1cceSStefano Zampini 
739928143c3dSStefano Zampini     color = 0;
740053a05cb3SStefano Zampini     if (restrict_full) {
74016aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
740253a05cb3SStefano Zampini     } else {
74036aad120cSJose E. Roman       if (!n_recvs && n_sends) color = 1; /* just those processes that are sending but not receiving anything will not participate in new comm */
740453a05cb3SStefano Zampini     }
74051c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
7406e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
740728143c3dSStefano Zampini     /* check if reuse has been requested */
740857de7509SStefano Zampini     if (reuse) {
740928143c3dSStefano Zampini       if (*mat_n) {
741028143c3dSStefano Zampini         PetscMPIInt subcommsize2;
74119566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
74125f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
741328143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
741428143c3dSStefano Zampini       } else {
741528143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
741628143c3dSStefano Zampini       }
741728143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
7418779c1cceSStefano Zampini       PetscMPIInt rank;
7419779c1cceSStefano Zampini 
74209566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
74219566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
74229566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
74239566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
7424306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
742528143c3dSStefano Zampini     }
742628143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
742728143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
742828143c3dSStefano Zampini   } else {
742928143c3dSStefano Zampini     comm_n = comm;
743028143c3dSStefano Zampini   }
743128143c3dSStefano Zampini 
7432e7931f94SStefano Zampini   /* prepare send/receive buffers */
74339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
74349566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
74359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
74369566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
743748a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
7438e7931f94SStefano Zampini 
743928143c3dSStefano Zampini   /* Get data from local matrices */
7440e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
7441e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
7442e7931f94SStefano Zampini   /*
7443e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
7444e7931f94SStefano Zampini        send_buffer_idxs should contain:
7445e7931f94SStefano Zampini        - MatType_PRIVATE type
7446e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
7447e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
7448e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
7449e7931f94SStefano Zampini     */
7450e432b41dSStefano Zampini   {
7451e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
7452e432b41dSStefano Zampini 
74539566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
74549566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
74559566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
74569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
7457e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
7458e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
74599566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
74609566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
74619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
74629566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
7463e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
7464e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
7465e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
7466c8587f34SStefano Zampini     }
7467c8587f34SStefano Zampini   }
74689566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
746928143c3dSStefano Zampini   /* additional is (if any) */
747028143c3dSStefano Zampini   if (nis) {
747128143c3dSStefano Zampini     PetscMPIInt psum;
747228143c3dSStefano Zampini     PetscInt    j;
747328143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
747428143c3dSStefano Zampini       PetscInt plen;
74759566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
74769566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
74776aad120cSJose E. Roman       psum += len + 1; /* indices + length */
747828143c3dSStefano Zampini     }
74799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
748028143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
748128143c3dSStefano Zampini       PetscInt        plen;
748228143c3dSStefano Zampini       const PetscInt *is_array_idxs;
74839566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
748428143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
74859566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
74869566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
74879566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
74886aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
748928143c3dSStefano Zampini     }
7490ad540459SPierre Jolivet     for (i = 0; i < n_sends; i++) ilengths_idxs_is[is_indices[i]] = psum;
74919566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
749228143c3dSStefano Zampini   }
74939566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
749428143c3dSStefano Zampini 
7495e7931f94SStefano Zampini   buf_size_idxs    = 0;
7496e7931f94SStefano Zampini   buf_size_vals    = 0;
749728143c3dSStefano Zampini   buf_size_idxs_is = 0;
74981ae86dd6SStefano Zampini   buf_size_vecs    = 0;
7499e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7500e7931f94SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
7501e7931f94SStefano Zampini     buf_size_vals += (PetscInt)olengths_vals[i];
750228143c3dSStefano Zampini     if (nis) buf_size_idxs_is += (PetscInt)olengths_idxs_is[i];
75031ae86dd6SStefano Zampini     if (nvecs) buf_size_vecs += (PetscInt)olengths_idxs[i];
7504e7931f94SStefano Zampini   }
75059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
75069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
75079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
75089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
7509e7931f94SStefano Zampini 
7510e7931f94SStefano Zampini   /* get new tags for clean communications */
75119566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
75129566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
75139566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
75149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
7515e7931f94SStefano Zampini 
7516e7931f94SStefano Zampini   /* allocate for requests */
75179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
75189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
75199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
75209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
75219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
75229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
75239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
75249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
7525e7931f94SStefano Zampini 
7526e7931f94SStefano Zampini   /* communications */
7527e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
7528e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
752928143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
75301ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
7531e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7532e7931f94SStefano Zampini     source_dest = onodes[i];
75339566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, source_dest, tag_idxs, comm, &recv_req_idxs[i]));
75349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, source_dest, tag_vals, comm, &recv_req_vals[i]));
7535e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7536e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
753728143c3dSStefano Zampini     if (nis) {
753857de7509SStefano Zampini       source_dest = onodes_is[i];
75399566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_idxs_is, olengths_idxs_is[i], MPIU_INT, source_dest, tag_idxs_is, comm, &recv_req_idxs_is[i]));
754028143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
754128143c3dSStefano Zampini     }
75421ae86dd6SStefano Zampini     if (nvecs) {
75431ae86dd6SStefano Zampini       source_dest = onodes[i];
75449566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &recv_req_vecs[i]));
75451ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
75461ae86dd6SStefano Zampini     }
7547e7931f94SStefano Zampini   }
7548e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
75499566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
75509566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
75519566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend((PetscScalar *)send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
755248a46eb9SPierre Jolivet     if (nis) PetscCallMPI(MPI_Isend(send_buffer_idxs_is, ilengths_idxs_is[source_dest], MPIU_INT, source_dest, tag_idxs_is, comm, &send_req_idxs_is[i]));
75531ae86dd6SStefano Zampini     if (nvecs) {
75549566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
75559566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
75561ae86dd6SStefano Zampini     }
7557e7931f94SStefano Zampini   }
75589566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
75599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
7560e7931f94SStefano Zampini 
7561e7931f94SStefano Zampini   /* assemble new l2g map */
75629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
7563e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
75649d30be91SStefano Zampini   new_local_rows = 0;
7565e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75669d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7567e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7568e7931f94SStefano Zampini   }
75699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
7570e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
75719d30be91SStefano Zampini   new_local_rows = 0;
7572e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75739566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
75749d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7575e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7576e7931f94SStefano Zampini   }
75779566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
75789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
75799566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
7580e7931f94SStefano Zampini 
7581e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
7582e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
7583e7931f94SStefano Zampini   /* 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) */
7584e7931f94SStefano Zampini   if (n_recvs) {
758528143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
7586e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
7587e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
7588e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
7589e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
7590e7931f94SStefano Zampini         break;
7591e7931f94SStefano Zampini       }
7592e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
7593e7931f94SStefano Zampini     }
7594e7931f94SStefano Zampini     switch (new_local_type_private) {
759528143c3dSStefano Zampini     case MATDENSE_PRIVATE:
7596e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7597e7931f94SStefano Zampini       bs             = 1;
7598e7931f94SStefano Zampini       break;
7599e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
7600e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7601e7931f94SStefano Zampini       bs             = 1;
7602e7931f94SStefano Zampini       break;
7603d71ae5a4SJacob Faibussowitsch     case MATBAIJ_PRIVATE:
7604d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQBAIJ;
7605d71ae5a4SJacob Faibussowitsch       break;
7606d71ae5a4SJacob Faibussowitsch     case MATSBAIJ_PRIVATE:
7607d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQSBAIJ;
7608d71ae5a4SJacob Faibussowitsch       break;
7609d71ae5a4SJacob Faibussowitsch     default:
7610d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
7611e7931f94SStefano Zampini     }
7612ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
7613ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
761428143c3dSStefano Zampini     bs             = 1;
7615e7931f94SStefano Zampini   }
7616e7931f94SStefano Zampini 
761770cf5478SStefano Zampini   /* create MATIS object if needed */
761857de7509SStefano Zampini   if (!reuse) {
76199566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
76209566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
762170cf5478SStefano Zampini   } else {
762270cf5478SStefano Zampini     /* it also destroys the local matrices */
762357de7509SStefano Zampini     if (*mat_n) {
76249566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
762557de7509SStefano Zampini     } else { /* this is a fake object */
76269566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
762757de7509SStefano Zampini     }
762870cf5478SStefano Zampini   }
76299566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
76309566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
76319d30be91SStefano Zampini 
76329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
76339d30be91SStefano Zampini 
76349d30be91SStefano Zampini   /* Global to local map of received indices */
76359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
76369566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
76379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
76389d30be91SStefano Zampini 
76399d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
76409d30be91SStefano Zampini   buf_size_idxs = 0;
76419d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
76429d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
76439d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
76449d30be91SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
76459d30be91SStefano Zampini   }
76469566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
76479d30be91SStefano Zampini 
76489d30be91SStefano Zampini   /* set preallocation */
76499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
76509d30be91SStefano Zampini   if (!newisdense) {
76510a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
76529d30be91SStefano Zampini 
76539d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
765448a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
76559d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
76569d30be91SStefano Zampini       PetscInt j;
76579d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
7658ad540459SPierre Jolivet         for (j = 0; j < *(ptr_idxs + 1); j++) new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1);
76599d30be91SStefano Zampini       } else {
76609d30be91SStefano Zampini         /* TODO */
76619d30be91SStefano Zampini       }
76629d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
76639d30be91SStefano Zampini     }
76649d30be91SStefano Zampini     if (new_local_nnz) {
76659d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
76669566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
76679d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
76689566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
76699d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
76709566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
76719d30be91SStefano Zampini     } else {
76729566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
76739d30be91SStefano Zampini     }
76749566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
76759d30be91SStefano Zampini   } else {
76769566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
76779d30be91SStefano Zampini   }
7678e7931f94SStefano Zampini 
7679e7931f94SStefano Zampini   /* set values */
7680e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
76819d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
7682e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7683e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
76849566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
76859566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
76869566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
76879566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
76889566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
768928143c3dSStefano Zampini     } else {
769028143c3dSStefano Zampini       /* TODO */
7691e7931f94SStefano Zampini     }
7692e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7693e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
7694e7931f94SStefano Zampini   }
76959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
76969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
76979566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
76989566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
76999566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
77009566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
7701e7931f94SStefano Zampini 
7702dfd14d43SStefano Zampini #if 0
770328143c3dSStefano Zampini   if (!restrict_comm) { /* check */
7704e7931f94SStefano Zampini     Vec       lvec,rvec;
7705e7931f94SStefano Zampini     PetscReal infty_error;
7706e7931f94SStefano Zampini 
77079566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
77089566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
77099566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
77109566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
77119566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
77129566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
77139566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
77149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
77159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
7716e7931f94SStefano Zampini   }
771728143c3dSStefano Zampini #endif
7718e7931f94SStefano Zampini 
771928143c3dSStefano Zampini   /* assemble new additional is (if any) */
772028143c3dSStefano Zampini   if (nis) {
772128143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
772228143c3dSStefano Zampini 
77239566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
77249566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
772528143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
772628143c3dSStefano Zampini     psum     = 0;
772728143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
772828143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
772928143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
773028143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
773128143c3dSStefano Zampini         psum += plen;
773228143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
773328143c3dSStefano Zampini       }
773428143c3dSStefano Zampini     }
77359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
77369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
77378e3a54c0SPierre Jolivet     for (i = 1; i < nis; i++) temp_idxs[i] = PetscSafePointerPlusOffset(temp_idxs[i - 1], count_is[i - 1]);
77389566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
773928143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
774028143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
774128143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
774228143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
77439566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
774428143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
774528143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
774628143c3dSStefano Zampini       }
774728143c3dSStefano Zampini     }
774828143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
77499566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
77509566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
77519566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
775228143c3dSStefano Zampini     }
77539566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
77549566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
77559566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
775628143c3dSStefano Zampini   }
7757e7931f94SStefano Zampini   /* free workspace */
77589566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
77599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
77609566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
77619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
7762e7931f94SStefano Zampini   if (isdense) {
77639566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
77649566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
77659566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
7766e7931f94SStefano Zampini   } else {
77679566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
7768e7931f94SStefano Zampini   }
776928143c3dSStefano Zampini   if (nis) {
77709566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
77719566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
777228143c3dSStefano Zampini   }
77731ae86dd6SStefano Zampini 
77741ae86dd6SStefano Zampini   if (nvecs) {
77759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
77769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
77779566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
77789566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
77799566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
77809566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
77819566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
77821ae86dd6SStefano Zampini     /* set values */
77831ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
77841ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
77859566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
77861ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
77871ae86dd6SStefano Zampini       PetscInt j;
7788ad540459SPierre Jolivet       for (j = 0; j < *(ptr_idxs + 1); j++) send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j);
77891ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
77901ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
77911ae86dd6SStefano Zampini     }
77929566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
77939566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
77949566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
77951ae86dd6SStefano Zampini   }
77961ae86dd6SStefano Zampini 
77979566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
77989566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
77999566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
78009566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
78019566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
78029566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
78039566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
78049566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
78059566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
78069566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
78079566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
78089566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
78099566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
78109566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
78119566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
781228143c3dSStefano Zampini   if (nis) {
78139566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
78149566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
78159566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
781628143c3dSStefano Zampini   }
78179566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
78186aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
78199566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
782048a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
78211ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
78229566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
78231ae86dd6SStefano Zampini     }
782453a05cb3SStefano Zampini     *mat_n = NULL;
782528143c3dSStefano Zampini   }
78263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7827e7931f94SStefano Zampini }
7828a57a6d2fSStefano Zampini 
782912edc857SStefano Zampini /* temporary hack into ksp private data structure */
7830af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
783112edc857SStefano Zampini 
7832d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, PetscScalar *coarse_submat_vals)
7833d71ae5a4SJacob Faibussowitsch {
7834c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7835c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
783620a2ab83SStefano Zampini   Mat                    coarse_mat, coarse_mat_is, coarse_submat_dense;
78371ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
78381e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
78399881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
784020a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
78414f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
78426e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
784330368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
7844e569e4e1SStefano Zampini   PetscInt               coarse_eqs_per_proc;
7845f9eb5b7dSStefano Zampini   PC                     pc_temp;
7846c8587f34SStefano Zampini   PCType                 coarse_pc_type;
7847c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
7848f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
78497274672aSStefano Zampini   PetscBool              coarse_reuse;
78501e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
785168457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
785222bc73bbSStefano Zampini   PetscScalar           *array;
785357de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
785457de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
7855e569e4e1SStefano Zampini   PetscMPIInt            size;
7856fdc09c96SStefano Zampini 
7857c8587f34SStefano Zampini   PetscFunctionBegin;
78589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
7859c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
786068457ee5SStefano Zampini   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 */
7861fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
78625a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
78637de4f681Sstefano_zampini 
78647de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
7865fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
78669566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
78679566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
7868f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
7869fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
787051bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
787151bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
78729566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
7873fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
7874fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
7875fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
7876f4ddd8eeSStefano Zampini       }
7877fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
7878fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
7879f4ddd8eeSStefano Zampini     }
788070cf5478SStefano Zampini     /* reset any subassembling information */
788148a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
78826e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
7883fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
7884f4ddd8eeSStefano Zampini   }
788557de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
78869566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
78879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
788857de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
788918a45a71SStefano Zampini   } else {
789057de7509SStefano Zampini     coarse_mat       = NULL;
789157de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
78926e683305SStefano Zampini   }
7893e7931f94SStefano Zampini 
7894abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
78959566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
78969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
7897abbbba34SStefano Zampini 
7898abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
78999566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_submat_dense));
79009566063dSJacob Faibussowitsch   PetscCall(MatCreateIS(PetscObjectComm((PetscObject)pc), 1, PETSC_DECIDE, PETSC_DECIDE, pcbddc->coarse_size, pcbddc->coarse_size, coarse_islg, coarse_islg, &t_coarse_mat_is));
79019566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat_dense));
79029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
79039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
79049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_submat_dense));
7905abbbba34SStefano Zampini 
790657de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
7907*f4f49eeaSPierre Jolivet   im_active = !!pcis->n;
79081c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
790957de7509SStefano Zampini 
791014f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
791128d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
791257de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
79139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
791457de7509SStefano Zampini   coarse_mat_is        = NULL;
791557de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
791657de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
7917e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
7918ce64c636SStefano Zampini   if (coarse_eqs_per_proc < 0) coarse_eqs_per_proc = pcbddc->coarse_size;
791957de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
7920e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
792157de7509SStefano Zampini   if (multilevel_requested) {
792257de7509SStefano Zampini     ncoarse    = active_procs / pcbddc->coarsening_ratio;
792357de7509SStefano Zampini     restr      = PETSC_FALSE;
792457de7509SStefano Zampini     full_restr = PETSC_FALSE;
792557de7509SStefano Zampini   } else {
7926e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
792757de7509SStefano Zampini     restr      = PETSC_TRUE;
792857de7509SStefano Zampini     full_restr = PETSC_TRUE;
792957de7509SStefano Zampini   }
7930e569e4e1SStefano Zampini   if (!pcbddc->coarse_size || size == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
793157de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
793257de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
7933a198735bSStefano Zampini     if (pcbddc->coarsening_ratio > 1) {
7934bb360cb4SStefano Zampini       if (multilevel_requested) {
79359566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7936bb360cb4SStefano Zampini       } else {
79379566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7938bb360cb4SStefano Zampini       }
7939a198735bSStefano Zampini     } else {
79407de4f681Sstefano_zampini       PetscMPIInt rank;
794128d58a37SPierre Jolivet 
79429566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
7943e569e4e1SStefano Zampini       have_void = (active_procs == (PetscInt)size) ? PETSC_FALSE : PETSC_TRUE;
79449566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
7945a198735bSStefano Zampini     }
794657de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
794757de7509SStefano Zampini     PetscInt psum;
794857de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
794957de7509SStefano Zampini     else psum = 0;
79501c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
7951075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
795257de7509SStefano Zampini   }
795357de7509SStefano Zampini   /* determine if we can go multilevel */
795457de7509SStefano Zampini   if (multilevel_requested) {
795557de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
795657de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
795757de7509SStefano Zampini   }
795857de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
795957de7509SStefano Zampini 
7960e4d548c7SStefano Zampini   /* dump subassembling pattern */
796148a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
79626e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
79631e0482f5SStefano Zampini   nedcfield = -1;
79644f819b78SStefano Zampini   corners   = NULL;
79658966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
79666e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
79676e683305SStefano Zampini     const PetscInt        *idxs;
79686e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
79696e683305SStefano Zampini 
79706e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
79719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
79726e683305SStefano Zampini     /* allocate space for temporary storage */
79739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
79749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
79756e683305SStefano Zampini     /* allocate for IS array */
79766e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
79771e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
79781e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
79791e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
79801e0482f5SStefano Zampini       } else {
79811e0482f5SStefano Zampini         nedcfield = 0;
798263a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
79831e0482f5SStefano Zampini         nisdofs = 1;
79841e0482f5SStefano Zampini       }
79851e0482f5SStefano Zampini     }
79866e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
798727b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
798830368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
79899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
79906e683305SStefano Zampini     /* dofs splitting */
79916e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
79929566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
79931e0482f5SStefano Zampini       if (nedcfield != i) {
79949566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
79959566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
79969566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
79979566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
79981e0482f5SStefano Zampini       } else {
79999566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
80009566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
80019566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
800263a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
80039566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
80041e0482f5SStefano Zampini       }
80059566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
80069566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
80079566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
80086e683305SStefano Zampini     }
80096e683305SStefano Zampini     /* neumann boundaries */
80106e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
80119566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
80129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
80139566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
80149566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
80159566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
80169566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
80179566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
80189566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
80196e683305SStefano Zampini     }
80204f819b78SStefano Zampini     /* coordinates */
80214f819b78SStefano Zampini     if (pcbddc->corner_selected) {
80229566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
80239566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
80249566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
80259566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
802663a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
80279566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
80289566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
80299566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
80309566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
80314f819b78SStefano Zampini     }
80329566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
80339566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
80349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
80356e683305SStefano Zampini   } else {
80366e683305SStefano Zampini     nis     = 0;
80376e683305SStefano Zampini     nisdofs = 0;
80386e683305SStefano Zampini     nisneu  = 0;
803930368db7SStefano Zampini     nisvert = 0;
80406e683305SStefano Zampini     isarray = NULL;
80416e683305SStefano Zampini   }
80426e683305SStefano Zampini   /* destroy no longer needed map */
80439566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
80446e683305SStefano Zampini 
804557de7509SStefano Zampini   /* subassemble */
804657de7509SStefano Zampini   if (multilevel_allowed) {
80471ae86dd6SStefano Zampini     Vec       vp[1];
80481ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
804957de7509SStefano Zampini     PetscBool reuse, reuser;
80501ae86dd6SStefano Zampini 
805157de7509SStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
805257de7509SStefano Zampini     else reuse = PETSC_FALSE;
80531c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&reuse, &reuser, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
80541ae86dd6SStefano Zampini     vp[0] = NULL;
80551ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
80569566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
80579566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
80589566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
80591ae86dd6SStefano Zampini       nvecs = 1;
80601ae86dd6SStefano Zampini 
80611ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
8062a198735bSStefano Zampini         Mat      B, loc_divudotp;
80631ae86dd6SStefano Zampini         Vec      v, p;
80641ae86dd6SStefano Zampini         IS       dummy;
80651ae86dd6SStefano Zampini         PetscInt np;
80661ae86dd6SStefano Zampini 
80679566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
80689566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
80699566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
80709566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
80719566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
80729566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
80739566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
80749566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
80759566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
80769566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
80779566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
80789566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
80799566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
80809566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
80819566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
80829566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
808374e2c79eSStefano Zampini       }
80841ae86dd6SStefano Zampini     }
80851ae86dd6SStefano Zampini     if (reuser) {
80869566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
808774e2c79eSStefano Zampini     } else {
80889566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
80891ae86dd6SStefano Zampini     }
80901ae86dd6SStefano Zampini     if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
80911683a169SBarry Smith       PetscScalar       *arraym;
80921683a169SBarry Smith       const PetscScalar *arrayv;
80931ae86dd6SStefano Zampini       PetscInt           nl;
80949566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vp[0], &nl));
80959566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
80969566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
80979566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(vp[0], &arrayv));
80989566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(arraym, arrayv, nl));
80999566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
81009566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
81019566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vp[0]));
8102a198735bSStefano Zampini     } else {
81039566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
81041ae86dd6SStefano Zampini     }
81051ae86dd6SStefano Zampini   } else {
81069566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
81076e683305SStefano Zampini   }
810857de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
810957de7509SStefano Zampini     if (!multilevel_allowed) {
81109566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
81116e683305SStefano Zampini     } else {
811257de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
811357de7509SStefano Zampini       if (coarse_mat_is) {
811428b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
81159566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
811657de7509SStefano Zampini         coarse_mat = coarse_mat_is;
811757de7509SStefano Zampini       }
8118779c1cceSStefano Zampini     }
8119779c1cceSStefano Zampini   }
81209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
81219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
81226e683305SStefano Zampini 
81236e683305SStefano Zampini   /* create local to global scatters for coarse problem */
812468457ee5SStefano Zampini   if (compute_vecs) {
81256e683305SStefano Zampini     PetscInt lrows;
81269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
812757de7509SStefano Zampini     if (coarse_mat) {
81289566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
81296e683305SStefano Zampini     } else {
81306e683305SStefano Zampini       lrows = 0;
81316e683305SStefano Zampini     }
81329566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
81339566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
81349566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
81359566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
81369566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
81376e683305SStefano Zampini   }
81389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8139c8587f34SStefano Zampini 
8140f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8141f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8142f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8143f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8144f9eb5b7dSStefano Zampini   } else {
8145f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8146f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8147c8587f34SStefano Zampini   }
8148c8587f34SStefano Zampini 
81496e683305SStefano Zampini   /* print some info if requested */
81506e683305SStefano Zampini   if (pcbddc->dbg_flag) {
81516e683305SStefano Zampini     if (!multilevel_allowed) {
81529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
81536e683305SStefano Zampini       if (multilevel_requested) {
815463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Not enough active processes on level %" PetscInt_FMT " (active processes %" PetscInt_FMT ", coarsening ratio %" PetscInt_FMT ")\n", pcbddc->current_level, active_procs, pcbddc->coarsening_ratio));
81556e683305SStefano Zampini       } else if (pcbddc->max_levels) {
815663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
81576e683305SStefano Zampini       }
81589566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
81596e683305SStefano Zampini     }
81606e683305SStefano Zampini   }
81616e683305SStefano Zampini 
81621e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
81631e0482f5SStefano Zampini   coarseG = NULL;
81641e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
81651e0482f5SStefano Zampini     MPI_Comm ccomm;
81661e0482f5SStefano Zampini     if (coarse_mat) {
81671e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
81681e0482f5SStefano Zampini     } else {
81691e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
81701e0482f5SStefano Zampini     }
81719566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
81721e0482f5SStefano Zampini   }
81731e0482f5SStefano Zampini 
8174f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
817557de7509SStefano Zampini   if (coarse_mat) {
817628d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
81776a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8178b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
81797274672aSStefano Zampini 
81806e683305SStefano Zampini     if (pcbddc->dbg_flag) {
818157de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
81829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
81836e683305SStefano Zampini     }
8184f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8185312be037SStefano Zampini       char   prefix[256], str_level[16];
8186e604994aSStefano Zampini       size_t len;
81871e0482f5SStefano Zampini 
81889566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
81893821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->coarse_ksp, pc->kspnestlevel));
81909566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
81919566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
81929566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1));
81939566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
81949566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
81959566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
81969566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
81971e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
81989566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8199e604994aSStefano Zampini       /* prefix */
8200c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(prefix, "", sizeof(prefix)));
8201c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(str_level, "", sizeof(str_level)));
8202e604994aSStefano Zampini       if (!pcbddc->current_level) {
82039566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
82049566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8205c8587f34SStefano Zampini       } else {
82069566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8207312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8208312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8209a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
82109566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
8211*f4f49eeaSPierre Jolivet         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)pcbddc->current_level));
82129566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8213e604994aSStefano Zampini       }
82149566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
82153e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
82169566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
82179566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
82189566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8219f9eb5b7dSStefano Zampini       /* allow user customization */
82209566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8221e569e4e1SStefano Zampini       /* get some info after set from options */
82229566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
822328d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
822428d58a37SPierre Jolivet       force = PETSC_FALSE;
82259566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
82269566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
82279566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
822828d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8229e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
82309566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
82319566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
82329566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
82339566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
82344f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8235d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8236dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8237dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8238d0609cedSBarry Smith           PetscOptionsEnd();
82394f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
82404f819b78SStefano Zampini         }
8241e569e4e1SStefano Zampini       }
82423e3c6dadSStefano Zampini     }
82433e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
82449566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
82453e3c6dadSStefano Zampini     if (nisdofs) {
82469566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
824748a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
82483e3c6dadSStefano Zampini     }
82493e3c6dadSStefano Zampini     if (nisneu) {
82509566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
82519566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8252312be037SStefano Zampini     }
825330368db7SStefano Zampini     if (nisvert) {
82549566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
82559566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
825630368db7SStefano Zampini     }
82571baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8258f9eb5b7dSStefano Zampini 
8259f9eb5b7dSStefano Zampini     /* get some info after set from options */
82609566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
82614f819b78SStefano Zampini 
8262b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
826348a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
826428d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
826528d58a37SPierre Jolivet     force = PETSC_FALSE;
82669566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
82679566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
826848a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
82699566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
82704f3a063dSStefano Zampini     if (isredundant) {
82714f3a063dSStefano Zampini       KSP inner_ksp;
82724f3a063dSStefano Zampini       PC  inner_pc;
82739326c5c6Sstefano_zampini 
82749566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
82759566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
82764f3a063dSStefano Zampini     }
8277f9eb5b7dSStefano Zampini 
827857de7509SStefano Zampini     /* parameters which miss an API */
82799566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
828057de7509SStefano Zampini     if (isbddc) {
8281720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
82827274672aSStefano Zampini 
8283720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
828457de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8285e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
828627b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
828727b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
8288a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
8289a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
8290a198735bSStefano Zampini         IS                     row, col;
8291a198735bSStefano Zampini         const PetscInt        *gidxs;
8292a198735bSStefano Zampini         PetscInt               n, st, M, N;
8293a198735bSStefano Zampini 
82949566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
82959566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
8296a198735bSStefano Zampini         st = st - n;
82979566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
82989566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
82999566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
83009566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
83019566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
83029566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
83039566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
83049566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
83059566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
83069566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
83079566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
83089566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
83099566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
83109566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
83119566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
83129566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
83139566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
83149566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
83159566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
83169566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
83179566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
83189566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
8319720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8320bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8321720d30f9SStefano Zampini       }
8322d4d8cf7bSStefano Zampini     }
83239881197aSStefano Zampini 
83243301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
83259566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
8326b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
8327b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
8328b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
8329b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
8330b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
8331b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
8332b94d7dedSBarry Smith 
833348a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
83346e683305SStefano Zampini     /* set operators */
83359566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
83369566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
83379566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
83381baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
83396e683305SStefano Zampini   }
83409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
83419566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
8342b1ecc7b1SStefano Zampini #if 0
8343b9b85e73SStefano Zampini   {
8344b9b85e73SStefano Zampini     PetscViewer viewer;
8345b9b85e73SStefano Zampini     char filename[256];
8346a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "coarse_mat_level%d.m",pcbddc->current_level));
83479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
83489566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
83499566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
83509566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
83519566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
8352b9b85e73SStefano Zampini   }
8353b9b85e73SStefano Zampini #endif
8354f9eb5b7dSStefano Zampini 
83554f819b78SStefano Zampini   if (corners) {
83564f819b78SStefano Zampini     Vec             gv;
83574f819b78SStefano Zampini     IS              is;
83584f819b78SStefano Zampini     const PetscInt *idxs;
83594f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
83604f819b78SStefano Zampini     PetscScalar    *coords;
83614f819b78SStefano Zampini 
836228b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
83639566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
83649566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
83659566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
83669566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
83679566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
83689566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
83699566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
83709566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
83714f819b78SStefano Zampini 
83729566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
83739566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
83749566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
83759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
83764f819b78SStefano Zampini     for (i = 0; i < n; i++) {
8377ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d];
83784f819b78SStefano Zampini     }
83799566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
83809566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
83814f819b78SStefano Zampini 
83829566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
83839566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
83849566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
83859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
83869566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
83879566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
83889566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
83899566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
83904f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
83914f819b78SStefano Zampini       PC        coarse_pc;
83924f819b78SStefano Zampini       PetscBool isbddc;
83934f819b78SStefano Zampini 
83949566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
83959566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
83964f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
83974f819b78SStefano Zampini         PetscReal *realcoords;
83984f819b78SStefano Zampini 
83999566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
84004f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
84019566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
84024f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
84034f819b78SStefano Zampini #else
84044f819b78SStefano Zampini         realcoords = coords;
84054f819b78SStefano Zampini #endif
84069566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
84074f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
84089566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
84094f819b78SStefano Zampini #endif
84104f819b78SStefano Zampini       }
84114f819b78SStefano Zampini     }
84129566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
84139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
84144f819b78SStefano Zampini   }
84159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
84164f819b78SStefano Zampini 
841798a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
841898a51de6SStefano Zampini     Vec crhs, csol;
841904708bb6SStefano Zampini 
84209566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
84219566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
8422*f4f49eeaSPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &pcbddc->coarse_ksp->vec_sol, NULL));
8423*f4f49eeaSPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &pcbddc->coarse_ksp->vec_rhs));
8424b0f5fe93SStefano Zampini   }
84259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
8426b0f5fe93SStefano Zampini 
8427b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
8428b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
84299566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
843048a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(VecSetValue(pcbddc->vec1_P, pcbddc->local_primal_size - pcbddc->benign_n + i, 1.0, INSERT_VALUES));
84319566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
84329566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
84339566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
84349566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
8435b0f5fe93SStefano Zampini     if (coarse_mat) {
8436b0f5fe93SStefano Zampini       Vec          nullv;
8437b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
8438b0f5fe93SStefano Zampini       PetscInt     nl;
8439b0f5fe93SStefano Zampini 
84409566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
84419566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
84429566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
84439566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
84449566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
84459566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
84469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
84479566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
84489566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
84499566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
8450b0f5fe93SStefano Zampini     }
8451b0f5fe93SStefano Zampini   }
84529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8453b0f5fe93SStefano Zampini 
84549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
8455b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
8456b0f5fe93SStefano Zampini     PetscBool ispreonly;
8457b0f5fe93SStefano Zampini 
8458b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
8459b0f5fe93SStefano Zampini       PetscBool isnull;
84607c625d9fSStefano Zampini 
84619566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
84621baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
8463bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
8464b0f5fe93SStefano Zampini     }
8465b0f5fe93SStefano Zampini     /* setup coarse ksp */
84669566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
8467cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
84689566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
84696e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
8470c8587f34SStefano Zampini       KSP         check_ksp;
84712b510759SStefano Zampini       KSPType     check_ksp_type;
8472c8587f34SStefano Zampini       PC          check_pc;
84736e683305SStefano Zampini       Vec         check_vec, coarse_vec;
84746a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
84752b510759SStefano Zampini       PetscInt    its;
84766e683305SStefano Zampini       PetscBool   compute_eigs;
84776e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
84786e683305SStefano Zampini       PetscInt    neigs;
84798e185a42SStefano Zampini       const char *prefix;
8480c8587f34SStefano Zampini 
84812b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
84829566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
84833821be0aSBarry Smith       PetscCall(KSPSetNestLevel(check_ksp, pc->kspnestlevel));
84849566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
84859566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
84869566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
84879566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_DEFAULT, pcbddc->coarse_size));
8488e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
84899566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
84909566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
84912b510759SStefano Zampini       if (ispreonly) {
84922b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
84936e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
84942b510759SStefano Zampini       } else {
8495cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
84966e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
8497c8587f34SStefano Zampini       }
84989566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
84999566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
85009566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
85019566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
85029566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
85039566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
85049566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
85059566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
85069566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
85079566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
85089566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
8509c8587f34SStefano Zampini       /* create random vec */
85109566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
85119566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
85129566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
8513c8587f34SStefano Zampini       /* solve coarse problem */
85149566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
85159566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
8516cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
85176e683305SStefano Zampini       if (compute_eigs) {
85189566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
85199566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
85209566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
85211ae86dd6SStefano Zampini         if (neigs) {
85226e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
85236e683305SStefano Zampini           lambda_min = eigs_r[0];
85246e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
85252701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
85269566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
85279566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
8528cbcc2c2aSStefano Zampini             }
8529c8587f34SStefano Zampini           }
8530c8587f34SStefano Zampini         }
85311ae86dd6SStefano Zampini       }
8532cbcc2c2aSStefano Zampini 
8533c8587f34SStefano Zampini       /* check coarse problem residual error */
85346e683305SStefano Zampini       if (pcbddc->dbg_flag) {
85356e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
85369566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
85379566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
85389566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
85399566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
85409566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
85419566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
8542*f4f49eeaSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pcbddc->coarse_ksp, dbg_viewer));
85439566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(check_pc), dbg_viewer));
854463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
854563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
854648a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
85476e683305SStefano Zampini         if (compute_eigs) {
85486e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
8549b03ebc13SStefano Zampini           KSPConvergedReason reason;
85509566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
85519566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
85529566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
85539566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
855463a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem eigenvalues (estimated with %" PetscInt_FMT " iterations of %s, conv reason %d): %1.6e %1.6e (%1.6e %1.6e)\n", its, check_ksp_type, reason, (double)lambda_min, (double)lambda_max, (double)lambda_min_s, (double)lambda_max_s));
855548a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
85566e683305SStefano Zampini         }
85579566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
85589566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
85596e683305SStefano Zampini       }
85609566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
85619566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
85629566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
85636e683305SStefano Zampini       if (compute_eigs) {
85649566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
85659566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
8566c8587f34SStefano Zampini       }
85676e683305SStefano Zampini     }
85686e683305SStefano Zampini   }
85699566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
8570cbcc2c2aSStefano Zampini   /* print additional info */
8571cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
85726e683305SStefano Zampini     /* waits until all processes reaches this point */
85739566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
857463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
85759566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8576cbcc2c2aSStefano Zampini   }
8577cbcc2c2aSStefano Zampini 
85782b510759SStefano Zampini   /* free memory */
85799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
85809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
85813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8582c8587f34SStefano Zampini }
8583674ae819SStefano Zampini 
8584d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n)
8585d71ae5a4SJacob Faibussowitsch {
8586f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
8587f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
8588f34684f1SStefano Zampini   Mat_IS         *matis  = (Mat_IS *)pc->pmat->data;
8589dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
8590dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
859173be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
8592dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
8593f34684f1SStefano Zampini 
8594f34684f1SStefano Zampini   PetscFunctionBegin;
8595f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
859608401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
8597*f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
85989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
85999566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
8600*f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
86019566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
86029566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
86039566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
86049566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
860563a3b9bcSJacob Faibussowitsch   PetscCheck(local_size == pcbddc->local_primal_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of local primal indices computed %" PetscInt_FMT " != %" PetscInt_FMT, local_size, pcbddc->local_primal_size);
86069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
86079566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
86089566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
86099566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
86109566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
8611f34684f1SStefano Zampini 
8612f34684f1SStefano Zampini   /* check numbering */
8613f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
8614019a44ceSStefano Zampini     PetscScalar coarsesum, *array, *array2;
8615dc456d91SStefano Zampini     PetscInt    i;
8616b9b85e73SStefano Zampini     PetscBool   set_error = PETSC_FALSE, set_error_reduced = PETSC_FALSE;
8617f34684f1SStefano Zampini 
86189566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86199566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
86209566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse indices\n"));
86219566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
8622019a44ceSStefano Zampini     /* counter */
86239566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
86249566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 1.0));
86259566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86269566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86279566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
86289566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
86299566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.0));
863048a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->local_primal_size; i++) PetscCall(VecSetValue(pcis->vec1_N, pcbddc->primal_indices_local_idxs[i], 1.0, INSERT_VALUES));
86319566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
86329566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
86339566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
86349566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86359566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86369566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
86379566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
86389566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec1_N, &array));
86399566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec2_N, &array2));
8640f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8641019a44ceSStefano Zampini       if (array[i] != 0.0 && array[i] != array2[i]) {
86422c66d082SStefano Zampini         PetscInt owned = (PetscInt)PetscRealPart(array[i]), gi;
864375c01103SStefano Zampini         PetscInt neigh = (PetscInt)PetscRealPart(array2[i]);
8644b9b85e73SStefano Zampini         set_error      = PETSC_TRUE;
86459566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, 1, &i, &gi));
864663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d: local index %" PetscInt_FMT " (gid %" PetscInt_FMT ") owned by %" PetscInt_FMT " processes instead of %" PetscInt_FMT "!\n", PetscGlobalRank, i, gi, owned, neigh));
8647f34684f1SStefano Zampini       }
8648f34684f1SStefano Zampini     }
86499566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec2_N, &array2));
86501c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&set_error, &set_error_reduced, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
86519566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8652f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8653f34684f1SStefano Zampini       if (PetscRealPart(array[i]) > 0.0) array[i] = 1.0 / PetscRealPart(array[i]);
8654f34684f1SStefano Zampini     }
86559566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec1_N, &array));
86569566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
86579566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86589566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
86599566063dSJacob Faibussowitsch     PetscCall(VecSum(pcis->vec1_global, &coarsesum));
866063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT " (%lf)\n", coarse_size, (double)PetscRealPart(coarsesum)));
8661b9b85e73SStefano Zampini     if (pcbddc->dbg_flag > 1 || set_error_reduced) {
8662ca8b9ea9SStefano Zampini       PetscInt *gidxs;
8663ca8b9ea9SStefano Zampini 
86649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->local_primal_size, &gidxs));
86659566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, gidxs));
86669566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Distribution of local primal indices\n"));
86679566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d\n", PetscGlobalRank));
8669f34684f1SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
867063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "local_primal_indices[%" PetscInt_FMT "]=%" PetscInt_FMT " (%" PetscInt_FMT ",%" PetscInt_FMT ")\n", i, local_primal_indices[i], pcbddc->primal_indices_local_idxs[i], gidxs[i]));
8671f34684f1SStefano Zampini       }
86729566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86739566063dSJacob Faibussowitsch       PetscCall(PetscFree(gidxs));
8674f34684f1SStefano Zampini     }
86759566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
867728b400f6SJacob Faibussowitsch     PetscCheck(!set_error_reduced, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "BDDC Numbering of coarse dofs failed");
8678f34684f1SStefano Zampini   }
86796080607fSStefano Zampini 
8680f34684f1SStefano Zampini   /* get back data */
8681f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
8682f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
86833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8684674ae819SStefano Zampini }
8685674ae819SStefano Zampini 
8686d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis)
8687d71ae5a4SJacob Faibussowitsch {
8688e456f2a8SStefano Zampini   IS           localis_t;
8689a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
8690e456f2a8SStefano Zampini   PetscScalar *vals;
8691e456f2a8SStefano Zampini 
8692e456f2a8SStefano Zampini   PetscFunctionBegin;
8693a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
86949566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
86959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
8696e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
86979566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
86989566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
86999566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
87001035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
87019566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
87029566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
87031035eff8SStefano Zampini   }
87049566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
87059566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
87069566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
87079566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
8708a7dc3881SStefano Zampini   /* now compute set in local ordering */
87099566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
87109566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
87119566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
87129566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
8713a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
8714ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) lsize++;
8715e456f2a8SStefano Zampini   }
87169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
8717a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
8718ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) idxs[lsize++] = i;
8719e456f2a8SStefano Zampini   }
87209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
87219566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
8722e456f2a8SStefano Zampini   *localis = localis_t;
87233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8724e456f2a8SStefano Zampini }
8725906d46d4SStefano Zampini 
8726d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr)
8727d71ae5a4SJacob Faibussowitsch {
87287c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
87297c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
87307c625d9fSStefano Zampini   PC_IS   *pcisf;
87317c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
87327c625d9fSStefano Zampini   PC       pcf;
87337c625d9fSStefano Zampini 
87347c625d9fSStefano Zampini   PetscFunctionBegin;
87357c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
87367c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
87377c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
87387c625d9fSStefano Zampini 
87397c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
874032fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
874132fe681dSStefano Zampini 
87427c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
87437c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
87447c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
87457c625d9fSStefano Zampini   pcisf->n          = pcis->n;
87467c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
87477c625d9fSStefano Zampini 
87487c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
874932fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
87507c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
875132fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
875232fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
875332fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
875432fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
875532fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
875632fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
87577c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
875832fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
875932fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
876032fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
87617c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
876232fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
876332fe681dSStefano Zampini 
876432fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
87657c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
87667c625d9fSStefano Zampini 
87677c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
87687c625d9fSStefano Zampini   if (change_primal) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddcf->local_primal_size_cc, pcbddcf->local_primal_ref_node, PETSC_COPY_VALUES, change_primal));
87697c625d9fSStefano Zampini   if (change_primal_mult) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddcf->local_primal_size_cc, pcbddcf->local_primal_ref_mult, PETSC_COPY_VALUES, change_primal_mult));
87707c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
87717c625d9fSStefano Zampini 
877232fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
87737c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
877432fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
877532fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
877632fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
877732fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
87787c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
87793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
87807c625d9fSStefano Zampini }
87817c625d9fSStefano Zampini 
8782d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
8783d71ae5a4SJacob Faibussowitsch {
8784a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
8785b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
8786b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
8787a64f4aa4SStefano Zampini   Mat             S_j;
8788b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
8789b96c3477SStefano Zampini   PetscBool       free_used_adj;
8790b96c3477SStefano Zampini 
8791b96c3477SStefano Zampini   PetscFunctionBegin;
87929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
8793b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
8794b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
879508122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
8796b96c3477SStefano Zampini     used_xadj   = NULL;
8797b96c3477SStefano Zampini     used_adjncy = NULL;
8798b96c3477SStefano Zampini   } else {
879908122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
880008122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
880108122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
880208122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
8803b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
8804b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
8805b96c3477SStefano Zampini     } else {
88062fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
8807b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
8808b96c3477SStefano Zampini       PetscInt        nvtxs;
8809b96c3477SStefano Zampini 
88109566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
88112fffb893SStefano Zampini       if (flg_row) {
88129566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
88139566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
88149566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
8815b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
88162fffb893SStefano Zampini       } else {
88172fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
88182fffb893SStefano Zampini         used_xadj                 = NULL;
88192fffb893SStefano Zampini         used_adjncy               = NULL;
88202fffb893SStefano Zampini       }
88219566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
8822b96c3477SStefano Zampini     }
8823b96c3477SStefano Zampini   }
8824d5574798SStefano Zampini 
8825d5574798SStefano Zampini   /* setup sub_schurs data */
88269566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
8827df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
8828df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
88299566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
88309566063dSJacob Faibussowitsch     PetscCall(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));
8831a64f4aa4SStefano Zampini   } else {
883272b8c272SStefano Zampini     Mat       change        = NULL;
88339d54b7f4SStefano Zampini     Vec       scaling       = NULL;
8834111315fdSstefano_zampini     IS        change_primal = NULL, iP;
8835111315fdSstefano_zampini     PetscInt  benign_n;
8836111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
88377ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
8838111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
8839a3df083aSStefano Zampini 
88405feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
88415feab87aSStefano Zampini       PetscInt n_vertices;
88425feab87aSStefano Zampini 
88439566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
88442034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
88455feab87aSStefano Zampini     }
8846a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
8847a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
8848ca92afb2SStefano Zampini     } else {
8849a3df083aSStefano Zampini       benign_n = 0;
8850ca92afb2SStefano Zampini     }
8851b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
8852b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
8853b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
885472b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
885522db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
88561c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
885722db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
8858b7ab4a40SStefano Zampini     }
88597c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
8860b7ab4a40SStefano Zampini     if (need_change) {
886128b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
886232fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
886388c03ad3SStefano Zampini     }
88649d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
8865111315fdSstefano_zampini 
88669566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
8867111315fdSstefano_zampini     if (iP) {
8868d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
88699566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
8870d0609cedSBarry Smith       PetscOptionsEnd();
8871111315fdSstefano_zampini     }
8872111315fdSstefano_zampini     if (discrete_harmonic) {
8873111315fdSstefano_zampini       Mat A;
88749566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
88759566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
88769566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
88779371c9d4SSatish Balay       PetscCall(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,
88789371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
88799566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
8880111315fdSstefano_zampini     } else {
88819371c9d4SSatish Balay       PetscCall(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,
88829371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
8883111315fdSstefano_zampini     }
88849566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
88859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
8886ca92afb2SStefano Zampini   }
88879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
8888b96c3477SStefano Zampini 
8889b96c3477SStefano Zampini   /* free adjacency */
88901baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
88919566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
88923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8893b96c3477SStefano Zampini }
8894b96c3477SStefano Zampini 
8895d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCInitSubSchurs(PC pc)
8896d71ae5a4SJacob Faibussowitsch {
8897b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
8898b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
8899b96c3477SStefano Zampini   PCBDDCGraph graph;
8900b96c3477SStefano Zampini 
8901b96c3477SStefano Zampini   PetscFunctionBegin;
8902b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
890308122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
89043301b35fSStefano Zampini     IS       verticesIS, verticescomm;
89053301b35fSStefano Zampini     PetscInt vsize, *idxs;
8906b96c3477SStefano Zampini 
89079566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
89089566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
89099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
89109566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
89119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
89129566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
89139566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
89149566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
89159566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
89169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
89179566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
8918b96c3477SStefano Zampini   } else {
8919b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
8920b96c3477SStefano Zampini   }
8921e4d548c7SStefano Zampini   /* print some info */
89225c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
8923e4d548c7SStefano Zampini     IS       vertices;
8924e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
89259566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
89269566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
89279566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
89289566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
89299566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
893063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
893163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
893263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
89339566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
89349566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
89359566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
8936e4d548c7SStefano Zampini   }
8937b96c3477SStefano Zampini 
8938b96c3477SStefano Zampini   /* sub_schurs init */
893948a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
894032fe681dSStefano Zampini   PetscCall(PCBDDCSubSchursInit(pcbddc->sub_schurs, ((PetscObject)pc)->prefix, pcis->is_I_local, pcis->is_B_local, graph, pcis->BtoNmap, pcbddc->sub_schurs_rebuild, PETSC_FALSE));
8941a64f4aa4SStefano Zampini 
8942b96c3477SStefano Zampini   /* free graph struct */
894348a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
89443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8945b96c3477SStefano Zampini }
8946fa34dd3eSStefano Zampini 
89471e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
8948ba38deedSJacob Faibussowitsch static PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
8949d71ae5a4SJacob Faibussowitsch {
89501e0482f5SStefano Zampini   Mat         At;
89511e0482f5SStefano Zampini   IS          rows;
89521e0482f5SStefano Zampini   PetscInt    rst, ren;
89531e0482f5SStefano Zampini   PetscLayout rmap;
89541e0482f5SStefano Zampini 
89551e0482f5SStefano Zampini   PetscFunctionBegin;
89561e0482f5SStefano Zampini   rst = ren = 0;
89571e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
89589566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
89599566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
89609566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
89619566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
89629566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
89631e0482f5SStefano Zampini   }
89649566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
89659566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
89669566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
89671e0482f5SStefano Zampini 
89681e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
89691e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
89701e0482f5SStefano Zampini     IS          from, to;
89711e0482f5SStefano Zampini     Vec         gvec;
89721e0482f5SStefano Zampini     PetscInt    lsize;
89731e0482f5SStefano Zampini 
89749566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
89759566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
89769566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
89779566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&((*B)->rmap)));
89789566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
89791e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
89801e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
89819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
89829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
89839566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
89849566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
89851e0482f5SStefano Zampini     b->A = a->A;
89861e0482f5SStefano Zampini     b->B = a->B;
89871e0482f5SStefano Zampini 
89881e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
89891e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
89900a545947SLisandro Dalcin     b->rowindices   = NULL;
89910a545947SLisandro Dalcin     b->rowvalues    = NULL;
89921e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
89931e0482f5SStefano Zampini 
89941e0482f5SStefano Zampini     (*B)->rmap         = rmap;
89951e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
89961e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
89971e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
89981e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
89991e0482f5SStefano Zampini 
90001e0482f5SStefano Zampini     if (a->colmap) {
90011e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
9002eec179cfSJacob Faibussowitsch       PetscCall(PetscHMapIDuplicate(a->colmap, &b->colmap));
90031e0482f5SStefano Zampini #else
90049566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
90059566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
90061e0482f5SStefano Zampini #endif
90070a545947SLisandro Dalcin     } else b->colmap = NULL;
90081e0482f5SStefano Zampini     if (a->garray) {
90091e0482f5SStefano Zampini       PetscInt len;
90101e0482f5SStefano Zampini       len = a->B->cmap->n;
90119566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
90129566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
90130a545947SLisandro Dalcin     } else b->garray = NULL;
90141e0482f5SStefano Zampini 
90159566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
90161e0482f5SStefano Zampini     b->lvec = a->lvec;
90171e0482f5SStefano Zampini 
90181e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
90199566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
90209566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
90219566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
90229566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
90239566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
90249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
90259566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
90269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
90271e0482f5SStefano Zampini   }
90289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
90293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
90301e0482f5SStefano Zampini }
9031