xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision 8a162dc661ac58c8ee750d413a4b6872a32eda28)
11cf9b237SStefano Zampini #include <../src/mat/impls/aij/seq/aij.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
49de2952eSStefano Zampini #include <petsc/private/kernels/blockinvert.h>
5837cedc9SStefano Zampini #include <../src/mat/impls/dense/seq/dense.h>
6c80a6c00SStefano Zampini #include <petscdmplex.h>
7674ae819SStefano Zampini #include <petscblaslapack.h>
8daf8a457SStefano Zampini #include <petsc/private/sfimpl.h>
9c80a6c00SStefano Zampini #include <petsc/private/dmpleximpl.h>
107620a527SStefano Zampini #include <petscdmda.h>
11674ae819SStefano Zampini 
121e0482f5SStefano Zampini static PetscErrorCode MatMPIAIJRestrict(Mat, MPI_Comm, Mat *);
131e0482f5SStefano Zampini 
14f498cd09SStefano Zampini /* if range is true,  it returns B s.t. span{B} = range(A)
15f498cd09SStefano Zampini    if range is false, it returns B s.t. range(B) _|_ range(A) */
16ba38deedSJacob Faibussowitsch static PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B)
17d71ae5a4SJacob Faibussowitsch {
18a13144ffSStefano Zampini   PetscScalar *uwork, *data, *U, ds = 0.;
19a13144ffSStefano Zampini   PetscReal   *sing;
20a13144ffSStefano Zampini   PetscBLASInt bM, bN, lwork, lierr, di = 1;
21a13144ffSStefano Zampini   PetscInt     ulw, i, nr, nc, n;
22abee2b68SSebastian Grimberg #if defined(PETSC_USE_COMPLEX)
23abee2b68SSebastian Grimberg   PetscReal *rwork2;
24abee2b68SSebastian Grimberg #endif
25a13144ffSStefano Zampini 
26a13144ffSStefano Zampini   PetscFunctionBegin;
279566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
283ba16761SJacob Faibussowitsch   if (!nr || !nc) PetscFunctionReturn(PETSC_SUCCESS);
29a13144ffSStefano Zampini 
30a13144ffSStefano Zampini   /* workspace */
31a13144ffSStefano Zampini   if (!work) {
32a13144ffSStefano Zampini     ulw = PetscMax(PetscMax(1, 5 * PetscMin(nr, nc)), 3 * PetscMin(nr, nc) + PetscMax(nr, nc));
339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ulw, &uwork));
34a13144ffSStefano Zampini   } else {
35a13144ffSStefano Zampini     ulw   = lw;
36a13144ffSStefano Zampini     uwork = work;
37a13144ffSStefano Zampini   }
38a13144ffSStefano Zampini   n = PetscMin(nr, nc);
39a13144ffSStefano Zampini   if (!rwork) {
409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &sing));
41a13144ffSStefano Zampini   } else {
42a13144ffSStefano Zampini     sing = rwork;
43a13144ffSStefano Zampini   }
44a13144ffSStefano Zampini 
45a13144ffSStefano Zampini   /* SVD */
469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nr, &U));
479566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nr, &bM));
489566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nc, &bN));
499566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(ulw, &lwork));
509566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(A, &data));
519566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
52abee2b68SSebastian Grimberg #if !defined(PETSC_USE_COMPLEX)
53792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, &lierr));
54abee2b68SSebastian Grimberg #else
559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(5 * n, &rwork2));
56792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, rwork2, &lierr));
579566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork2));
58abee2b68SSebastian Grimberg #endif
599566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPop());
60835f2295SStefano Zampini   PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %" PetscBLASInt_FMT, lierr);
619566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(A, &data));
629371c9d4SSatish Balay   for (i = 0; i < n; i++)
639371c9d4SSatish Balay     if (sing[i] < PETSC_SMALL) break;
6448a46eb9SPierre Jolivet   if (!rwork) PetscCall(PetscFree(sing));
6548a46eb9SPierre Jolivet   if (!work) PetscCall(PetscFree(uwork));
66a13144ffSStefano Zampini   /* create B */
67f498cd09SStefano Zampini   if (!range) {
689566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, nr - i, NULL, B));
699566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
709566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U + nr * i, (nr - i) * nr));
71f498cd09SStefano Zampini   } else {
729566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, i, NULL, B));
739566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
749566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U, i * nr));
75f498cd09SStefano Zampini   }
769566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(*B, &data));
779566063dSJacob Faibussowitsch   PetscCall(PetscFree(U));
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
79a13144ffSStefano Zampini }
80a13144ffSStefano Zampini 
811e0482f5SStefano Zampini /* TODO REMOVE */
821e0482f5SStefano Zampini #if defined(PRINT_GDET)
831e0482f5SStefano Zampini static int inc = 0;
841e0482f5SStefano Zampini static int lev = 0;
851e0482f5SStefano Zampini #endif
861e0482f5SStefano Zampini 
87ba38deedSJacob 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)
88d71ae5a4SJacob Faibussowitsch {
89a13144ffSStefano Zampini   Mat          GE, GEd;
90a13144ffSStefano Zampini   PetscInt     rsize, csize, esize;
91a13144ffSStefano Zampini   PetscScalar *ptr;
92a13144ffSStefano Zampini 
93a13144ffSStefano Zampini   PetscFunctionBegin;
949566063dSJacob Faibussowitsch   PetscCall(ISGetSize(edge, &esize));
953ba16761SJacob Faibussowitsch   if (!esize) PetscFunctionReturn(PETSC_SUCCESS);
969566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extrow, &rsize));
979566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extcol, &csize));
98a13144ffSStefano Zampini 
99a13144ffSStefano Zampini   /* gradients */
100a13144ffSStefano Zampini   ptr = work + 5 * esize;
1019566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, extrow, extcol, MAT_INITIAL_MATRIX, &GE));
1029566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, rsize, csize, ptr, Gins));
1039566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, Gins));
1049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
105a13144ffSStefano Zampini 
106a13144ffSStefano Zampini   /* constants */
107a13144ffSStefano Zampini   ptr += rsize * csize;
1089566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, esize, csize, ptr, &GEd));
1099566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, edge, extcol, MAT_INITIAL_MATRIX, &GE));
1109566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, &GEd));
1119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
1129566063dSJacob Faibussowitsch   PetscCall(MatDenseOrthogonalRangeOrComplement(GEd, PETSC_FALSE, 5 * esize, work, rwork, GKins));
1139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GEd));
1141e0482f5SStefano Zampini 
1151e0482f5SStefano Zampini   if (corners) {
1161e0482f5SStefano Zampini     Mat                GEc;
1171683a169SBarry Smith     const PetscScalar *vals;
1181683a169SBarry Smith     PetscScalar        v;
1191e0482f5SStefano Zampini 
1209566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(lG, edge, corners, MAT_INITIAL_MATRIX, &GEc));
1219566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(GEc, *GKins, MAT_INITIAL_MATRIX, 1.0, &GEd));
1229566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(GEd, &vals));
123a8f51744SPierre Jolivet     /* v       = PetscAbsScalar(vals[0]); */
124637e8532SStefano Zampini     v        = 1.;
1251e0482f5SStefano Zampini     cvals[0] = vals[0] / v;
1261e0482f5SStefano Zampini     cvals[1] = vals[1] / v;
1279566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(GEd, &vals));
1289566063dSJacob Faibussowitsch     PetscCall(MatScale(*GKins, 1. / v));
1291e0482f5SStefano Zampini #if defined(PRINT_GDET)
1301e0482f5SStefano Zampini     {
1311e0482f5SStefano Zampini       PetscViewer viewer;
1321e0482f5SStefano Zampini       char        filename[256];
133a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "Gdet_l%d_r%d_cc%d.m", lev, PetscGlobalRank, inc++));
1349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &viewer));
1359566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
1369566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEc, "GEc"));
1379566063dSJacob Faibussowitsch       PetscCall(MatView(GEc, viewer));
138f4f49eeaSPierre Jolivet       PetscCall(PetscObjectSetName((PetscObject)*GKins, "GK"));
1399566063dSJacob Faibussowitsch       PetscCall(MatView(*GKins, viewer));
1409566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEd, "Gproj"));
1419566063dSJacob Faibussowitsch       PetscCall(MatView(GEd, viewer));
1429566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
1431e0482f5SStefano Zampini     }
1441e0482f5SStefano Zampini #endif
1459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEd));
1469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEc));
1471e0482f5SStefano Zampini   }
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149a13144ffSStefano Zampini }
150a13144ffSStefano Zampini 
1519de2952eSStefano Zampini static PetscErrorCode MatAIJExtractRows(Mat, IS, Mat *);
1529de2952eSStefano Zampini 
153d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNedelecSupport(PC pc)
154d71ae5a4SJacob Faibussowitsch {
155a13144ffSStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
156a13144ffSStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
1570569b399SStefano Zampini   Mat                    G, T, conn, lG, lGt, lGis, lGall, lGe, lGinit;
158a13144ffSStefano Zampini   PetscSF                sfv;
1591e0482f5SStefano Zampini   ISLocalToGlobalMapping el2g, vl2g, fl2g, al2g;
160a13144ffSStefano Zampini   MPI_Comm               comm;
1610b61a303SStefano Zampini   IS                     lned, primals, allprimals, nedfieldlocal, elements_corners = NULL;
162c2151214SStefano Zampini   IS                    *eedges, *extrows, *extcols, *alleedges;
1637d871cd7SStefano Zampini   PetscBT                btv, bte, btvc, btb, btbd, btvcand, btvi, btee, bter;
164a13144ffSStefano Zampini   PetscScalar           *vals, *work;
165a13144ffSStefano Zampini   PetscReal             *rwork;
166a13144ffSStefano Zampini   const PetscInt        *idxs, *ii, *jj, *iit, *jjt;
1671e0482f5SStefano Zampini   PetscInt               ne, nv, Lv, order, n, field;
168eee23b56SStefano Zampini   PetscInt               i, j, extmem, cum, maxsize, nee;
169b03ebc13SStefano Zampini   PetscInt              *extrow, *extrowcum, *marks, *vmarks, *gidxs;
170a13144ffSStefano Zampini   PetscInt              *sfvleaves, *sfvroots;
171b03ebc13SStefano Zampini   PetscInt              *corners, *cedges;
172637e8532SStefano Zampini   PetscInt              *ecount, **eneighs, *vcount, **vneighs;
173b03ebc13SStefano Zampini   PetscInt              *emarks;
1740b61a303SStefano Zampini   PetscBool              print, eerr, done, lrc[2], conforming, global, setprimal;
175a13144ffSStefano Zampini 
176a13144ffSStefano Zampini   PetscFunctionBegin;
177213b8bfaSStefano Zampini   /* If the discrete gradient is defined for a subset of dofs and global is true,
178213b8bfaSStefano Zampini      it assumes G is given in global ordering for all the dofs.
179213b8bfaSStefano Zampini      Otherwise, the ordering is global for the Nedelec field */
180213b8bfaSStefano Zampini   order      = pcbddc->nedorder;
181213b8bfaSStefano Zampini   conforming = pcbddc->conforming;
182213b8bfaSStefano Zampini   field      = pcbddc->nedfield;
183213b8bfaSStefano Zampini   global     = pcbddc->nedglobal;
184213b8bfaSStefano Zampini   setprimal  = PETSC_FALSE;
185a13144ffSStefano Zampini   print      = 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));
1900b61a303SStefano Zampini   /* print debug info and adaptive order TODO: to be removed */
1919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bddc_nedelec_order", "Test variable order code (to be removed)", NULL, order, &order, NULL));
1929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_print", "Print debug info", NULL, print, &print, NULL));
193d0609cedSBarry Smith   PetscOptionsEnd();
194213b8bfaSStefano Zampini 
1950b61a303SStefano Zampini   /* Return if there are no edges in the decomposition */
1969566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &al2g, NULL));
1979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(al2g, &n));
1989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
1999566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
200a13144ffSStefano Zampini   lrc[0] = PETSC_FALSE;
201c2151214SStefano Zampini   for (i = 0; i < n; i++) {
202a13144ffSStefano Zampini     if (PetscRealPart(vals[i]) > 2.) {
203a13144ffSStefano Zampini       lrc[0] = PETSC_TRUE;
204a13144ffSStefano Zampini       break;
205a13144ffSStefano Zampini     }
206a13144ffSStefano Zampini   }
2079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
208462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&lrc[0], &lrc[1], 1, MPIU_BOOL, MPI_LOR, comm));
2093ba16761SJacob Faibussowitsch   if (!lrc[1]) PetscFunctionReturn(PETSC_SUCCESS);
210a13144ffSStefano Zampini 
211213b8bfaSStefano Zampini   /* Get Nedelec field */
21263a3b9bcSJacob 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);
213213b8bfaSStefano Zampini   if (pcbddc->n_ISForDofsLocal && field >= 0) {
2149566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofsLocal[field]));
215c2151214SStefano Zampini     nedfieldlocal = pcbddc->ISForDofsLocal[field];
2169566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nedfieldlocal, &ne));
217213b8bfaSStefano Zampini   } else if (!pcbddc->n_ISForDofsLocal && field != PETSC_DECIDE) {
218213b8bfaSStefano Zampini     ne            = n;
219213b8bfaSStefano Zampini     nedfieldlocal = NULL;
220213b8bfaSStefano Zampini     global        = PETSC_TRUE;
221213b8bfaSStefano Zampini   } else if (field == PETSC_DECIDE) {
222213b8bfaSStefano Zampini     PetscInt rst, ren, *idx;
223213b8bfaSStefano Zampini 
2249566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_leafdata, n));
2259566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
2269566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(pcbddc->discretegradient, &rst, &ren));
227213b8bfaSStefano Zampini     for (i = rst; i < ren; i++) {
228213b8bfaSStefano Zampini       PetscInt nc;
229213b8bfaSStefano Zampini 
2309566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
231213b8bfaSStefano Zampini       if (nc > 1) matis->sf_rootdata[i - rst] = 1;
2329566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
233213b8bfaSStefano Zampini     }
2349566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2359566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &idx));
2379371c9d4SSatish Balay     for (i = 0, ne = 0; i < n; i++)
2389371c9d4SSatish Balay       if (matis->sf_leafdata[i]) idx[ne++] = i;
2399566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, ne, idx, PETSC_OWN_POINTER, &nedfieldlocal));
240213b8bfaSStefano Zampini   } else {
241213b8bfaSStefano Zampini     SETERRQ(comm, PETSC_ERR_USER, "When multiple fields are present, the Nedelec field has to be specified");
242213b8bfaSStefano Zampini   }
243213b8bfaSStefano Zampini 
244213b8bfaSStefano Zampini   /* Sanity checks */
2457827d75bSBarry Smith   PetscCheck(order || conforming, comm, PETSC_ERR_SUP, "Variable order and non-conforming spaces are not supported at the same time");
24628b400f6SJacob Faibussowitsch   PetscCheck(!pcbddc->user_ChangeOfBasisMatrix, comm, PETSC_ERR_SUP, "Cannot generate Nedelec support with user defined change of basis");
24763a3b9bcSJacob 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);
248213b8bfaSStefano Zampini 
249213b8bfaSStefano Zampini   /* Just set primal dofs and return */
2501e0482f5SStefano Zampini   if (setprimal) {
251eee23b56SStefano Zampini     IS        enedfieldlocal;
252eee23b56SStefano Zampini     PetscInt *eidxs;
253eee23b56SStefano Zampini 
2549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &eidxs));
2559566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
256213b8bfaSStefano Zampini     if (nedfieldlocal) {
2579566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
258eee23b56SStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
259ad540459SPierre Jolivet         if (PetscRealPart(vals[idxs[i]]) > 2.) eidxs[cum++] = idxs[i];
260eee23b56SStefano Zampini       }
2619566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
262213b8bfaSStefano Zampini     } else {
263213b8bfaSStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
264ad540459SPierre Jolivet         if (PetscRealPart(vals[i]) > 2.) eidxs[cum++] = i;
265213b8bfaSStefano Zampini       }
266213b8bfaSStefano Zampini     }
2679566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2689566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, eidxs, PETSC_COPY_VALUES, &enedfieldlocal));
2699566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, enedfieldlocal));
2709566063dSJacob Faibussowitsch     PetscCall(PetscFree(eidxs));
2719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nedfieldlocal));
2729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&enedfieldlocal));
2733ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2741e0482f5SStefano Zampini   }
275a13144ffSStefano Zampini 
276213b8bfaSStefano Zampini   /* Compute some l2g maps */
277213b8bfaSStefano Zampini   if (nedfieldlocal) {
278c2151214SStefano Zampini     IS is;
279c2151214SStefano Zampini 
280c2151214SStefano Zampini     /* need to map from the local Nedelec field to local numbering */
2819566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(nedfieldlocal, &fl2g));
2821e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering for the whole dofs*/
2839566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(al2g, nedfieldlocal, &is));
2849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &al2g));
2851e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering (for Nedelec only) */
2861e0482f5SStefano Zampini     if (global) {
2879566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)al2g));
2881e0482f5SStefano Zampini       el2g = al2g;
2891e0482f5SStefano Zampini     } else {
2901e0482f5SStefano Zampini       IS gis;
2911e0482f5SStefano Zampini 
2929566063dSJacob Faibussowitsch       PetscCall(ISRenumber(is, NULL, NULL, &gis));
2939566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(gis, &el2g));
2949566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&gis));
2951e0482f5SStefano Zampini     }
2969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
297c2151214SStefano Zampini   } else {
2981e0482f5SStefano Zampini     /* one ref for the destruction of al2g, one for el2g */
2999566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3011e0482f5SStefano Zampini     el2g = al2g;
302c2151214SStefano Zampini     fl2g = NULL;
303c2151214SStefano Zampini   }
304a13144ffSStefano Zampini 
305213b8bfaSStefano Zampini   /* Start communication to drop connections for interior edges (for cc analysis only) */
3069566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
3079566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
308c2151214SStefano Zampini   if (nedfieldlocal) {
3099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
310c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[idxs[i]] = 1;
3119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
312c2151214SStefano Zampini   } else {
313c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[i] = 1;
314c2151214SStefano Zampini   }
3159566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
3169566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
317213b8bfaSStefano Zampini 
3180b61a303SStefano Zampini   /* There's no way to detect all possible corner candidates in a element-by-element case in a pure algebraic setting
3190b61a303SStefano Zampini      Firedrake attaches a index set to identify them upfront. If it is present, we assume we are in such a case */
3200b61a303SStefano Zampini   if (matis->allow_repeated) PetscCall(PetscObjectQuery((PetscObject)pcbddc->discretegradient, "_elements_corners", (PetscObject *)&elements_corners));
3210b61a303SStefano Zampini 
3220b61a303SStefano Zampini   /* drop connections with interior edges to avoid unneeded communications and memory movements */
3230b61a303SStefano Zampini   PetscCall(MatViewFromOptions(pcbddc->discretegradient, (PetscObject)pc, "-pc_bddc_discrete_gradient_view"));
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   }
349a13144ffSStefano Zampini 
350a13144ffSStefano Zampini   /* Extract subdomain relevant rows of G  */
3519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(el2g, &idxs));
3529566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, ne, idxs, PETSC_USE_POINTER, &lned));
3539de2952eSStefano Zampini   PetscCall(MatAIJExtractRows(G, lned, &lGall));
3549de2952eSStefano Zampini   /* PetscCall(MatCreateSubMatrix(G, lned, NULL, MAT_INITIAL_MATRIX, &lGall)); */
3559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(el2g, &idxs));
3569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&lned));
3579566063dSJacob Faibussowitsch   PetscCall(MatConvert(lGall, MATIS, MAT_INITIAL_MATRIX, &lGis));
3589566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGall));
3599566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(lGis, &lG));
3609de2952eSStefano Zampini   if (matis->allow_repeated) { /* multi-element support */
3619de2952eSStefano Zampini     Mat                   *lGn, B;
3629de2952eSStefano Zampini     IS                    *is_rows, *tcols, tmap, nmap;
3639de2952eSStefano Zampini     PetscInt               subnv;
3649de2952eSStefano Zampini     const PetscInt        *subvidxs;
3659de2952eSStefano Zampini     ISLocalToGlobalMapping mapn;
3669de2952eSStefano Zampini 
3679de2952eSStefano Zampini     PetscCall(PetscCalloc1(pcbddc->n_local_subs * pcbddc->n_local_subs, &lGn));
3689de2952eSStefano Zampini     PetscCall(PetscMalloc1(pcbddc->n_local_subs, &is_rows));
3699de2952eSStefano Zampini     PetscCall(PetscMalloc1(pcbddc->n_local_subs, &tcols));
3709de2952eSStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) {
3719de2952eSStefano Zampini       if (fl2g) {
3729de2952eSStefano Zampini         PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->local_subs[i], &is_rows[i]));
3739de2952eSStefano Zampini       } else {
3749de2952eSStefano Zampini         PetscCall(PetscObjectReference((PetscObject)pcbddc->local_subs[i]));
3759de2952eSStefano Zampini         is_rows[i] = pcbddc->local_subs[i];
3769de2952eSStefano Zampini       }
3779de2952eSStefano Zampini       PetscCall(MatCreateSubMatrix(lG, is_rows[i], NULL, MAT_INITIAL_MATRIX, &lGn[i * (1 + pcbddc->n_local_subs)]));
3789de2952eSStefano Zampini       PetscCall(MatSeqAIJCompactOutExtraColumns_SeqAIJ(lGn[i * (1 + pcbddc->n_local_subs)], &mapn));
3799de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingGetSize(mapn, &subnv));
3809de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingGetIndices(mapn, &subvidxs));
3819de2952eSStefano Zampini       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, subnv, subvidxs, PETSC_COPY_VALUES, &tcols[i]));
3829de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingRestoreIndices(mapn, &subvidxs));
3839de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingDestroy(&mapn));
3849de2952eSStefano Zampini     }
3859de2952eSStefano Zampini 
3869de2952eSStefano Zampini     /* Create new MATIS with repeated vertices */
3879de2952eSStefano Zampini     PetscCall(MatCreate(comm, &B));
3889de2952eSStefano Zampini     PetscCall(MatSetSizes(B, lGis->rmap->n, lGis->cmap->n, lGis->rmap->N, lGis->cmap->N));
3899de2952eSStefano Zampini     PetscCall(MatSetType(B, MATIS));
3909de2952eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PETSC_TRUE));
3919de2952eSStefano Zampini     PetscCall(ISConcatenate(PETSC_COMM_SELF, pcbddc->n_local_subs, tcols, &tmap));
3929de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingApplyIS(lGis->cmap->mapping, tmap, &nmap));
3939de2952eSStefano Zampini     PetscCall(ISDestroy(&tmap));
3949de2952eSStefano Zampini     PetscCall(ISGetLocalSize(nmap, &subnv));
3959de2952eSStefano Zampini     PetscCall(ISGetIndices(nmap, &subvidxs));
3969de2952eSStefano Zampini     PetscCall(ISCreateGeneral(comm, subnv, subvidxs, PETSC_USE_POINTER, &tmap));
3979de2952eSStefano Zampini     PetscCall(ISRestoreIndices(nmap, &subvidxs));
3989de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingCreateIS(tmap, &mapn));
3999de2952eSStefano Zampini     PetscCall(ISDestroy(&tmap));
4009de2952eSStefano Zampini     PetscCall(ISDestroy(&nmap));
4019de2952eSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(B, lGis->rmap->mapping, mapn));
4029de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingDestroy(&mapn));
4039de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, pcbddc->n_local_subs, is_rows, pcbddc->n_local_subs, NULL, lGn, &lG));
4049de2952eSStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) {
4059de2952eSStefano Zampini       PetscCall(MatDestroy(&lGn[i * (1 + pcbddc->n_local_subs)]));
4069de2952eSStefano Zampini       PetscCall(ISDestroy(&is_rows[i]));
4079de2952eSStefano Zampini       PetscCall(ISDestroy(&tcols[i]));
4089de2952eSStefano Zampini     }
4099de2952eSStefano Zampini     PetscCall(MatConvert(lG, MATSEQAIJ, MAT_INPLACE_MATRIX, &lG));
4109de2952eSStefano Zampini     PetscCall(PetscFree(lGn));
4119de2952eSStefano Zampini     PetscCall(PetscFree(is_rows));
4129de2952eSStefano Zampini     PetscCall(PetscFree(tcols));
4139de2952eSStefano Zampini     PetscCall(MatISSetLocalMat(B, lG));
4149de2952eSStefano Zampini     PetscCall(MatDestroy(&lG));
4159de2952eSStefano Zampini 
4169de2952eSStefano Zampini     PetscCall(MatDestroy(&lGis));
4179de2952eSStefano Zampini     lGis = B;
4180b61a303SStefano Zampini 
4190b61a303SStefano Zampini     lGis->assembled = PETSC_TRUE;
4209de2952eSStefano Zampini   }
4210b61a303SStefano Zampini   PetscCall(MatViewFromOptions(lGis, (PetscObject)pc, "-pc_bddc_nedelec_init_G_view"));
4229de2952eSStefano Zampini 
423213b8bfaSStefano Zampini   /* SF for nodal dofs communications */
4249566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(G, NULL, &Lv));
4259566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(lGis, NULL, &vl2g));
4269566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)vl2g));
4279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(vl2g, &nv));
4289566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sfv));
4299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(vl2g, &idxs));
4309566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sfv, lGis->cmap, nv, NULL, PETSC_OWN_POINTER, idxs));
4319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(vl2g, &idxs));
432a13144ffSStefano Zampini 
4330b61a303SStefano Zampini   if (elements_corners) {
4340b61a303SStefano Zampini     IS      tmp;
4350b61a303SStefano Zampini     Vec     global, local;
4360b61a303SStefano Zampini     Mat_IS *tGis = (Mat_IS *)lGis->data;
4370b61a303SStefano Zampini 
4380b61a303SStefano Zampini     PetscCall(MatCreateVecs(lGis, &global, NULL));
4390b61a303SStefano Zampini     PetscCall(MatCreateVecs(tGis->A, &local, NULL));
4400b61a303SStefano Zampini     PetscCall(PCBDDCGlobalToLocal(tGis->cctx, global, local, elements_corners, &tmp));
4410b61a303SStefano Zampini     PetscCall(VecDestroy(&global));
4420b61a303SStefano Zampini     PetscCall(VecDestroy(&local));
4430b61a303SStefano Zampini     elements_corners = tmp;
4440b61a303SStefano Zampini   }
4450b61a303SStefano Zampini 
4460b61a303SStefano Zampini   /* Destroy temporary G */
4479de2952eSStefano Zampini   PetscCall(MatISGetLocalMat(lGis, &lG));
4489566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)lG));
4499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&G));
4500b61a303SStefano Zampini   PetscCall(MatDestroy(&lGis));
451a13144ffSStefano Zampini 
452213b8bfaSStefano Zampini   if (print) {
4539566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "initial_lG"));
4549566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
455213b8bfaSStefano Zampini   }
456213b8bfaSStefano Zampini 
457213b8bfaSStefano Zampini   /* Save lG for values insertion in change of basis */
4589566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGinit));
4590569b399SStefano Zampini 
460a13144ffSStefano Zampini   /* Analyze the edge-nodes connections (duplicate lG) */
4619566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGe));
4629566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGe, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
4639566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btv));
4649566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &bte));
4659566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btb));
4669566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btbd));
467a13144ffSStefano Zampini   /* need to import the boundary specification to ensure the
468a13144ffSStefano Zampini      proper detection of coarse edges' endpoints */
469a13144ffSStefano Zampini   if (pcbddc->DirichletBoundariesLocal) {
470c2151214SStefano Zampini     IS is;
471c2151214SStefano Zampini 
472c2151214SStefano Zampini     if (fl2g) {
4739566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->DirichletBoundariesLocal, &is));
474c2151214SStefano Zampini     } else {
475c2151214SStefano Zampini       is = pcbddc->DirichletBoundariesLocal;
476c2151214SStefano Zampini     }
4779566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4789566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
479a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
4809de2952eSStefano Zampini       if (idxs[i] >= 0 && idxs[i] < ne) {
4819566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btb, idxs[i]));
4829566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btbd, idxs[i]));
483a13144ffSStefano Zampini       }
484a13144ffSStefano Zampini     }
4859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
48648a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
487a13144ffSStefano Zampini   }
488a13144ffSStefano Zampini   if (pcbddc->NeumannBoundariesLocal) {
489c2151214SStefano Zampini     IS is;
490c2151214SStefano Zampini 
491c2151214SStefano Zampini     if (fl2g) {
4929566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->NeumannBoundariesLocal, &is));
493c2151214SStefano Zampini     } else {
494c2151214SStefano Zampini       is = pcbddc->NeumannBoundariesLocal;
495c2151214SStefano Zampini     }
4969566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4979566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
498a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
4999de2952eSStefano Zampini       if (idxs[i] >= 0 && idxs[i] < ne) PetscCall(PetscBTSet(btb, idxs[i]));
500a13144ffSStefano Zampini     }
5019566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
50248a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
503c2151214SStefano Zampini   }
504c2151214SStefano Zampini 
505213b8bfaSStefano Zampini   /* Count neighs per dof */
5069de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, &ecount, NULL));
5079de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, &vcount, NULL));
508637e8532SStefano Zampini 
5097d871cd7SStefano Zampini   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
5107d871cd7SStefano Zampini      for proper detection of coarse edges' endpoints */
5119566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btee));
51262b0c6f7SStefano Zampini   for (i = 0; i < ne; i++) {
51348a46eb9SPierre Jolivet     if ((ecount[i] > 2 && !PetscBTLookup(btbd, i)) || (ecount[i] == 2 && PetscBTLookup(btb, i))) PetscCall(PetscBTSet(btee, i));
51462b0c6f7SStefano Zampini   }
5159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ne, &marks));
51662b0c6f7SStefano Zampini   if (!conforming) {
5179566063dSJacob Faibussowitsch     PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
5189566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
51962b0c6f7SStefano Zampini   }
5209566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5219566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGe, &vals));
52262b0c6f7SStefano Zampini   cum = 0;
523a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
524dec27d64SStefano Zampini     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
52562b0c6f7SStefano Zampini     if (!PetscBTLookup(btee, i)) {
526a13144ffSStefano Zampini       marks[cum++] = i;
527dec27d64SStefano Zampini       continue;
528dec27d64SStefano Zampini     }
529dec27d64SStefano Zampini     /* set badly connected edge dofs as primal */
53062b0c6f7SStefano Zampini     if (!conforming) {
53162b0c6f7SStefano Zampini       if (ii[i + 1] - ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
532a13144ffSStefano Zampini         marks[cum++] = i;
5339566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(bte, i));
53448a46eb9SPierre Jolivet         for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
53562b0c6f7SStefano Zampini       } else {
536aaa8cc7dSPierre Jolivet         /* every edge dofs should be connected through a certain number of nodal dofs
53762b0c6f7SStefano Zampini            to other edge dofs belonging to coarse edges
53862b0c6f7SStefano Zampini            - at most 2 endpoints
53962b0c6f7SStefano Zampini            - order-1 interior nodal dofs
54062b0c6f7SStefano Zampini            - no undefined nodal dofs (nconn < order)
54162b0c6f7SStefano Zampini         */
54262b0c6f7SStefano Zampini         PetscInt ends = 0, ints = 0, undef = 0;
54362b0c6f7SStefano Zampini         for (j = ii[i]; j < ii[i + 1]; j++) {
54462b0c6f7SStefano Zampini           PetscInt v     = jj[j], k;
54562b0c6f7SStefano Zampini           PetscInt nconn = iit[v + 1] - iit[v];
5469371c9d4SSatish Balay           for (k = iit[v]; k < iit[v + 1]; k++)
5479371c9d4SSatish Balay             if (!PetscBTLookup(btee, jjt[k])) nconn--;
54862b0c6f7SStefano Zampini           if (nconn > order) ends++;
54962b0c6f7SStefano Zampini           else if (nconn == order) ints++;
55062b0c6f7SStefano Zampini           else undef++;
55162b0c6f7SStefano Zampini         }
55262b0c6f7SStefano Zampini         if (undef || ends > 2 || ints != order - 1) {
55362b0c6f7SStefano Zampini           marks[cum++] = i;
5549566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(bte, i));
55548a46eb9SPierre Jolivet           for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
55662b0c6f7SStefano Zampini         }
55762b0c6f7SStefano Zampini       }
558a13144ffSStefano Zampini     }
559dec27d64SStefano Zampini     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
560dec27d64SStefano Zampini     if (!order && ii[i + 1] != ii[i]) {
561dec27d64SStefano Zampini       PetscScalar val = 1. / (ii[i + 1] - ii[i] - 1);
562dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vals[j] = val;
563a13144ffSStefano Zampini     }
564dec27d64SStefano Zampini   }
5659566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btee));
5669566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGe, &vals));
5679566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
56862b0c6f7SStefano Zampini   if (!conforming) {
5699566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
5709566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lGt));
57162b0c6f7SStefano Zampini   }
5729566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGe, cum, marks, 0., NULL, NULL));
573637e8532SStefano Zampini 
5740b61a303SStefano Zampini   /* identify splitpoints and corner candidates */
5750b61a303SStefano Zampini   PetscCall(PetscMalloc2(nv, &sfvleaves, Lv, &sfvroots));
5760b61a303SStefano Zampini   PetscCall(PetscBTCreate(nv, &btvcand));
5770b61a303SStefano Zampini   if (elements_corners) {
5780b61a303SStefano Zampini     PetscCall(ISGetLocalSize(elements_corners, &cum));
5790b61a303SStefano Zampini     PetscCall(ISGetIndices(elements_corners, &idxs));
5800b61a303SStefano Zampini     for (i = 0; i < cum; i++) PetscCall(PetscBTSet(btvcand, idxs[i]));
5810b61a303SStefano Zampini     PetscCall(ISRestoreIndices(elements_corners, &idxs));
5820b61a303SStefano Zampini   }
5830b61a303SStefano Zampini 
5849de2952eSStefano Zampini   if (matis->allow_repeated) { /* assign a uniq global id to edge local subsets and communicate it with nodal space */
5859de2952eSStefano Zampini     PetscSF   emlsf, vmlsf;
5869de2952eSStefano Zampini     PetscInt *eleaves, *vleaves, *meleaves, *mvleaves;
5879de2952eSStefano Zampini     PetscInt  cum_subs = 0, n_subs = pcbddc->n_local_subs, bs, emnr, emnl, vmnr, vmnl;
5889de2952eSStefano Zampini 
5899de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(el2g, &bs));
5909de2952eSStefano Zampini     PetscCheck(bs == 1, comm, PETSC_ERR_SUP, "Not coded");
5919de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(vl2g, &bs));
5929de2952eSStefano Zampini     PetscCheck(bs == 1, comm, PETSC_ERR_SUP, "Not coded");
5939de2952eSStefano Zampini 
5949de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockMultiLeavesSF(el2g, &emlsf));
5959de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockMultiLeavesSF(vl2g, &vmlsf));
5969de2952eSStefano Zampini 
5979de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(emlsf, &emnr, &emnl, NULL, NULL));
5989de2952eSStefano Zampini     for (i = 0, j = 0; i < ne; i++) j += ecount[i];
5999de2952eSStefano Zampini     PetscCheck(emnr == ne, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of roots in edge multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, emnr, ne);
6009de2952eSStefano Zampini     PetscCheck(emnl == j, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of leaves in edge multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, emnl, j);
6019de2952eSStefano Zampini 
6029de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(vmlsf, &vmnr, &vmnl, NULL, NULL));
6039de2952eSStefano Zampini     for (i = 0, j = 0; i < nv; i++) j += vcount[i];
6049de2952eSStefano Zampini     PetscCheck(vmnr == nv, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of roots in nodal multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, vmnr, nv);
6059de2952eSStefano Zampini     PetscCheck(vmnl == j, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of leaves in nodal multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, vmnl, j);
6069de2952eSStefano Zampini 
6079de2952eSStefano Zampini     PetscCall(PetscMalloc1(ne, &eleaves));
6089de2952eSStefano Zampini     PetscCall(PetscMalloc1(nv, &vleaves));
6091690c2aeSBarry Smith     for (i = 0; i < ne; i++) eleaves[i] = PETSC_INT_MAX;
6101690c2aeSBarry Smith     for (i = 0; i < nv; i++) vleaves[i] = PETSC_INT_MAX;
6119de2952eSStefano Zampini     PetscCall(PetscMalloc1(emnl, &meleaves));
6129de2952eSStefano Zampini     PetscCall(PetscMalloc1(vmnl, &mvleaves));
6139de2952eSStefano Zampini 
6149de2952eSStefano Zampini     PetscCallMPI(MPI_Exscan(&n_subs, &cum_subs, 1, MPIU_INT, MPI_SUM, comm));
6150b61a303SStefano Zampini     PetscCall(MatGetRowIJ(lGinit, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
6169de2952eSStefano Zampini     for (i = 0; i < n_subs; i++) {
6179de2952eSStefano Zampini       const PetscInt *idxs;
6189de2952eSStefano Zampini       const PetscInt  subid = cum_subs + i;
6199de2952eSStefano Zampini       PetscInt        ns;
6209de2952eSStefano Zampini 
6219de2952eSStefano Zampini       PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &ns));
6229de2952eSStefano Zampini       PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
6239de2952eSStefano Zampini       for (j = 0; j < ns; j++) {
6249de2952eSStefano Zampini         const PetscInt e = idxs[j];
6259de2952eSStefano Zampini 
6269de2952eSStefano Zampini         eleaves[e] = subid;
6279de2952eSStefano Zampini         for (PetscInt k = ii[e]; k < ii[e + 1]; k++) vleaves[jj[k]] = subid;
6289de2952eSStefano Zampini       }
6299de2952eSStefano Zampini       PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
6309de2952eSStefano Zampini     }
6310b61a303SStefano Zampini     PetscCall(MatRestoreRowIJ(lGinit, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
6329de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(emlsf, MPIU_INT, eleaves, meleaves, MPI_REPLACE));
6339de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(emlsf, MPIU_INT, eleaves, meleaves, MPI_REPLACE));
6349de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(vmlsf, MPIU_INT, vleaves, mvleaves, MPI_REPLACE));
6359de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(vmlsf, MPIU_INT, vleaves, mvleaves, MPI_REPLACE));
6369de2952eSStefano Zampini     PetscCall(PetscFree(eleaves));
6379de2952eSStefano Zampini     PetscCall(PetscFree(vleaves));
6389de2952eSStefano Zampini 
6399de2952eSStefano Zampini     PetscCall(PetscMalloc1(ne + 1, &eneighs));
6409de2952eSStefano Zampini     eneighs[0] = meleaves;
6410b61a303SStefano Zampini     for (i = 0; i < ne; i++) {
6420b61a303SStefano Zampini       PetscCall(PetscSortInt(ecount[i], eneighs[i]));
6430b61a303SStefano Zampini       eneighs[i + 1] = eneighs[i] + ecount[i];
6449de2952eSStefano Zampini     }
6459de2952eSStefano Zampini     PetscCall(PetscMalloc1(nv + 1, &vneighs));
6469de2952eSStefano Zampini     vneighs[0] = mvleaves;
6470b61a303SStefano Zampini     for (i = 0; i < nv; i++) {
6480b61a303SStefano Zampini       PetscCall(PetscSortInt(vcount[i], vneighs[i]));
6490b61a303SStefano Zampini       vneighs[i + 1] = vneighs[i] + vcount[i];
6509de2952eSStefano Zampini     }
6519de2952eSStefano Zampini   } else {
6529de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, NULL, &eneighs));
6539de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, NULL, &vneighs));
6549de2952eSStefano Zampini   }
6559de2952eSStefano Zampini 
6569566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
657a13144ffSStefano Zampini   if (print) {
6589566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGe, "edgerestr_lG"));
6599566063dSJacob Faibussowitsch     PetscCall(MatView(lGe, NULL));
6609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "edgerestr_lGt"));
6619566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
662a13144ffSStefano Zampini   }
6639566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
6649566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGt, &vals));
665a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
666637e8532SStefano Zampini     PetscInt  ord = order, test = ii[i + 1] - ii[i], vc = vcount[i];
6677d871cd7SStefano Zampini     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
668b03ebc13SStefano Zampini     if (!order) { /* variable order */
669dec27d64SStefano Zampini       PetscReal vorder = 0.;
670dec27d64SStefano Zampini 
671dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vorder += PetscRealPart(vals[j]);
672dec27d64SStefano Zampini       test = PetscFloorReal(vorder + 10. * PETSC_SQRT_MACHINE_EPSILON);
67363a3b9bcSJacob Faibussowitsch       PetscCheck(vorder - test <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected value for vorder: %g (%" PetscInt_FMT ")", (double)vorder, test);
674dec27d64SStefano Zampini       ord = 1;
675dec27d64SStefano Zampini     }
676637e8532SStefano Zampini     for (j = ii[i]; j < ii[i + 1] && sneighs; j++) {
6779de2952eSStefano Zampini       const PetscInt e = jj[j];
6789de2952eSStefano Zampini 
6799de2952eSStefano Zampini       if (PetscBTLookup(btbd, e)) {
6807d871cd7SStefano Zampini         bdir = PETSC_TRUE;
6817d871cd7SStefano Zampini         break;
6827d871cd7SStefano Zampini       }
6839de2952eSStefano Zampini       if (vc != ecount[e]) {
684637e8532SStefano Zampini         sneighs = PETSC_FALSE;
685637e8532SStefano Zampini       } else {
6869de2952eSStefano Zampini         const PetscInt *vn = vneighs[i], *en = eneighs[e];
6879de2952eSStefano Zampini 
6889de2952eSStefano Zampini         for (PetscInt k = 0; k < vc; k++) {
689637e8532SStefano Zampini           if (vn[k] != en[k]) {
690637e8532SStefano Zampini             sneighs = PETSC_FALSE;
691637e8532SStefano Zampini             break;
692637e8532SStefano Zampini           }
693637e8532SStefano Zampini         }
694637e8532SStefano Zampini       }
695637e8532SStefano Zampini     }
6960b61a303SStefano Zampini     if (elements_corners) test = 0;
6977d871cd7SStefano Zampini     if (!sneighs || test >= 3 * ord || bdir) { /* splitpoints */
6983ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "SPLITPOINT %" PetscInt_FMT " (%s %s %s)\n", i, PetscBools[!sneighs], PetscBools[test >= 3 * ord], PetscBools[bdir]));
6999566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
700dec27d64SStefano Zampini     } else if (test == ord) {
701b03ebc13SStefano Zampini       if (order == 1 || (!order && ii[i + 1] - ii[i] == 1)) {
7023ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINT %" PetscInt_FMT "\n", i));
7039566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btv, i));
7040b61a303SStefano Zampini       } else if (!elements_corners) {
7053ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "CORNER CANDIDATE %" PetscInt_FMT "\n", i));
7069566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btvcand, i));
707a13144ffSStefano Zampini       }
708a13144ffSStefano Zampini     }
709a13144ffSStefano Zampini   }
7109566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btbd));
711b03ebc13SStefano Zampini 
712b03ebc13SStefano Zampini   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
713b03ebc13SStefano Zampini   if (order != 1) {
7143ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "INSPECTING CANDIDATES\n"));
7159566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
716b03ebc13SStefano Zampini     for (i = 0; i < nv; i++) {
717b03ebc13SStefano Zampini       if (PetscBTLookup(btvcand, i)) {
718b03ebc13SStefano Zampini         PetscBool found = PETSC_FALSE;
719b03ebc13SStefano Zampini         for (j = ii[i]; j < ii[i + 1] && !found; j++) {
720b03ebc13SStefano Zampini           PetscInt k, e = jj[j];
721b03ebc13SStefano Zampini           if (PetscBTLookup(bte, e)) continue;
722b03ebc13SStefano Zampini           for (k = iit[e]; k < iit[e + 1]; k++) {
723b03ebc13SStefano Zampini             PetscInt v = jjt[k];
724b03ebc13SStefano Zampini             if (v != i && PetscBTLookup(btvcand, v)) {
725b03ebc13SStefano Zampini               found = PETSC_TRUE;
726b03ebc13SStefano Zampini               break;
727b03ebc13SStefano Zampini             }
728b03ebc13SStefano Zampini           }
729b03ebc13SStefano Zampini         }
730b03ebc13SStefano Zampini         if (!found) {
7313ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " CLEARED\n", i));
7329566063dSJacob Faibussowitsch           PetscCall(PetscBTClear(btvcand, i));
733b03ebc13SStefano Zampini         } else {
7343ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " ACCEPTED\n", i));
735b03ebc13SStefano Zampini         }
736b03ebc13SStefano Zampini       }
737b03ebc13SStefano Zampini     }
7389566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
739b03ebc13SStefano Zampini   }
7409566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGt, &vals));
7419566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
7429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGe));
743a13144ffSStefano Zampini 
744a13144ffSStefano Zampini   /* Get the local G^T explicitly */
7459566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
7469566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
7479566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGt, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
748a13144ffSStefano Zampini 
7499de2952eSStefano Zampini   /* Mark shared nodal dofs */
7509566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvi));
7519de2952eSStefano Zampini   for (i = 0; i < nv; i++) {
7529de2952eSStefano Zampini     if (vcount[i] > 1) PetscCall(PetscBTSet(btvi, i));
753a13144ffSStefano Zampini   }
7549de2952eSStefano Zampini 
7559de2952eSStefano Zampini   if (matis->allow_repeated) {
7569de2952eSStefano Zampini     PetscCall(PetscFree(eneighs[0]));
7579de2952eSStefano Zampini     PetscCall(PetscFree(vneighs[0]));
7589de2952eSStefano Zampini     PetscCall(PetscFree(eneighs));
7599de2952eSStefano Zampini     PetscCall(PetscFree(vneighs));
7609de2952eSStefano Zampini   }
7619de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(el2g, NULL, &ecount, &eneighs));
7629de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(vl2g, NULL, &vcount, &vneighs));
763a13144ffSStefano Zampini 
764a13144ffSStefano Zampini   /* communicate corners and splitpoints */
7659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nv, &vmarks));
7669566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvleaves, nv));
7679566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvroots, Lv));
7689371c9d4SSatish Balay   for (i = 0; i < nv; i++)
7699371c9d4SSatish Balay     if (PetscUnlikely(PetscBTLookup(btv, i))) sfvleaves[i] = 1;
770a13144ffSStefano Zampini 
771a13144ffSStefano Zampini   if (print) {
772a13144ffSStefano Zampini     IS tbz;
773a13144ffSStefano Zampini 
774a13144ffSStefano Zampini     cum = 0;
775a13144ffSStefano Zampini     for (i = 0; i < nv; i++)
7769371c9d4SSatish Balay       if (sfvleaves[i]) vmarks[cum++] = i;
777a13144ffSStefano Zampini 
7789566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
7799566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_local"));
7809566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
7819566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
782a13144ffSStefano Zampini   }
783a13144ffSStefano Zampini 
7849566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
7859566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
7869566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
7879566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
788a13144ffSStefano Zampini 
7894e64d54eSstefano_zampini   /* Zero rows of lGt corresponding to identified corners
7904e64d54eSstefano_zampini      and interior nodal dofs */
791a13144ffSStefano Zampini   cum = 0;
792a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
793a13144ffSStefano Zampini     if (sfvleaves[i]) {
794a13144ffSStefano Zampini       vmarks[cum++] = i;
7959566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
7969de2952eSStefano Zampini     } else if (!PetscBTLookup(btvi, i)) vmarks[cum++] = i;
797a13144ffSStefano Zampini   }
7989566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvi));
799a13144ffSStefano Zampini   if (print) {
800a13144ffSStefano Zampini     IS tbz;
801a13144ffSStefano Zampini 
8029566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
8039566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_with_interior"));
8049566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
8059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
806a13144ffSStefano Zampini   }
8079566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGt, cum, vmarks, 0., NULL, NULL));
8089566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmarks));
8099566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfv));
8109566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sfvleaves, sfvroots));
811a13144ffSStefano Zampini 
812a13144ffSStefano Zampini   /* Recompute G */
8139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
8149566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGt, MAT_INITIAL_MATRIX, &lG));
815a13144ffSStefano Zampini   if (print) {
8169566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "used_lG"));
8179566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
8189566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "used_lGt"));
8199566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
820a13144ffSStefano Zampini   }
821a13144ffSStefano Zampini 
822a13144ffSStefano Zampini   /* Get primal dofs (if any) */
823a13144ffSStefano Zampini   cum = 0;
824a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
825a13144ffSStefano Zampini     if (PetscUnlikely(PetscBTLookup(bte, i))) marks[cum++] = i;
826a13144ffSStefano Zampini   }
8271baa6e33SBarry Smith   if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, marks, marks));
8289566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, cum, marks, PETSC_COPY_VALUES, &primals));
829a13144ffSStefano Zampini   if (print) {
8309566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "prescribed_primal_dofs"));
8319566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
832a13144ffSStefano Zampini   }
8339566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bte));
834c2151214SStefano Zampini   /* TODO: what if the user passed in some of them ?  */
8359566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
8369566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&primals));
837a13144ffSStefano Zampini 
838a13144ffSStefano Zampini   /* Compute edge connectivity */
8399566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lG, "econn_"));
8404222ddf1SHong Zhang 
8414222ddf1SHong Zhang   /* Symbolic conn = lG*lGt */
8420b61a303SStefano Zampini   if (!elements_corners) { /* if present, we assume we are in the element-by-element case and the CSR graph is not needed */
8439566063dSJacob Faibussowitsch     PetscCall(MatProductCreate(lG, lGt, NULL, &conn));
8449566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(conn, MATPRODUCT_AB));
8459566063dSJacob Faibussowitsch     PetscCall(MatProductSetAlgorithm(conn, "default"));
8469566063dSJacob Faibussowitsch     PetscCall(MatProductSetFill(conn, PETSC_DEFAULT));
8479566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)conn, "econn_"));
8489566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(conn));
8499566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(conn));
8509566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
851c2151214SStefano Zampini     if (fl2g) {
852c2151214SStefano Zampini       PetscBT   btf;
853c2151214SStefano Zampini       PetscInt *iia, *jja, *iiu, *jju;
854c2151214SStefano Zampini       PetscBool rest = PETSC_FALSE, free = PETSC_FALSE;
855c2151214SStefano Zampini 
856c2151214SStefano Zampini       /* create CSR for all local dofs */
8579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n + 1, &iia));
858c2151214SStefano Zampini       if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
85963a3b9bcSJacob 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);
860c2151214SStefano Zampini         iiu = pcbddc->mat_graph->xadj;
861c2151214SStefano Zampini         jju = pcbddc->mat_graph->adjncy;
862c2151214SStefano Zampini       } else if (pcbddc->use_local_adj) {
863c2151214SStefano Zampini         rest = PETSC_TRUE;
8649566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
865c2151214SStefano Zampini       } else {
866c2151214SStefano Zampini         free = PETSC_TRUE;
8679566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(n + 1, &iiu, n, &jju));
868c2151214SStefano Zampini         iiu[0] = 0;
869c2151214SStefano Zampini         for (i = 0; i < n; i++) {
870c2151214SStefano Zampini           iiu[i + 1] = i + 1;
871c2151214SStefano Zampini           jju[i]     = -1;
872d904f53bSStefano Zampini         }
873c2151214SStefano Zampini       }
874c2151214SStefano Zampini 
875c2151214SStefano Zampini       /* import sizes of CSR */
876c2151214SStefano Zampini       iia[0] = 0;
877c2151214SStefano Zampini       for (i = 0; i < n; i++) iia[i + 1] = iiu[i + 1] - iiu[i];
878c2151214SStefano Zampini 
879c2151214SStefano Zampini       /* overwrite entries corresponding to the Nedelec field */
8809566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(n, &btf));
8819566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
882c2151214SStefano Zampini       for (i = 0; i < ne; i++) {
8839566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btf, idxs[i]));
884c2151214SStefano Zampini         iia[idxs[i] + 1] = ii[i + 1] - ii[i];
885c2151214SStefano Zampini       }
886c2151214SStefano Zampini 
887c2151214SStefano Zampini       /* iia in CSR */
888c2151214SStefano Zampini       for (i = 0; i < n; i++) iia[i + 1] += iia[i];
889c2151214SStefano Zampini 
890c2151214SStefano Zampini       /* jja in CSR */
8919566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(iia[n], &jja));
892c2151214SStefano Zampini       for (i = 0; i < n; i++)
893c2151214SStefano Zampini         if (!PetscBTLookup(btf, i))
8949371c9d4SSatish Balay           for (j = 0; j < iiu[i + 1] - iiu[i]; j++) jja[iia[i] + j] = jju[iiu[i] + j];
895c2151214SStefano Zampini 
896c2151214SStefano Zampini       /* map edge dofs connectivity */
8971e0482f5SStefano Zampini       if (jj) {
8989566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, ii[ne], jj, (PetscInt *)jj));
899c2151214SStefano Zampini         for (i = 0; i < ne; i++) {
900c2151214SStefano Zampini           PetscInt e = idxs[i];
901c2151214SStefano Zampini           for (j = 0; j < ii[i + 1] - ii[i]; j++) jja[iia[e] + j] = jj[ii[i] + j];
902c2151214SStefano Zampini         }
9031e0482f5SStefano Zampini       }
9049566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
9050b61a303SStefano Zampini       PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, iia, jja, PETSC_COPY_VALUES));
90648a46eb9SPierre Jolivet       if (rest) PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
9071baa6e33SBarry Smith       if (free) PetscCall(PetscFree2(iiu, jju));
9089566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btf));
909c2151214SStefano Zampini     } else {
9100b61a303SStefano Zampini       PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, ii, jj, PETSC_COPY_VALUES));
9110b61a303SStefano Zampini     }
9120b61a303SStefano Zampini     PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
9130b61a303SStefano Zampini     PetscCall(MatDestroy(&conn));
914c2151214SStefano Zampini   }
915c2151214SStefano Zampini 
916a13144ffSStefano Zampini   /* Analyze interface for edge dofs */
9179566063dSJacob Faibussowitsch   PetscCall(PCBDDCAnalyzeInterface(pc));
918213b8bfaSStefano Zampini   pcbddc->mat_graph->twodim = PETSC_FALSE;
919a13144ffSStefano Zampini 
920a13144ffSStefano Zampini   /* Get coarse edges in the edge space */
9219566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
922a13144ffSStefano Zampini 
923c2151214SStefano Zampini   if (fl2g) {
9249566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
9259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee, &eedges));
92648a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
927c2151214SStefano Zampini   } else {
928c2151214SStefano Zampini     eedges  = alleedges;
929c2151214SStefano Zampini     primals = allprimals;
930c2151214SStefano Zampini   }
931c2151214SStefano Zampini 
932a13144ffSStefano Zampini   /* Mark fine edge dofs with their coarse edge id */
9339566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(marks, ne));
9349566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
9359566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
936c2151214SStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = nee + 1;
9379566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
938c2151214SStefano Zampini   if (print) {
9399566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs"));
9409566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
941c2151214SStefano Zampini   }
942c2151214SStefano Zampini 
943c2151214SStefano Zampini   maxsize = 0;
944a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
945a13144ffSStefano Zampini     PetscInt size, mark = i + 1;
946a13144ffSStefano Zampini 
9479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
9489566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
949a13144ffSStefano Zampini     for (j = 0; j < size; j++) marks[idxs[j]] = mark;
9509566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
951a13144ffSStefano Zampini     maxsize = PetscMax(maxsize, size);
952a13144ffSStefano Zampini   }
953a13144ffSStefano Zampini 
954a13144ffSStefano Zampini   /* Find coarse edge endpoints */
9559566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
9569566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
957a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
958a13144ffSStefano Zampini     PetscInt mark = i + 1, size;
959a13144ffSStefano Zampini 
9609566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
9611e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
96263a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
9639566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
964a13144ffSStefano Zampini     if (print) {
96563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINTS ANALYSIS EDGE %" PetscInt_FMT "\n", i));
9669566063dSJacob Faibussowitsch       PetscCall(ISView(eedges[i], NULL));
967a13144ffSStefano Zampini     }
968a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
969a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
9703ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  idx %" PetscInt_FMT "\n", ee));
971a13144ffSStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
9723ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    inspect %" PetscInt_FMT "\n", jj[k]));
973a13144ffSStefano Zampini         if (PetscBTLookup(btv, jj[k])) {
9743ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      corner found (already set) %" PetscInt_FMT "\n", jj[k]));
975a13144ffSStefano Zampini         } else if (PetscBTLookup(btvcand, jj[k])) { /* is it ok? */
976a13144ffSStefano Zampini           PetscInt  k2;
977a13144ffSStefano Zampini           PetscBool corner = PETSC_FALSE;
978a13144ffSStefano Zampini           for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) {
9793ba16761SJacob 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])));
980c2151214SStefano Zampini             /* it's a corner if either is connected with an edge dof belonging to a different cc or
981c2151214SStefano Zampini                if the edge dof lie on the natural part of the boundary */
982c2151214SStefano Zampini             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb, jjt[k2]))) {
983a13144ffSStefano Zampini               corner = PETSC_TRUE;
984a13144ffSStefano Zampini               break;
985a13144ffSStefano Zampini             }
986a13144ffSStefano Zampini           }
987a13144ffSStefano Zampini           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
9883ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        corner found %" PetscInt_FMT "\n", jj[k]));
9899566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
990a13144ffSStefano Zampini           } else {
9913ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        no corners found\n"));
992a13144ffSStefano Zampini           }
993a13144ffSStefano Zampini         }
994a13144ffSStefano Zampini       }
995a13144ffSStefano Zampini     }
9969566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
997a13144ffSStefano Zampini   }
9989566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9999566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10009566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btb));
1001a13144ffSStefano Zampini 
1002a13144ffSStefano Zampini   /* Reset marked primal dofs */
10039566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
10049566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
1005a13144ffSStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = 0;
10069566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
1007a13144ffSStefano Zampini 
10080569b399SStefano Zampini   /* Now use the initial lG */
10099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
10109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
10110569b399SStefano Zampini   lG = lGinit;
10129566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
10130569b399SStefano Zampini 
1014a13144ffSStefano Zampini   /* Compute extended cols indices */
10159566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvc));
10169566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nee, &bter));
10179566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10189566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lG, &i));
1019a13144ffSStefano Zampini   i *= maxsize;
10209566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extcols));
10219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i, &extrow, i, &gidxs));
1022a13144ffSStefano Zampini   eerr = PETSC_FALSE;
1023a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1024b03ebc13SStefano Zampini     PetscInt size, found = 0;
1025a13144ffSStefano Zampini 
1026a13144ffSStefano Zampini     cum = 0;
10279566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
10281e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
102963a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10309566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
10319566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
1032a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
1033a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
1034b03ebc13SStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
1035b03ebc13SStefano Zampini         PetscInt vv = jj[k];
1036b03ebc13SStefano Zampini         if (!PetscBTLookup(btv, vv)) extrow[cum++] = vv;
1037b03ebc13SStefano Zampini         else if (!PetscBTLookupSet(btvc, vv)) found++;
1038b03ebc13SStefano Zampini       }
1039a13144ffSStefano Zampini     }
10409566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
10419566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
10429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
10439566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
10449566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1045a13144ffSStefano Zampini     /* it may happen that endpoints are not defined at this point
1046a13144ffSStefano Zampini        if it is the case, mark this edge for a second pass */
1047b03ebc13SStefano Zampini     if (cum != size - 1 || found != 2) {
10489566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(bter, i));
1049a13144ffSStefano Zampini       if (print) {
10509566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge"));
10519566063dSJacob Faibussowitsch         PetscCall(ISView(eedges[i], NULL));
10529566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol"));
10539566063dSJacob Faibussowitsch         PetscCall(ISView(extcols[i], NULL));
1054a13144ffSStefano Zampini       }
1055a13144ffSStefano Zampini       eerr = PETSC_TRUE;
1056a13144ffSStefano Zampini     }
1057a13144ffSStefano Zampini   }
105828b400f6SJacob Faibussowitsch   /* PetscCheck(!eerr,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
1059462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&eerr, &done, 1, MPIU_BOOL, MPI_LOR, comm));
1060a13144ffSStefano Zampini   if (done) {
1061a13144ffSStefano Zampini     PetscInt *newprimals;
1062a13144ffSStefano Zampini 
10639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &newprimals));
10649566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(primals, &cum));
10659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(primals, &idxs));
10669566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(newprimals, idxs, cum));
10679566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(primals, &idxs));
10689566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
10693ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOING SECOND PASS (eerr %s)\n", PetscBools[eerr]));
1070a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1071b03ebc13SStefano Zampini       PetscBool has_candidates = PETSC_FALSE;
1072b03ebc13SStefano Zampini       if (PetscBTLookup(bter, i)) {
1073a13144ffSStefano Zampini         PetscInt size, mark = i + 1;
1074a13144ffSStefano Zampini 
10759566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(eedges[i], &size));
10769566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(eedges[i], &idxs));
1077c2151214SStefano Zampini         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
1078a13144ffSStefano Zampini         for (j = 0; j < size; j++) {
1079a13144ffSStefano Zampini           PetscInt k, ee = idxs[j];
10803ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Inspecting edge dof %" PetscInt_FMT " [%" PetscInt_FMT " %" PetscInt_FMT ")\n", ee, ii[ee], ii[ee + 1]));
1081a13144ffSStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
1082a13144ffSStefano Zampini             /* set all candidates located on the edge as corners */
1083a13144ffSStefano Zampini             if (PetscBTLookup(btvcand, jj[k])) {
1084a13144ffSStefano Zampini               PetscInt k2, vv = jj[k];
1085b03ebc13SStefano Zampini               has_candidates = PETSC_TRUE;
10863ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Candidate set to vertex %" PetscInt_FMT "\n", vv));
10879566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(btv, vv));
1088a13144ffSStefano Zampini               /* set all edge dofs connected to candidate as primals */
1089a13144ffSStefano Zampini               for (k2 = iit[vv]; k2 < iit[vv + 1]; k2++) {
1090a13144ffSStefano Zampini                 if (marks[jjt[k2]] == mark) {
1091a13144ffSStefano Zampini                   PetscInt k3, ee2 = jjt[k2];
10923ba16761SJacob Faibussowitsch                   if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Connected edge dof set to primal %" PetscInt_FMT "\n", ee2));
1093a13144ffSStefano Zampini                   newprimals[cum++] = ee2;
1094a13144ffSStefano Zampini                   /* finally set the new corners */
1095a13144ffSStefano Zampini                   for (k3 = ii[ee2]; k3 < ii[ee2 + 1]; k3++) {
10963ba16761SJacob Faibussowitsch                     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Connected nodal dof set to vertex %" PetscInt_FMT "\n", jj[k3]));
10979566063dSJacob Faibussowitsch                     PetscCall(PetscBTSet(btv, jj[k3]));
1098a13144ffSStefano Zampini                   }
1099a13144ffSStefano Zampini                 }
1100a13144ffSStefano Zampini               }
1101b03ebc13SStefano Zampini             } else {
11023ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Not a candidate vertex %" PetscInt_FMT "\n", jj[k]));
1103a13144ffSStefano Zampini             }
1104a13144ffSStefano Zampini           }
1105a13144ffSStefano Zampini         }
1106b03ebc13SStefano Zampini         if (!has_candidates) { /* circular edge */
1107b03ebc13SStefano Zampini           PetscInt k, ee = idxs[0], *tmarks;
1108b03ebc13SStefano Zampini 
11099566063dSJacob Faibussowitsch           PetscCall(PetscCalloc1(ne, &tmarks));
11103ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Circular edge %" PetscInt_FMT "\n", i));
1111b03ebc13SStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
1112b03ebc13SStefano Zampini             PetscInt k2;
11133ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Set to corner %" PetscInt_FMT "\n", jj[k]));
11149566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
1115b03ebc13SStefano Zampini             for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) tmarks[jjt[k2]]++;
1116b03ebc13SStefano Zampini           }
1117b03ebc13SStefano Zampini           for (j = 0; j < size; j++) {
1118b03ebc13SStefano Zampini             if (tmarks[idxs[j]] > 1) {
11193ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge dof set to primal %" PetscInt_FMT "\n", idxs[j]));
1120b03ebc13SStefano Zampini               newprimals[cum++] = idxs[j];
1121b03ebc13SStefano Zampini             }
1122b03ebc13SStefano Zampini           }
11239566063dSJacob Faibussowitsch           PetscCall(PetscFree(tmarks));
1124b03ebc13SStefano Zampini         }
11259566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(eedges[i], &idxs));
1126a13144ffSStefano Zampini       }
11279566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&extcols[i]));
1128a13144ffSStefano Zampini     }
11299566063dSJacob Faibussowitsch     PetscCall(PetscFree(extcols));
11309566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
11319566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, newprimals));
1132c2151214SStefano Zampini     if (fl2g) {
11339566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, newprimals, newprimals));
11349566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&primals));
113548a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
11369566063dSJacob Faibussowitsch       PetscCall(PetscFree(eedges));
1137c2151214SStefano Zampini     }
11389566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
11399566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, newprimals, PETSC_COPY_VALUES, &primals));
11409566063dSJacob Faibussowitsch     PetscCall(PetscFree(newprimals));
11419566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
11429566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
11439566063dSJacob Faibussowitsch     PetscCall(PCBDDCAnalyzeInterface(pc));
1144213b8bfaSStefano Zampini     pcbddc->mat_graph->twodim = PETSC_FALSE;
11459566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
1146c2151214SStefano Zampini     if (fl2g) {
11479566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
11489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nee, &eedges));
114948a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
1150c2151214SStefano Zampini     } else {
1151c2151214SStefano Zampini       eedges  = alleedges;
1152c2151214SStefano Zampini       primals = allprimals;
1153c2151214SStefano Zampini     }
11549566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nee, &extcols));
1155a13144ffSStefano Zampini 
1156a13144ffSStefano Zampini     /* Mark again */
11579566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(marks, ne));
1158a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1159a13144ffSStefano Zampini       PetscInt size, mark = i + 1;
1160a13144ffSStefano Zampini 
11619566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
11629566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1163a13144ffSStefano Zampini       for (j = 0; j < size; j++) marks[idxs[j]] = mark;
11649566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1165a13144ffSStefano Zampini     }
1166a13144ffSStefano Zampini     if (print) {
11679566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs_secondpass"));
11689566063dSJacob Faibussowitsch       PetscCall(ISView(primals, NULL));
1169a13144ffSStefano Zampini     }
1170a13144ffSStefano Zampini 
1171a13144ffSStefano Zampini     /* Recompute extended cols */
1172a13144ffSStefano Zampini     eerr = PETSC_FALSE;
1173a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1174a13144ffSStefano Zampini       PetscInt size;
1175a13144ffSStefano Zampini 
1176a13144ffSStefano Zampini       cum = 0;
11779566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
11781e0482f5SStefano Zampini       if (!size && nedfieldlocal) continue;
117963a3b9bcSJacob Faibussowitsch       PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
11809566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1181a13144ffSStefano Zampini       for (j = 0; j < size; j++) {
1182a13144ffSStefano Zampini         PetscInt k, ee = idxs[j];
11839371c9d4SSatish Balay         for (k = ii[ee]; k < ii[ee + 1]; k++)
11849371c9d4SSatish Balay           if (!PetscBTLookup(btv, jj[k])) extrow[cum++] = jj[k];
1185a13144ffSStefano Zampini       }
11869566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
11879566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
11889566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
11899566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
11909566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1191a13144ffSStefano Zampini       if (cum != size - 1) {
1192a13144ffSStefano Zampini         if (print) {
11939566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge_secondpass"));
11949566063dSJacob Faibussowitsch           PetscCall(ISView(eedges[i], NULL));
11959566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol_secondpass"));
11969566063dSJacob Faibussowitsch           PetscCall(ISView(extcols[i], NULL));
1197a13144ffSStefano Zampini         }
1198a13144ffSStefano Zampini         eerr = PETSC_TRUE;
1199a13144ffSStefano Zampini       }
1200a13144ffSStefano Zampini     }
1201a13144ffSStefano Zampini   }
12029566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12039566063dSJacob Faibussowitsch   PetscCall(PetscFree2(extrow, gidxs));
12049566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bter));
12059566063dSJacob Faibussowitsch   if (print) PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, 5, PETSC_VIEWER_STDOUT_SELF));
1206a13144ffSStefano Zampini   /* an error should not occur at this point */
120728b400f6SJacob Faibussowitsch   PetscCheck(!eerr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1208a13144ffSStefano Zampini 
12094e64d54eSstefano_zampini   /* Check the number of endpoints */
12109566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * nee, &corners));
12129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &cedges));
12134e64d54eSstefano_zampini   for (i = 0; i < nee; i++) {
1214b03ebc13SStefano Zampini     PetscInt size, found = 0, gc[2];
12154e64d54eSstefano_zampini 
1216b03ebc13SStefano Zampini     /* init with defaults */
1217b03ebc13SStefano Zampini     cedges[i] = corners[i * 2] = corners[i * 2 + 1] = -1;
12189566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
12191e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
122063a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
12219566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
12229566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
12234e64d54eSstefano_zampini     for (j = 0; j < size; j++) {
12244e64d54eSstefano_zampini       PetscInt k, ee = idxs[j];
12254e64d54eSstefano_zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
12264e64d54eSstefano_zampini         PetscInt vv = jj[k];
12274e64d54eSstefano_zampini         if (PetscBTLookup(btv, vv) && !PetscBTLookupSet(btvc, vv)) {
1228467446fbSPierre Jolivet           PetscCheck(found != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more than two corners for edge %" PetscInt_FMT, i);
1229b03ebc13SStefano Zampini           corners[i * 2 + found++] = vv;
12304e64d54eSstefano_zampini         }
12314e64d54eSstefano_zampini       }
12324e64d54eSstefano_zampini     }
1233b03ebc13SStefano Zampini     if (found != 2) {
1234b03ebc13SStefano Zampini       PetscInt e;
1235b03ebc13SStefano Zampini       if (fl2g) {
12369566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, 1, idxs, &e));
1237b03ebc13SStefano Zampini       } else {
1238b03ebc13SStefano Zampini         e = idxs[0];
1239b03ebc13SStefano Zampini       }
124063a3b9bcSJacob 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]);
1241b03ebc13SStefano Zampini     }
1242eee23b56SStefano Zampini 
1243eee23b56SStefano Zampini     /* get primal dof index on this coarse edge */
12449566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, 2, corners + 2 * i, gc));
1245b03ebc13SStefano Zampini     if (gc[0] > gc[1]) {
1246b03ebc13SStefano Zampini       PetscInt swap      = corners[2 * i];
1247b03ebc13SStefano Zampini       corners[2 * i]     = corners[2 * i + 1];
1248b03ebc13SStefano Zampini       corners[2 * i + 1] = swap;
1249b03ebc13SStefano Zampini     }
1250eee23b56SStefano Zampini     cedges[i] = idxs[size - 1];
12519566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
12523ba16761SJacob 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]));
12534e64d54eSstefano_zampini   }
12549566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12559566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvc));
12564e64d54eSstefano_zampini 
125776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
1258a13144ffSStefano Zampini     /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1259a13144ffSStefano Zampini      not interfere with neighbouring coarse edges */
12609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee + 1, &emarks));
12619566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
1262a13144ffSStefano Zampini     for (i = 0; i < nv; i++) {
1263a13144ffSStefano Zampini       PetscInt emax = 0, eemax = 0;
1264a13144ffSStefano Zampini 
1265a13144ffSStefano Zampini       if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
12669566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(emarks, nee + 1));
1267a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) emarks[marks[jj[j]]]++;
1268a13144ffSStefano Zampini       for (j = 1; j < nee + 1; j++) {
1269a13144ffSStefano Zampini         if (emax < emarks[j]) {
1270a13144ffSStefano Zampini           emax  = emarks[j];
1271a13144ffSStefano Zampini           eemax = j;
1272a13144ffSStefano Zampini         }
1273a13144ffSStefano Zampini       }
1274a13144ffSStefano Zampini       /* not relevant for edges */
1275a13144ffSStefano Zampini       if (!eemax) continue;
1276a13144ffSStefano Zampini 
1277a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
12787a46b595SBarry 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]);
1279a13144ffSStefano Zampini       }
1280a13144ffSStefano Zampini     }
12819566063dSJacob Faibussowitsch     PetscCall(PetscFree(emarks));
12829566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
128376bd3646SJed Brown   }
1284a13144ffSStefano Zampini 
1285a13144ffSStefano Zampini   /* Compute extended rows indices for edge blocks of the change of basis */
12869566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12879566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lGt, &extmem));
1288a13144ffSStefano Zampini   extmem *= maxsize;
12899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(extmem * nee, &extrow));
12909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &extrows));
12919566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extrowcum));
1292a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
1293a13144ffSStefano Zampini     PetscInt mark = 0, size, start;
1294213b8bfaSStefano Zampini 
1295a13144ffSStefano Zampini     if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
1296a13144ffSStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++)
12979371c9d4SSatish Balay       if (marks[jj[j]] && !mark) mark = marks[jj[j]];
1298a13144ffSStefano Zampini 
1299a13144ffSStefano Zampini     /* not relevant */
1300a13144ffSStefano Zampini     if (!mark) continue;
1301a13144ffSStefano Zampini 
1302a13144ffSStefano Zampini     /* import extended row */
1303a13144ffSStefano Zampini     mark--;
1304a13144ffSStefano Zampini     start = mark * extmem + extrowcum[mark];
1305a13144ffSStefano Zampini     size  = ii[i + 1] - ii[i];
130663a3b9bcSJacob Faibussowitsch     PetscCheck(extrowcum[mark] + size <= extmem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not enough memory allocated %" PetscInt_FMT " > %" PetscInt_FMT, extrowcum[mark] + size, extmem);
13079566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(extrow + start, jj + ii[i], size));
1308a13144ffSStefano Zampini     extrowcum[mark] += size;
1309a13144ffSStefano Zampini   }
13109566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
13119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
13129566063dSJacob Faibussowitsch   PetscCall(PetscFree(marks));
1313213b8bfaSStefano Zampini 
1314213b8bfaSStefano Zampini   /* Compress extrows */
1315a13144ffSStefano Zampini   cum = 0;
1316a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1317a13144ffSStefano Zampini     PetscInt size = extrowcum[i], *start = extrow + i * extmem;
13189566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&size, start));
13199566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, start, PETSC_USE_POINTER, &extrows[i]));
1320a13144ffSStefano Zampini     cum = PetscMax(cum, size);
1321a13144ffSStefano Zampini   }
13229566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrowcum));
13239566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btv));
13249566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvcand));
1325a13144ffSStefano Zampini 
1326a13144ffSStefano Zampini   /* Workspace for lapack inner calls and VecSetValues */
13279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2((5 + cum + maxsize) * maxsize, &work, maxsize, &rwork));
1328a13144ffSStefano Zampini 
1329a13144ffSStefano Zampini   /* Create change of basis matrix (preallocation can be improved) */
13309566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
13319de2952eSStefano Zampini   PetscCall(MatSetLayouts(T, pc->mat->rmap, pc->mat->cmap));
13329566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
13339de2952eSStefano Zampini   PetscCall(MatSeqAIJSetPreallocation(T, maxsize, NULL));
13349de2952eSStefano Zampini   PetscCall(MatMPIAIJSetPreallocation(T, maxsize, NULL, maxsize, NULL));
13359566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
13369566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
13379566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
13389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1339a13144ffSStefano Zampini 
1340a13144ffSStefano Zampini   /* Defaults to identity */
13419de2952eSStefano Zampini   for (i = pc->mat->rmap->rstart; i < pc->mat->rmap->rend; i++) PetscCall(MatSetValue(T, i, i, 1.0, INSERT_VALUES));
1342a13144ffSStefano Zampini 
13431e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
13449566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
13459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
13461e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
13471e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
13481e0482f5SStefano Zampini     IS                     wis, gwis;
13491e0482f5SStefano Zampini     PetscInt               cnv, cne;
13501e0482f5SStefano Zampini 
13519566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
13521e0482f5SStefano Zampini     if (fl2g) {
13539566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
13541e0482f5SStefano Zampini     } else {
13559566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
13561e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
13571e0482f5SStefano Zampini     }
13589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
13599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13609566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
13619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
13629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13641e0482f5SStefano Zampini 
13659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
13669566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
13679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13689566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
13699566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
13709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13721e0482f5SStefano Zampini 
13739566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
13749566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
13759566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
13769566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
13779566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
13789566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
13799566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
13809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
13811e0482f5SStefano Zampini   }
13829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
13831e0482f5SStefano Zampini 
13841e0482f5SStefano Zampini #if defined(PRINT_GDET)
13851e0482f5SStefano Zampini   inc = 0;
13861e0482f5SStefano Zampini   lev = pcbddc->current_level;
13871e0482f5SStefano Zampini #endif
1388213b8bfaSStefano Zampini 
1389213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1390a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1391a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
13921e0482f5SStefano Zampini     IS          cornersis = NULL;
13931e0482f5SStefano Zampini     PetscScalar cvals[2];
1394a13144ffSStefano Zampini 
139548a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
13969566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1397a13144ffSStefano Zampini     if (Gins && GKins) {
13981683a169SBarry Smith       const PetscScalar *data;
1399a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1400a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1401a13144ffSStefano Zampini 
14029566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1403a13144ffSStefano Zampini       /* H1 */
14049566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
14059566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
14069566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
14079566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
14089566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
14099566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1410a13144ffSStefano Zampini       /* complement */
14119566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
141263a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
141363a3b9bcSJacob 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);
141463a3b9bcSJacob 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);
14159566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
14169566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
14179566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
14181e0482f5SStefano Zampini 
14191e0482f5SStefano Zampini       /* coarse discrete gradient */
14201e0482f5SStefano Zampini       if (pcbddc->nedcG) {
14211e0482f5SStefano Zampini         PetscInt cols[2];
14221e0482f5SStefano Zampini 
14231e0482f5SStefano Zampini         cols[0] = 2 * i;
14241e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
14259566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
14261e0482f5SStefano Zampini       }
14279566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1428a13144ffSStefano Zampini     }
14299566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
14309566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
14319566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
14329566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
14339566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1434a13144ffSStefano Zampini   }
14350b61a303SStefano Zampini 
14360b61a303SStefano Zampini   /* for FDM element-by-element: first dof on the edge only constraint. Why? */
14370b61a303SStefano Zampini   if (elements_corners && pcbddc->mat_graph->multi_element) {
14380b61a303SStefano Zampini     ISLocalToGlobalMapping map;
14390b61a303SStefano Zampini     MatNullSpace           nnsp;
14400b61a303SStefano Zampini     Vec                    quad_vec;
14410b61a303SStefano Zampini 
14420b61a303SStefano Zampini     PetscCall(MatCreateVecs(pc->pmat, &quad_vec, NULL));
14430b61a303SStefano Zampini     PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)pc), PETSC_FALSE, 1, &quad_vec, &nnsp));
14440b61a303SStefano Zampini     PetscCall(VecLockReadPop(quad_vec));
14450b61a303SStefano Zampini     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
14460b61a303SStefano Zampini     PetscCall(VecSetLocalToGlobalMapping(quad_vec, map));
14470b61a303SStefano Zampini     for (i = 0; i < nee; i++) {
14480b61a303SStefano Zampini       const PetscInt *idxs;
14490b61a303SStefano Zampini       PetscScalar     one = 1.0;
14500b61a303SStefano Zampini 
14510b61a303SStefano Zampini       PetscCall(ISGetLocalSize(alleedges[i], &cum));
14520b61a303SStefano Zampini       if (!cum) continue;
14530b61a303SStefano Zampini       PetscCall(ISGetIndices(alleedges[i], &idxs));
14540b61a303SStefano Zampini       PetscCall(VecSetValuesLocal(quad_vec, 1, idxs, &one, INSERT_VALUES));
14550b61a303SStefano Zampini       PetscCall(ISRestoreIndices(alleedges[i], &idxs));
14560b61a303SStefano Zampini     }
14570b61a303SStefano Zampini     PetscCall(VecLockReadPush(quad_vec));
14580b61a303SStefano Zampini     PetscCall(VecDestroy(&quad_vec));
14590b61a303SStefano Zampini     PetscCall(MatSetNearNullSpace(pc->pmat, nnsp));
14600b61a303SStefano Zampini     PetscCall(MatNullSpaceDestroy(&nnsp));
14610b61a303SStefano Zampini   }
14629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1463a13144ffSStefano Zampini 
1464a13144ffSStefano Zampini   /* Start assembling */
14659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
14661baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1467a13144ffSStefano Zampini 
1468a13144ffSStefano Zampini   /* Free */
1469c2151214SStefano Zampini   if (fl2g) {
14709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
147148a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
14729566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1473c2151214SStefano Zampini   }
1474eee23b56SStefano Zampini 
1475eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1476eee23b56SStefano Zampini   {
1477eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1478eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1479eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1480eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1481eee23b56SStefano Zampini 
1482eee23b56SStefano Zampini     /* find first primal edge */
1483eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
14849566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1485eee23b56SStefano Zampini     } else {
14861baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1487eee23b56SStefano Zampini       idxs = cedges;
1488eee23b56SStefano Zampini     }
1489eee23b56SStefano Zampini     cum = 0;
1490eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1491eee23b56SStefano Zampini 
1492eee23b56SStefano Zampini     /* adapt connected components */
14939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1494eee23b56SStefano Zampini     graph->cptr[0] = 0;
1495eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1496eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1497eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1498eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1499eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1500eee23b56SStefano Zampini         ncc++;
1501eee23b56SStefano Zampini         lc--;
1502eee23b56SStefano Zampini         cum++;
1503eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1504eee23b56SStefano Zampini       }
1505eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1506eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1507eee23b56SStefano Zampini       ncc++;
1508eee23b56SStefano Zampini     }
1509eee23b56SStefano Zampini     graph->ncc = ncc;
151048a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
15119566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1512eee23b56SStefano Zampini   }
15139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
15149566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
15159566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
1516eee23b56SStefano Zampini 
15179566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
15189566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
15199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
15209566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
15219566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
15229566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
15239566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
15249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1525a13144ffSStefano Zampini 
1526a13144ffSStefano Zampini   /* Complete assembling */
15279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
15289de2952eSStefano Zampini   PetscCall(MatViewFromOptions(T, (PetscObject)pc, "-pc_bddc_nedelec_change_view"));
15291e0482f5SStefano Zampini   if (pcbddc->nedcG) {
15309566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1531a4cdd7efSStefano Zampini     PetscCall(MatViewFromOptions(pcbddc->nedcG, (PetscObject)pc, "-pc_bddc_nedelec_coarse_change_view"));
15321e0482f5SStefano Zampini   }
1533a13144ffSStefano Zampini 
15340b61a303SStefano Zampini   PetscCall(ISDestroy(&elements_corners));
15350b61a303SStefano Zampini 
1536a13144ffSStefano Zampini   /* set change of basis */
15370b61a303SStefano Zampini   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, PETSC_FALSE));
15389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
15393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1540a13144ffSStefano Zampini }
1541a13144ffSStefano Zampini 
1542d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1543d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1544d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
1545d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1546d71ae5a4SJacob Faibussowitsch {
1547d8203eabSStefano Zampini   PetscInt i;
1548d8203eabSStefano Zampini 
1549d8203eabSStefano Zampini   PetscFunctionBegin;
1550d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1551d8203eabSStefano Zampini     PetscInt first, last;
1552d8203eabSStefano Zampini 
15539566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
15547827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1555d8203eabSStefano Zampini     if (i >= first && i < last) {
1556d8203eabSStefano Zampini       PetscScalar *data;
15579566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1558d8203eabSStefano Zampini       if (!has_const) {
1559d8203eabSStefano Zampini         data[i - first] = 1.;
1560d8203eabSStefano Zampini       } else {
156186fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
156286fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1563d8203eabSStefano Zampini       }
15649566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1565d8203eabSStefano Zampini     }
15669566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1567d8203eabSStefano Zampini   }
15689566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1569d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1570d8203eabSStefano Zampini     PetscInt first, last;
15719566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
15729566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1573d8203eabSStefano Zampini     if (i >= first && i < last) {
1574d8203eabSStefano Zampini       PetscScalar *data;
15759566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1576d8203eabSStefano Zampini       if (!has_const) {
1577d8203eabSStefano Zampini         data[i - first] = 0.;
1578d8203eabSStefano Zampini       } else {
157986fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
158086fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1581d8203eabSStefano Zampini       }
15829566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1583d8203eabSStefano Zampini     }
15849566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
15859566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1586d8203eabSStefano Zampini   }
15873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1588d8203eabSStefano Zampini }
1589d8203eabSStefano Zampini 
1590d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1591d71ae5a4SJacob Faibussowitsch {
1592a198735bSStefano Zampini   Mat                    loc_divudotp;
15939de2952eSStefano Zampini   Vec                    p, v, quad_vec;
15948ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
15959de2952eSStefano Zampini   PetscScalar           *array;
1596669cc0f4SStefano Zampini 
1597669cc0f4SStefano Zampini   PetscFunctionBegin;
15989566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
15998ae0ca82SStefano Zampini   if (!transpose) {
16009566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
16018ae0ca82SStefano Zampini   } else {
16029566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
16038ae0ca82SStefano Zampini   }
16049de2952eSStefano Zampini   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, 1, &quad_vec, nnsp));
16059de2952eSStefano Zampini   PetscCall(VecLockReadPop(quad_vec));
16069de2952eSStefano Zampini   PetscCall(VecSetLocalToGlobalMapping(quad_vec, map));
1607d8203eabSStefano Zampini 
1608669cc0f4SStefano Zampini   /* compute local quad vec */
16099566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
16108ae0ca82SStefano Zampini   if (!transpose) {
16119566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
16128ae0ca82SStefano Zampini   } else {
16139566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
16148ae0ca82SStefano Zampini   }
16159de2952eSStefano Zampini   /* the assumption here is that the constant vector interpolates the constant on the L2 conforming space */
16169566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
16178ae0ca82SStefano Zampini   if (!transpose) {
16189566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
16198ae0ca82SStefano Zampini   } else {
16209566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
16218ae0ca82SStefano Zampini   }
16229de2952eSStefano Zampini   PetscCall(VecDestroy(&p));
1623fa23a32eSStefano Zampini   if (vl2l) {
1624187c917aSStefano Zampini     Mat        lA;
1625187c917aSStefano Zampini     VecScatter sc;
16269de2952eSStefano Zampini     Vec        vins;
1627187c917aSStefano Zampini 
16289566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
16299566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
16309566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
16319566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
16329566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
16339566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
16349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&v));
16359de2952eSStefano Zampini     v = vins;
1636669cc0f4SStefano Zampini   }
16379de2952eSStefano Zampini 
16389de2952eSStefano Zampini   /* mask summation of interface values */
16399de2952eSStefano Zampini   PetscInt        n, *mmask, *mask, *idxs, nmr, nr;
16409de2952eSStefano Zampini   const PetscInt *degree;
16419de2952eSStefano Zampini   PetscSF         msf;
16429de2952eSStefano Zampini 
16439de2952eSStefano Zampini   PetscCall(VecGetLocalSize(v, &n));
16449de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nr, NULL, NULL, NULL));
16459de2952eSStefano Zampini   PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf));
16469de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
16479de2952eSStefano Zampini   PetscCall(PetscCalloc3(nmr, &mmask, n, &mask, n, &idxs));
16489de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &degree));
16499de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &degree));
16509de2952eSStefano Zampini   for (PetscInt i = 0, c = 0; i < nr; i++) {
16519de2952eSStefano Zampini     mmask[c] = 1;
16529de2952eSStefano Zampini     c += degree[i];
16539de2952eSStefano Zampini   }
16549de2952eSStefano Zampini   PetscCall(PetscSFScatterBegin(graph->interface_subset_sf, MPIU_INT, mmask, mask));
16559de2952eSStefano Zampini   PetscCall(PetscSFScatterEnd(graph->interface_subset_sf, MPIU_INT, mmask, mask));
16569de2952eSStefano Zampini   PetscCall(VecGetArray(v, &array));
16579de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
16589de2952eSStefano Zampini     array[i] *= mask[i];
16599de2952eSStefano Zampini     idxs[i] = i;
16609de2952eSStefano Zampini   }
16619de2952eSStefano Zampini   PetscCall(VecSetValuesLocal(quad_vec, n, idxs, array, ADD_VALUES));
16629de2952eSStefano Zampini   PetscCall(VecRestoreArray(v, &array));
16639de2952eSStefano Zampini   PetscCall(PetscFree3(mmask, mask, idxs));
16649de2952eSStefano Zampini   PetscCall(VecDestroy(&v));
16659de2952eSStefano Zampini   PetscCall(VecAssemblyBegin(quad_vec));
16669de2952eSStefano Zampini   PetscCall(VecAssemblyEnd(quad_vec));
16679de2952eSStefano Zampini   PetscCall(VecViewFromOptions(quad_vec, NULL, "-pc_bddc_quad_vec_view"));
16689de2952eSStefano Zampini   PetscCall(VecLockReadPush(quad_vec));
16699de2952eSStefano Zampini   PetscCall(VecDestroy(&quad_vec));
16703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1671669cc0f4SStefano Zampini }
1672669cc0f4SStefano Zampini 
1673d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1674d71ae5a4SJacob Faibussowitsch {
16757620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
16767620a527SStefano Zampini 
16777620a527SStefano Zampini   PetscFunctionBegin;
16787620a527SStefano Zampini   if (primalv) {
16797620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
16807620a527SStefano Zampini       IS list[2], newp;
16817620a527SStefano Zampini 
16827620a527SStefano Zampini       list[0] = primalv;
16837620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
16849566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
16859566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
16869566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
16877620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
16887620a527SStefano Zampini     } else {
16899566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
16907620a527SStefano Zampini     }
16917620a527SStefano Zampini   }
16923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16937620a527SStefano Zampini }
1694669cc0f4SStefano Zampini 
1695d71ae5a4SJacob Faibussowitsch static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1696d71ae5a4SJacob Faibussowitsch {
16971c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
16981c7a958bSStefano Zampini 
16991c7a958bSStefano Zampini   PetscFunctionBegin;
17001c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
17013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17021c7a958bSStefano Zampini }
1703674ae819SStefano Zampini 
1704d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1705d71ae5a4SJacob Faibussowitsch {
17061f4df5f7SStefano Zampini   Vec       local, global;
17071f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
17081f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
17095c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
17101f4df5f7SStefano Zampini 
17111f4df5f7SStefano Zampini   PetscFunctionBegin;
1712d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
17139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1714d0609cedSBarry Smith   PetscOptionsEnd();
17151f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
17169566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
17179566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
17189566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
17199566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
17206a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
172148a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
17226a8fc67bSStefano Zampini     goto boundary;
17236a8fc67bSStefano Zampini   }
17245c5e10d6SStefano Zampini 
17251f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
17261f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
17271f4df5f7SStefano Zampini       PetscInt i;
17280c85b387SStefano Zampini 
17299566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
17301f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
17310c85b387SStefano Zampini         PetscInt bs;
17320c85b387SStefano Zampini 
17339566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
17349566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
17359566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
17369566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
17371f4df5f7SStefano Zampini       }
17381f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
17391f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
17409566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
17411f4df5f7SStefano Zampini     }
17421f4df5f7SStefano Zampini   } else {
174321ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
174421ef3d20SStefano Zampini       DM dm;
174521ef3d20SStefano Zampini 
17469566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
174748a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
174821ef3d20SStefano Zampini       if (dm) {
174921ef3d20SStefano Zampini         IS      *fields;
175021ef3d20SStefano Zampini         PetscInt nf, i;
17510c85b387SStefano Zampini 
17529566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
17539566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
175421ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
17550c85b387SStefano Zampini           PetscInt bs;
17560c85b387SStefano Zampini 
17579566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
17589566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
17599566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
17609566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
176121ef3d20SStefano Zampini         }
17629566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
176321ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
176421ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
176521ef3d20SStefano Zampini         PetscContainer c;
176621ef3d20SStefano Zampini 
17679566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
176821ef3d20SStefano Zampini         if (c) {
176921ef3d20SStefano Zampini           MatISLocalFields lf;
17709566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
17719566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
177221ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
17731f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
17749566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
177521ef3d20SStefano Zampini           if (i > 1) {
1776986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
17779566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
177848a46eb9SPierre 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]));
17791f4df5f7SStefano Zampini           }
178021ef3d20SStefano Zampini         }
178121ef3d20SStefano Zampini       }
17827a0e7b2cSstefano_zampini     } else {
17837a0e7b2cSstefano_zampini       PetscInt i;
178448a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
17851f4df5f7SStefano Zampini     }
1786986cdee1SStefano Zampini   }
17871f4df5f7SStefano Zampini 
17885c5e10d6SStefano Zampini boundary:
17891f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
17909566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
17917a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
17929566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
17931f4df5f7SStefano Zampini   }
17941f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
17959566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
17967a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
17979566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
17981f4df5f7SStefano Zampini   }
179948a46eb9SPierre 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));
18009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
18019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
18029de2952eSStefano Zampini   /* detect local disconnected subdomains if requested or needed */
18039de2952eSStefano Zampini   if (pcbddc->detect_disconnected || matis->allow_repeated) {
18047620a527SStefano Zampini     IS        primalv = NULL;
18050b61a303SStefano Zampini     PetscInt  nel;
18068361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
18077a0e7b2cSstefano_zampini 
18080b61a303SStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
18099566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
18100b61a303SStefano Zampini     PetscCall(MatGetVariableBlockSizes(matis->A, &nel, NULL));
18110b61a303SStefano Zampini     if (matis->allow_repeated && nel) {
18120b61a303SStefano Zampini       const PetscInt *elsizes;
18130b61a303SStefano Zampini 
18140b61a303SStefano Zampini       pcbddc->n_local_subs = nel;
18150b61a303SStefano Zampini       PetscCall(MatGetVariableBlockSizes(matis->A, NULL, &elsizes));
18160b61a303SStefano Zampini       PetscCall(PetscMalloc1(nel, &pcbddc->local_subs));
18170b61a303SStefano Zampini       for (PetscInt i = 0, c = 0; i < nel; i++) {
18180b61a303SStefano Zampini         PetscCall(ISCreateStride(PETSC_COMM_SELF, elsizes[i], c, 1, &pcbddc->local_subs[i]));
18190b61a303SStefano Zampini         c += elsizes[i];
18200b61a303SStefano Zampini       }
18210b61a303SStefano Zampini     } else {
18229566063dSJacob Faibussowitsch       PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
18230b61a303SStefano Zampini     }
18249566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
18259566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
18267620a527SStefano Zampini   }
18277620a527SStefano Zampini   /* early stage corner detection */
18287620a527SStefano Zampini   {
18297620a527SStefano Zampini     DM dm;
18307620a527SStefano Zampini 
18319566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
183248a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
18337620a527SStefano Zampini     if (dm) {
18347620a527SStefano Zampini       PetscBool isda;
18357620a527SStefano Zampini 
18369566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
18377620a527SStefano Zampini       if (isda) {
18387620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
18397620a527SStefano Zampini         IS                     corners;
18407620a527SStefano Zampini         Mat                    lA;
18414f819b78SStefano Zampini         PetscBool              gl, lo;
18427620a527SStefano Zampini 
18434f819b78SStefano Zampini         {
18444f819b78SStefano Zampini           Vec                cvec;
18454f819b78SStefano Zampini           const PetscScalar *coords;
18464f819b78SStefano Zampini           PetscInt           dof, n, cdim;
18474f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
18484f819b78SStefano Zampini 
18499566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
18509566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
18519566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
18529566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
18534f819b78SStefano Zampini           n /= cdim;
18549566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
18559566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
18569566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
18574f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
18584f819b78SStefano Zampini           memc = PETSC_FALSE;
18594f819b78SStefano Zampini #endif
18604f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
18614f819b78SStefano Zampini           if (memc) {
18629566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
18634f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
18644f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
18654f819b78SStefano Zampini             PetscInt   i, b, d;
18664f819b78SStefano Zampini 
18674f819b78SStefano Zampini             for (i = 0; i < n; i++) {
18684f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
1869ad540459SPierre Jolivet                 for (d = 0; d < cdim; d++) bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]);
18704f819b78SStefano Zampini               }
18714f819b78SStefano Zampini             }
18724f819b78SStefano Zampini           }
18739566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
18744f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
18754f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
18764f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
18774f819b78SStefano Zampini         }
18789566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
18799566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
18809566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
18819566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
18824f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
1883462c564dSBarry Smith         PetscCallMPI(MPIU_Allreduce(&lo, &gl, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
18844f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
18857620a527SStefano Zampini           const PetscInt *idx;
188672ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
18877620a527SStefano Zampini 
18889566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
18899566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
18909566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
18919566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
189272ed36d8SStefano Zampini           if (bs == dof) {
18939566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
18949566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
189572ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
189672ed36d8SStefano Zampini             PetscInt i, d;
189772ed36d8SStefano Zampini 
18989566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
18999371c9d4SSatish Balay             for (i = 0; i < n; i++)
19009371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
19019566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
190272ed36d8SStefano Zampini 
190372ed36d8SStefano Zampini             bs = 1;
190472ed36d8SStefano Zampini             n *= dof;
190572ed36d8SStefano Zampini           }
19069566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
19079566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
19089566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
19099566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
19109566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
19111c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
19124f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
19134f819b78SStefano Zampini         }
191448a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
19157620a527SStefano Zampini       }
19167620a527SStefano Zampini     }
19177620a527SStefano Zampini   }
19181c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
19191c7a958bSStefano Zampini     DM dm;
19201c7a958bSStefano Zampini 
19219566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
192248a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
19234f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
19241c7a958bSStefano Zampini       Vec          vcoords;
19251c7a958bSStefano Zampini       PetscSection section;
19261c7a958bSStefano Zampini       PetscReal   *coords;
19271c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
19281c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
192951ab8ad6SStefano Zampini       /* debug coordinates */
193051ab8ad6SStefano Zampini       PetscViewer       viewer;
193151ab8ad6SStefano Zampini       PetscBool         flg;
193251ab8ad6SStefano Zampini       PetscViewerFormat format;
193351ab8ad6SStefano Zampini       const char       *prefix;
19341c7a958bSStefano Zampini 
19359566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
19369566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
19379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
19389566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
19399566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
19409566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
19419566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
19429566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
19431c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
19441c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
194551ab8ad6SStefano Zampini 
194651ab8ad6SStefano Zampini       /* debug coordinates */
194751ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
1948648c30bcSBarry Smith       PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
194951ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
19501c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
19511c7a958bSStefano Zampini         PetscInt           i;
19521c7a958bSStefano Zampini         const PetscScalar *v;
195351ab8ad6SStefano Zampini         char               name[16];
19541c7a958bSStefano Zampini 
19551c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
1956835f2295SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%" PetscInt_FMT, d));
195751ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
19589566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
195951ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
19609566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
19611c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
19629566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
19631c7a958bSStefano Zampini       }
19649566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
19659566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
19669566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
19679566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
19689566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
196951ab8ad6SStefano Zampini       if (flg) {
197051ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
1971648c30bcSBarry Smith         PetscCall(PetscViewerDestroy(&viewer));
197251ab8ad6SStefano Zampini       }
19731c7a958bSStefano Zampini     }
19741c7a958bSStefano Zampini   }
19753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19767a0e7b2cSstefano_zampini }
19777a0e7b2cSstefano_zampini 
1978d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
1979d71ae5a4SJacob Faibussowitsch {
1980f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
19817a0e7b2cSstefano_zampini   IS              nis;
19827a0e7b2cSstefano_zampini   const PetscInt *idxs;
19837a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
19847a0e7b2cSstefano_zampini 
19857a0e7b2cSstefano_zampini   PetscFunctionBegin;
198657508eceSPierre Jolivet   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
19877a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
19887a0e7b2cSstefano_zampini     /* init rootdata with true */
19891bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
19907a0e7b2cSstefano_zampini   } else {
19919566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
19927a0e7b2cSstefano_zampini   }
19939566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
19949566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
19959566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
19967a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
19979371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
19989566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
19999566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
20009566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
20019566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
20029566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
20037a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
20049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
20057a0e7b2cSstefano_zampini   } else {
20069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
20077a0e7b2cSstefano_zampini   }
20087a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
20099371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
2010f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)*is), nnd, nidxs, PETSC_OWN_POINTER, &nis));
20119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
20127a0e7b2cSstefano_zampini   *is = nis;
20133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20141f4df5f7SStefano Zampini }
20151f4df5f7SStefano Zampini 
2016d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z)
2017d71ae5a4SJacob Faibussowitsch {
2018f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2019f4f49eeaSPierre Jolivet   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
20203e589ea0SStefano Zampini 
20213e589ea0SStefano Zampini   PetscFunctionBegin;
20223ba16761SJacob Faibussowitsch   if (!pcbddc->benign_have_null) PetscFunctionReturn(PETSC_SUCCESS);
20233e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
20243e589ea0SStefano Zampini     Vec swap;
20253e589ea0SStefano Zampini 
20269566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
20273e589ea0SStefano Zampini     swap                = pcbddc->work_change;
20283e589ea0SStefano Zampini     pcbddc->work_change = r;
20293e589ea0SStefano Zampini     r                   = swap;
20303e589ea0SStefano Zampini   }
20319566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
20329566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
20339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
20349566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
20359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
20369566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
20379566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
20389566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
20399566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
20403e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
2041f913dca9SStefano Zampini     pcbddc->work_change = r;
20429566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
20439566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
20443e589ea0SStefano Zampini   }
20453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20463e589ea0SStefano Zampini }
20473e589ea0SStefano Zampini 
2048ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
2049d71ae5a4SJacob Faibussowitsch {
2050a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
2051a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
2052a3df083aSStefano Zampini 
2053a3df083aSStefano Zampini   PetscFunctionBegin;
20549566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
2055a3df083aSStefano Zampini   if (transpose) {
2056a3df083aSStefano Zampini     apply_right = ctx->apply_left;
2057a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
2058a3df083aSStefano Zampini   } else {
2059a3df083aSStefano Zampini     apply_right = ctx->apply_right;
2060a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
2061a3df083aSStefano Zampini   }
2062a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
2063a3df083aSStefano Zampini   if (apply_right) {
2064a3df083aSStefano Zampini     const PetscScalar *ax;
2065a3df083aSStefano Zampini     PetscInt           nl, i;
2066a3df083aSStefano Zampini 
20679566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
20689566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
20699566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
20709566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
2071a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2072a3df083aSStefano Zampini       PetscScalar     sum, val;
2073a3df083aSStefano Zampini       const PetscInt *idxs;
2074a3df083aSStefano Zampini       PetscInt        nz, j;
20759566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
20769566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2077a3df083aSStefano Zampini       sum = 0.;
2078a3df083aSStefano Zampini       if (ctx->apply_p0) {
2079a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
2080a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2081a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
2082a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
2083a3df083aSStefano Zampini         }
2084a3df083aSStefano Zampini       } else {
2085ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) sum += ctx->work[idxs[j]];
2086a3df083aSStefano Zampini       }
2087a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
20889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2089a3df083aSStefano Zampini     }
20909566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
2091a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
2092a3df083aSStefano Zampini   }
2093a3df083aSStefano Zampini   if (transpose) {
20949566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
2095a3df083aSStefano Zampini   } else {
20969566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
2097a3df083aSStefano Zampini   }
20981baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
2099a3df083aSStefano Zampini   if (apply_left) {
2100a3df083aSStefano Zampini     PetscScalar *ay;
2101a3df083aSStefano Zampini     PetscInt     i;
2102a3df083aSStefano Zampini 
21039566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
2104a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2105a3df083aSStefano Zampini       PetscScalar     sum, val;
2106a3df083aSStefano Zampini       const PetscInt *idxs;
2107a3df083aSStefano Zampini       PetscInt        nz, j;
21089566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
21099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2110a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
2111a3df083aSStefano Zampini       if (ctx->apply_p0) {
2112a3df083aSStefano Zampini         sum = 0.;
2113a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2114a3df083aSStefano Zampini           sum += ay[idxs[j]];
2115a3df083aSStefano Zampini           ay[idxs[j]] += val;
2116a3df083aSStefano Zampini         }
2117a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
2118a3df083aSStefano Zampini       } else {
2119ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) ay[idxs[j]] += val;
2120a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
2121a3df083aSStefano Zampini       }
21229566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2123a3df083aSStefano Zampini     }
21249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
2125a3df083aSStefano Zampini   }
21263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2127a3df083aSStefano Zampini }
2128a3df083aSStefano Zampini 
2129ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
2130d71ae5a4SJacob Faibussowitsch {
2131a3df083aSStefano Zampini   PetscFunctionBegin;
21329566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
21333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2134a3df083aSStefano Zampini }
2135a3df083aSStefano Zampini 
2136ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
2137d71ae5a4SJacob Faibussowitsch {
2138a3df083aSStefano Zampini   PetscFunctionBegin;
21399566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
21403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2141a3df083aSStefano Zampini }
2142a3df083aSStefano Zampini 
2143d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
2144d71ae5a4SJacob Faibussowitsch {
2145a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
2146a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
2147a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
2148a3df083aSStefano Zampini 
2149a3df083aSStefano Zampini   PetscFunctionBegin;
2150a3df083aSStefano Zampini   if (!restore) {
21511dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
2152a3df083aSStefano Zampini     PetscScalar       *work;
2153b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
2154a3df083aSStefano Zampini 
215528b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
21563ba16761SJacob Faibussowitsch     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(PETSC_SUCCESS);
21579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
21589566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
21599566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
21609566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
21619566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (void (*)(void))PCBDDCBenignMatMult_Private));
21629566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (void (*)(void))PCBDDCBenignMatMultTranspose_Private));
21639566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
21649566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
2165a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
2166a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
2167a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
2168a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
2169059032f7SStefano Zampini     if (reuse) {
2170a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
21711dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
2172059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
2173059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
2174059032f7SStefano Zampini       PetscInt               i;
2175059032f7SStefano Zampini 
21769566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
21779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
217848a46eb9SPierre 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]));
21799566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
21801dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
2181059032f7SStefano Zampini     }
2182a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
2183a3df083aSStefano Zampini     ctx->work = work;
21849566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
21859566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
21869566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
2187a3df083aSStefano Zampini     pcis->A_IB = A_IB;
2188a3df083aSStefano Zampini 
2189a3df083aSStefano Zampini     /* A_BI as A_IB^T */
21909566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
2191a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
2192a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
2193a3df083aSStefano Zampini   } else {
21943ba16761SJacob Faibussowitsch     if (!pcbddc->benign_original_mat) PetscFunctionReturn(PETSC_SUCCESS);
21959566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
21969566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2197a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
21981dd7afcfSStefano Zampini     ctx->A     = NULL;
21999566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
22001dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
22011dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
22021dd7afcfSStefano Zampini     if (ctx->free) {
2203059032f7SStefano Zampini       PetscInt i;
220448a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
22059566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2206059032f7SStefano Zampini     }
22079566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
22089566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2209a3df083aSStefano Zampini   }
22103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2211a3df083aSStefano Zampini }
2212a3df083aSStefano Zampini 
2213a3df083aSStefano Zampini /* used just in bddc debug mode */
2214ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2215d71ae5a4SJacob Faibussowitsch {
2216a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2217a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2218a3df083aSStefano Zampini   Mat      An;
2219a3df083aSStefano Zampini 
2220a3df083aSStefano Zampini   PetscFunctionBegin;
22219566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
22229566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2223a3df083aSStefano Zampini   if (is1) {
22249566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
22259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2226a3df083aSStefano Zampini   } else {
2227a3df083aSStefano Zampini     *B = An;
2228a3df083aSStefano Zampini   }
22293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2230a3df083aSStefano Zampini }
2231a3df083aSStefano Zampini 
22321cf9b237SStefano Zampini /* TODO: add reuse flag */
2233d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2234d71ae5a4SJacob Faibussowitsch {
22351cf9b237SStefano Zampini   Mat             Bt;
22361cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
22371cf9b237SStefano Zampini   const PetscInt *ii, *ij;
22381cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
22391cf9b237SStefano Zampini   PetscBool       flg_row;
22401cf9b237SStefano Zampini 
22411cf9b237SStefano Zampini   PetscFunctionBegin;
22429566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
22439566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
22449566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
22451cf9b237SStefano Zampini   nnz = n;
22461cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
22471cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
22481cf9b237SStefano Zampini   }
22499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
22509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
22519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
22521cf9b237SStefano Zampini   nnz    = 0;
22531cf9b237SStefano Zampini   bii[0] = 0;
22541cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
22551cf9b237SStefano Zampini     PetscInt j;
22561cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
22571cf9b237SStefano Zampini       PetscScalar entry = a[j];
22583272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
22591cf9b237SStefano Zampini         bij[nnz]   = ij[j];
22601cf9b237SStefano Zampini         bdata[nnz] = entry;
22611cf9b237SStefano Zampini         nnz++;
22621cf9b237SStefano Zampini       }
22631cf9b237SStefano Zampini     }
22641cf9b237SStefano Zampini     bii[i + 1] = nnz;
22651cf9b237SStefano Zampini   }
22669566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
22679566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
22689566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
22691cf9b237SStefano Zampini   {
2270f4f49eeaSPierre Jolivet     Mat_SeqAIJ *b = (Mat_SeqAIJ *)Bt->data;
22711cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
22721cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
22731cf9b237SStefano Zampini   }
227448a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
22751cf9b237SStefano Zampini   *B = Bt;
22763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22771cf9b237SStefano Zampini }
22781cf9b237SStefano Zampini 
2279d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv)
2280d71ae5a4SJacob Faibussowitsch {
2281c80a6c00SStefano Zampini   Mat                    B = NULL;
2282c80a6c00SStefano Zampini   DM                     dm;
22834f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
22844f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
22854f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2286c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
22874f1b2e48SStefano Zampini   PetscInt               i, n;
22884f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2289c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
22904f1b2e48SStefano Zampini 
22914f1b2e48SStefano Zampini   PetscFunctionBegin;
2292a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2293a2eca866SStefano Zampini   if (cc) *cc = NULL;
2294a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
22959566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
22969566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
229748a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
2298f9635d15SStefano Zampini   if (dm) PetscCall(PetscObjectTypeCompareAny((PetscObject)dm, &isplex, DMPLEX, DMP4EST, DMP8EST, ""));
22998361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
23008361f951SStefano Zampini 
2301c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2302c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2303c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2304c80a6c00SStefano Zampini     IS              cellNumbering;
2305c80a6c00SStefano Zampini     const PetscInt *cellNum;
2306c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2307c80a6c00SStefano Zampini     PetscSection    section;
2308c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2309c80a6c00SStefano Zampini     PetscSF         sfPoint;
2310c80a6c00SStefano Zampini 
2311f9635d15SStefano Zampini     PetscCall(DMConvert(dm, DMPLEX, &dm));
23129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
23139566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
23149566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2315c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
23169566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
23179566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
23189566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2319c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
23209566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
23219566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
23229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
23239566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2324c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2325c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
23269371c9d4SSatish Balay       if (nroots > 0) {
23279371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
23289371c9d4SSatish Balay       }
2329c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
23309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2331c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2332c80a6c00SStefano Zampini         const PetscInt point = adj[a];
23335cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2334c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
23359566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
23369566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2337c80a6c00SStefano Zampini           *pBuf = point;
2338c80a6c00SStefano Zampini         }
2339c80a6c00SStefano Zampini       }
2340c80a6c00SStefano Zampini       n++;
2341c80a6c00SStefano Zampini     }
23429566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2343c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
23449566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
23459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
23469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2347c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
23489371c9d4SSatish Balay       if (nroots > 0) {
23499371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
23509371c9d4SSatish Balay       }
2351f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetOffset(section, p, &xadj[idx++]));
2352c80a6c00SStefano Zampini     }
2353c80a6c00SStefano Zampini     xadj[n] = size;
23549566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2355c80a6c00SStefano Zampini     /* Clean up */
23569566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
23579566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
23589566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2359c80a6c00SStefano Zampini     graph->xadj   = xadj;
2360c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2361c80a6c00SStefano Zampini   } else {
2362c80a6c00SStefano Zampini     Mat       A;
23638361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2364c80a6c00SStefano Zampini 
23659566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
236663c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
23679566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
23683ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
236963c961adSStefano Zampini     }
23709566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
23714f1b2e48SStefano Zampini     if (!isseqaij && filter) {
23721cf9b237SStefano Zampini       PetscBool isseqdense;
23731cf9b237SStefano Zampini 
23749566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
23751cf9b237SStefano Zampini       if (!isseqdense) {
23769566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
23771cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
23781cf9b237SStefano Zampini         PetscScalar *array;
23791cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
23801cf9b237SStefano Zampini 
23819566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
23829566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
23839566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
23841cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
23851cf9b237SStefano Zampini           PetscInt j;
23861cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
23871cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
23881cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
23891cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
23901cf9b237SStefano Zampini           }
23911cf9b237SStefano Zampini         }
23929566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
23939566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
23941cf9b237SStefano Zampini       }
23954f1b2e48SStefano Zampini     } else {
23969566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
23974f1b2e48SStefano Zampini       B = A;
23984f1b2e48SStefano Zampini     }
23999566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
24004f1b2e48SStefano Zampini 
24014f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
24024f1b2e48SStefano Zampini     if (filter) {
24034f1b2e48SStefano Zampini       PetscScalar *data;
24044f1b2e48SStefano Zampini       PetscInt     j, cum;
24054f1b2e48SStefano Zampini 
24069566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
24079566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
24084f1b2e48SStefano Zampini       cum = 0;
24094f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
24104f1b2e48SStefano Zampini         PetscInt t;
24114f1b2e48SStefano Zampini 
24124f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
2413ad540459SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) continue;
24144f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
24154f1b2e48SStefano Zampini         }
24164f1b2e48SStefano Zampini         t                = xadj_filtered[i];
24174f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
24184f1b2e48SStefano Zampini         cum += t;
24194f1b2e48SStefano Zampini       }
24209566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
24214f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
24224f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
24234f1b2e48SStefano Zampini     } else {
24244f1b2e48SStefano Zampini       graph->xadj   = xadj;
24254f1b2e48SStefano Zampini       graph->adjncy = adjncy;
24264f1b2e48SStefano Zampini     }
2427c80a6c00SStefano Zampini   }
2428c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
24299de2952eSStefano Zampini   graph->seq_graph = PETSC_TRUE; /* analyze local connected components (i.e. disconnected subdomains) irrespective of dofs count */
24309566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
24319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
24329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
24331690c2aeSBarry Smith   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_INT_MAX));
24349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
24359566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
24369566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2437c80a6c00SStefano Zampini 
24384f1b2e48SStefano Zampini   /* partial clean up */
24399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2440c80a6c00SStefano Zampini   if (B) {
2441c80a6c00SStefano Zampini     PetscBool flg_row;
24429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
24439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
24444f1b2e48SStefano Zampini   }
2445c80a6c00SStefano Zampini   if (isplex) {
24469566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
24479566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2448c80a6c00SStefano Zampini   }
24494f1b2e48SStefano Zampini 
24504f1b2e48SStefano Zampini   /* get back data */
2451c80a6c00SStefano Zampini   if (isplex) {
2452c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2453c80a6c00SStefano Zampini     if (cc || primalv) {
2454c80a6c00SStefano Zampini       Mat          A;
2455f9635d15SStefano Zampini       PetscBT      btv, btvt, btvc;
2456c80a6c00SStefano Zampini       PetscSection subSection;
2457c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2458f9635d15SStefano Zampini       PetscInt     dim, cStart, cEnd, fStart, fEnd, vStart, vEnd, pStart, pEnd;
2459c80a6c00SStefano Zampini 
2460f9635d15SStefano Zampini       PetscCall(DMGetDimension(dm, &dim));
24619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
2462f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2463f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2464f9635d15SStefano Zampini       PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2465f9635d15SStefano Zampini       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
24669566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
24679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
24689566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
24699566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2470f9635d15SStefano Zampini       PetscCall(PetscBTCreate(pEnd - pStart, &btvc));
2471f9635d15SStefano Zampini 
2472f9635d15SStefano Zampini       /* First see if we find corners for the subdomains, i.e. a vertex
2473f9635d15SStefano Zampini          shared by at least dim subdomain boundary faces. This does not
2474f9635d15SStefano Zampini          cover all the possible cases with simplices but it is enough
2475f9635d15SStefano Zampini          for tensor cells */
2476f9635d15SStefano Zampini       if (vStart != fStart && dim <= 3) {
2477f9635d15SStefano Zampini         for (PetscInt c = cStart; c < cEnd; c++) {
2478f9635d15SStefano Zampini           PetscInt        nf, cnt = 0, mcnt = dim, *cfaces;
2479f9635d15SStefano Zampini           const PetscInt *faces;
2480f9635d15SStefano Zampini 
2481f9635d15SStefano Zampini           PetscCall(DMPlexGetConeSize(dm, c, &nf));
2482f9635d15SStefano Zampini           PetscCall(DMGetWorkArray(dm, nf, MPIU_INT, &cfaces));
2483f9635d15SStefano Zampini           PetscCall(DMPlexGetCone(dm, c, &faces));
2484f9635d15SStefano Zampini           for (PetscInt f = 0; f < nf; f++) {
2485f9635d15SStefano Zampini             PetscInt nc, ff;
2486f9635d15SStefano Zampini 
2487f9635d15SStefano Zampini             PetscCall(DMPlexGetSupportSize(dm, faces[f], &nc));
2488f9635d15SStefano Zampini             PetscCall(DMPlexGetTreeParent(dm, faces[f], &ff, NULL));
2489f9635d15SStefano Zampini             if (nc == 1 && faces[f] == ff) cfaces[cnt++] = faces[f];
2490f9635d15SStefano Zampini           }
2491f9635d15SStefano Zampini           if (cnt >= mcnt) {
2492f9635d15SStefano Zampini             PetscInt size, *closure = NULL;
2493f9635d15SStefano Zampini 
2494f9635d15SStefano Zampini             PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2495f9635d15SStefano Zampini             for (PetscInt k = 0; k < 2 * size; k += 2) {
2496f9635d15SStefano Zampini               PetscInt v = closure[k];
2497f9635d15SStefano Zampini               if (v >= vStart && v < vEnd) {
2498f9635d15SStefano Zampini                 PetscInt vsize, *vclosure = NULL;
2499f9635d15SStefano Zampini 
2500f9635d15SStefano Zampini                 cnt = 0;
2501f9635d15SStefano Zampini                 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2502f9635d15SStefano Zampini                 for (PetscInt vk = 0; vk < 2 * vsize; vk += 2) {
2503f9635d15SStefano Zampini                   PetscInt f = vclosure[vk];
2504f9635d15SStefano Zampini                   if (f >= fStart && f < fEnd) {
2505f9635d15SStefano Zampini                     PetscInt  nc, ff;
2506f9635d15SStefano Zampini                     PetscBool valid = PETSC_FALSE;
2507f9635d15SStefano Zampini 
2508f9635d15SStefano Zampini                     for (PetscInt fk = 0; fk < nf; fk++)
2509f9635d15SStefano Zampini                       if (f == cfaces[fk]) valid = PETSC_TRUE;
2510f9635d15SStefano Zampini                     if (!valid) continue;
2511f9635d15SStefano Zampini                     PetscCall(DMPlexGetSupportSize(dm, f, &nc));
2512f9635d15SStefano Zampini                     PetscCall(DMPlexGetTreeParent(dm, f, &ff, NULL));
2513f9635d15SStefano Zampini                     if (nc == 1 && f == ff) cnt++;
2514f9635d15SStefano Zampini                   }
2515f9635d15SStefano Zampini                 }
2516f9635d15SStefano Zampini                 if (cnt >= mcnt) PetscCall(PetscBTSet(btvc, v - pStart));
2517f9635d15SStefano Zampini                 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2518f9635d15SStefano Zampini               }
2519f9635d15SStefano Zampini             }
2520f9635d15SStefano Zampini             PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2521f9635d15SStefano Zampini           }
2522f9635d15SStefano Zampini           PetscCall(DMRestoreWorkArray(dm, nf, MPIU_INT, &cfaces));
2523f9635d15SStefano Zampini         }
2524f9635d15SStefano Zampini       }
2525c80a6c00SStefano Zampini 
2526c80a6c00SStefano Zampini       cids[0] = 0;
2527c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2528c80a6c00SStefano Zampini         PetscInt j;
2529c80a6c00SStefano Zampini 
25309566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2531c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2532c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2533c80a6c00SStefano Zampini 
25349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2535c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
253620c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2537c80a6c00SStefano Zampini 
25389566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
25399566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
25409566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2541c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2542c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2543f9635d15SStefano Zampini               if (PetscBTLookup(btvc, p - pStart)) pids[cump++] = off + s; /* subdomain corner */
2544f9635d15SStefano Zampini               else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2545e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2546c80a6c00SStefano Zampini             }
25479566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
254820c3699dSStefano Zampini             if (pp != p) {
25499566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
25509566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
25519566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
255220c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
255320c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2554f9635d15SStefano Zampini                 if (PetscBTLookup(btvc, pp - pStart)) pids[cump++] = off + s; /* subdomain corner */
2555f9635d15SStefano Zampini                 else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2556e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
255720c3699dSStefano Zampini               }
255820c3699dSStefano Zampini             }
2559c80a6c00SStefano Zampini           }
25609566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2561c80a6c00SStefano Zampini         }
2562c80a6c00SStefano Zampini         cids[i + 1] = cum;
2563c80a6c00SStefano Zampini         /* mark dofs as already assigned */
256448a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2565c80a6c00SStefano Zampini       }
2566c80a6c00SStefano Zampini       if (cc) {
25679566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
256848a46eb9SPierre 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]));
2569c80a6c00SStefano Zampini         *cc = cc_n;
2570c80a6c00SStefano Zampini       }
25711baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
25729566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
25739566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
25749566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2575f9635d15SStefano Zampini       PetscCall(PetscBTDestroy(&btvc));
2576f9635d15SStefano Zampini       PetscCall(DMDestroy(&dm));
2577c80a6c00SStefano Zampini     }
2578c80a6c00SStefano Zampini   } else {
25791cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
25801cf9b237SStefano Zampini     if (cc) {
25819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
258248a46eb9SPierre 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]));
25834f1b2e48SStefano Zampini       *cc = cc_n;
25841cf9b237SStefano Zampini     }
2585c80a6c00SStefano Zampini   }
25864f1b2e48SStefano Zampini   /* clean up graph */
25870a545947SLisandro Dalcin   graph->xadj   = NULL;
25880a545947SLisandro Dalcin   graph->adjncy = NULL;
25899566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
25903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25914f1b2e48SStefano Zampini }
25924f1b2e48SStefano Zampini 
2593d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2594d71ae5a4SJacob Faibussowitsch {
25955408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2596f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2597dee84bffSStefano Zampini   IS       dirIS  = NULL;
25984f1b2e48SStefano Zampini   PetscInt i;
25995408967cSStefano Zampini 
26005408967cSStefano Zampini   PetscFunctionBegin;
26019566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
26025408967cSStefano Zampini   if (zerodiag) {
26035408967cSStefano Zampini     Mat             A;
26045408967cSStefano Zampini     Vec             vec3_N;
26055408967cSStefano Zampini     PetscScalar    *vals;
26065408967cSStefano Zampini     const PetscInt *idxs;
2607d12d3064SStefano Zampini     PetscInt        nz, *count;
26085408967cSStefano Zampini 
26095408967cSStefano Zampini     /* p0 */
26109566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
26119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
26129566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
26139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
26144f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
26159566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
26169566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
26179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
26185408967cSStefano Zampini     /* v_I */
26199566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
26205408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
26219566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
26229566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
26239566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
26245408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
26259566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
26269566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
26275408967cSStefano Zampini     if (dirIS) {
26285408967cSStefano Zampini       PetscInt n;
26295408967cSStefano Zampini 
26309566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
26319566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
26325408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
26339566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
26349566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
26355408967cSStefano Zampini     }
26369566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
26379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
26389566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
26399566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
26409566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
26419566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
26429566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
26437827d75bSBarry 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]));
26449566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
26459566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2646d12d3064SStefano Zampini 
2647d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
26489566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
26499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2650d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
26519566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
26529566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
265363a3b9bcSJacob 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]);
26549566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
26559566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
26565408967cSStefano Zampini   }
26579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
26585408967cSStefano Zampini 
26595408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
26609566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
26614f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
26629566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
26634f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
26649566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2665f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2666f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
266763a3b9bcSJacob 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));
2668f2a566d8SStefano Zampini   }
26693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26705408967cSStefano Zampini }
26715408967cSStefano Zampini 
2672d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal)
2673d71ae5a4SJacob Faibussowitsch {
2674339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2675f4f49eeaSPierre Jolivet   Mat_IS   *matis     = (Mat_IS *)pc->pmat->data;
26763b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
26773b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
26784edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
26794edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2680339f8db1SStefano Zampini 
2681339f8db1SStefano Zampini   PetscFunctionBegin;
26823b03f7bbSStefano Zampini   if (reuse) goto project_b0;
26839566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
26849566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
268548a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
26869566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
26873b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
26883b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
26893b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
26903b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
26914f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
26924f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
26931ae86dd6SStefano Zampini      since the local Schur complements are already SPD
26944f1b2e48SStefano Zampini   */
269540fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
26967fbe2174Sstefano_zampini     IS        iP = NULL;
26973b03f7bbSStefano Zampini     PetscInt  p, *pp;
269847c5ace7SStefano Zampini     PetscBool flg, blocked = PETSC_FALSE;
26994f1b2e48SStefano Zampini 
27009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
27013b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2702d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
27039566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
270447c5ace7SStefano Zampini     PetscCall(PetscOptionsBool("-pc_bddc_pressure_blocked", "Use blocked pressure fields", NULL, blocked, &blocked, NULL));
2705d0609cedSBarry Smith     PetscOptionsEnd();
27063b03f7bbSStefano Zampini     if (!flg) {
27073b03f7bbSStefano Zampini       n     = 1;
27083b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
27093b03f7bbSStefano Zampini     }
27103b03f7bbSStefano Zampini 
27113b03f7bbSStefano Zampini     bsp = 0;
27123b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
271347c5ace7SStefano Zampini       PetscInt bs = 1;
27143b03f7bbSStefano Zampini 
271563a3b9bcSJacob 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]);
271647c5ace7SStefano Zampini       if (blocked) PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
27173b03f7bbSStefano Zampini       bsp += bs;
27183b03f7bbSStefano Zampini     }
27199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
27203b03f7bbSStefano Zampini     bsp = 0;
27213b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
27223b03f7bbSStefano Zampini       const PetscInt *idxs;
272347c5ace7SStefano Zampini       PetscInt        b, bs = 1, npl, *bidxs;
27243b03f7bbSStefano Zampini 
272547c5ace7SStefano Zampini       if (blocked) PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
27269566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
27279566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
27289566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
27293b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
27303b03f7bbSStefano Zampini         PetscInt i;
27313b03f7bbSStefano Zampini 
27323b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
27339566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
27343b03f7bbSStefano Zampini         bsp++;
27353b03f7bbSStefano Zampini       }
27369566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
27379566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
27383b03f7bbSStefano Zampini     }
27399566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
27403b03f7bbSStefano Zampini 
27417fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
27429566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
27437fbe2174Sstefano_zampini     if (iP) {
27447fbe2174Sstefano_zampini       IS newpressures;
27457fbe2174Sstefano_zampini 
27469566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
27479566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
27487fbe2174Sstefano_zampini       pressures = newpressures;
27497fbe2174Sstefano_zampini     }
27509566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
275148a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
27529566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
275340fa8d13SStefano Zampini   }
27543b03f7bbSStefano Zampini 
275597d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
27569566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
275727b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
27589566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
27599566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
276048a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
27619566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
27624edc6404Sstefano_zampini   zerodiag_save = zerodiag;
27639566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
27644f1b2e48SStefano Zampini   if (!nz) {
27654f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
27664f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
27679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
276840fa8d13SStefano Zampini   }
27694f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
27703b03f7bbSStefano Zampini 
27714f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
27724f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
27733b03f7bbSStefano Zampini   benign_n        = 0;
27741f4df5f7SStefano Zampini   n_interior_dofs = 0;
27751f4df5f7SStefano Zampini   interior_dofs   = NULL;
27764edc6404Sstefano_zampini   nneu            = 0;
277748a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
27783369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
27794edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
27809de2952eSStefano Zampini     PetscInt               n, i;
27819de2952eSStefano Zampini     PetscInt              *count;
27829de2952eSStefano Zampini     ISLocalToGlobalMapping mapping;
27831f4df5f7SStefano Zampini 
27849de2952eSStefano Zampini     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &mapping, NULL));
27859de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(mapping, &n, &count, NULL));
27869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
27871f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
27889de2952eSStefano Zampini       if (count[i] < 2) interior_dofs[n_interior_dofs++] = i;
27899de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(mapping, &n, &count, NULL));
27901f4df5f7SStefano Zampini   }
27914f1b2e48SStefano Zampini   if (has_null_pressures) {
27924f1b2e48SStefano Zampini     IS             *subs;
27934edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
27941f4df5f7SStefano Zampini     const PetscInt *idxs;
27951f4df5f7SStefano Zampini     PetscScalar    *array;
27961f4df5f7SStefano Zampini     Vec            *work;
27974f1b2e48SStefano Zampini 
27984f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
27994f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
28001f4df5f7SStefano 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) */
28014edc6404Sstefano_zampini     if (checkb) {
28029566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
28039566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
28049566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
28051f4df5f7SStefano Zampini       /* work[0] = 1_p */
28069566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
28079566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
28081f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
28099566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
28101f4df5f7SStefano Zampini       /* work[0] = 1_v */
28119566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
28129566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
28131f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
28149566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
28159566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
28161f4df5f7SStefano Zampini     }
28173b03f7bbSStefano Zampini 
28183b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
28193b03f7bbSStefano Zampini       IS      *is;
28203b03f7bbSStefano Zampini       PetscInt b, totb;
28213b03f7bbSStefano Zampini 
28223b03f7bbSStefano Zampini       totb  = bsp;
28233b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
28243b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
28259566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
28263b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
28274f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
28284f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
28294f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
28304f1b2e48SStefano Zampini           PetscInt               nl;
28314f1b2e48SStefano Zampini 
28323b03f7bbSStefano Zampini           if (subs) {
28339566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
28343b03f7bbSStefano Zampini           } else {
28353b03f7bbSStefano Zampini             IS tis;
28363b03f7bbSStefano Zampini 
28379566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
28389566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
28399566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
28409566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
28413b03f7bbSStefano Zampini           }
28429566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
28439566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
28444f1b2e48SStefano Zampini           if (nl) {
28454f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
28464f1b2e48SStefano Zampini 
28474edc6404Sstefano_zampini             if (checkb) {
28489566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
28499566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
28509566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
28519566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
28521f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
28539566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
28549566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
28559566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
28569566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
28579566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
28589566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
28591f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
28601f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
28611f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
28621f4df5f7SStefano Zampini                   break;
28631f4df5f7SStefano Zampini                 }
28641f4df5f7SStefano Zampini               }
28659566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
28661f4df5f7SStefano Zampini             }
28676632bad2Sstefano_zampini             if (valid && nneu) {
28686632bad2Sstefano_zampini               const PetscInt *idxs;
28691f4df5f7SStefano Zampini               PetscInt        nzb;
28701f4df5f7SStefano Zampini 
28719566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
28729566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
28739566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
28741f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
28751f4df5f7SStefano Zampini             }
28761f4df5f7SStefano Zampini             if (valid && pressures) {
28773b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
28783b03f7bbSStefano Zampini               PetscInt i1, i2;
28793b03f7bbSStefano Zampini 
28809566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
28819566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
28829566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
28839566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
28843b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
28859566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
28869566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
28874f1b2e48SStefano Zampini             }
28884f1b2e48SStefano Zampini             if (valid) {
28899566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
28903b03f7bbSStefano Zampini               benign_n++;
28913b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
28924f1b2e48SStefano Zampini           }
28939566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
28949566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
28954f1b2e48SStefano Zampini         }
28963b03f7bbSStefano Zampini       }
28974f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
28984f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
28991f4df5f7SStefano Zampini 
29006632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
290148a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
29024edc6404Sstefano_zampini       if (valid && checkb) {
29039566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
29049566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
29059566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
29061f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
29071f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
29081f4df5f7SStefano Zampini             valid = PETSC_FALSE;
29091f4df5f7SStefano Zampini             break;
29101f4df5f7SStefano Zampini           }
29111f4df5f7SStefano Zampini         }
29129566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
29131f4df5f7SStefano Zampini       }
29144f1b2e48SStefano Zampini       if (valid) {
29153b03f7bbSStefano Zampini         benign_n = 1;
29169566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
29179566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
29184f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
29194f1b2e48SStefano Zampini       }
29204f1b2e48SStefano Zampini     }
292148a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
29221f4df5f7SStefano Zampini   }
29239566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
29244f1b2e48SStefano Zampini 
29253b03f7bbSStefano Zampini   if (!benign_n) {
2926b9b0e38cSStefano Zampini     PetscInt n;
2927b9b0e38cSStefano Zampini 
29289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
29294f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
29309566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
293176a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
2932b9b0e38cSStefano Zampini   }
29334f1b2e48SStefano Zampini 
29344f1b2e48SStefano Zampini   /* final check for null pressures */
293548a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
29364f1b2e48SStefano Zampini 
29374f1b2e48SStefano Zampini   if (recompute_zerodiag) {
29389566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
29393b03f7bbSStefano Zampini     if (benign_n == 1) {
29409566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
29414f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
29424f1b2e48SStefano Zampini     } else {
29434f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
29444f1b2e48SStefano Zampini 
29454f1b2e48SStefano Zampini       nzn = 0;
29463b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
29474f1b2e48SStefano Zampini         PetscInt ns;
29489566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
29494f1b2e48SStefano Zampini         nzn += ns;
29504f1b2e48SStefano Zampini       }
29519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
29524f1b2e48SStefano Zampini       nzn = 0;
29533b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
29544f1b2e48SStefano Zampini         PetscInt ns, *idxs;
29559566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
29569566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
29579566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
29589566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
29594f1b2e48SStefano Zampini         nzn += ns;
29604f1b2e48SStefano Zampini       }
29619566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
29629566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
29634f1b2e48SStefano Zampini     }
29644f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
29654f1b2e48SStefano Zampini   }
29664f1b2e48SStefano Zampini 
29673b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
2968462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
29693b03f7bbSStefano Zampini 
2970669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
2971a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2972a198735bSStefano Zampini     Mat                    A, loc_divudotp;
2973a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
2974a198735bSStefano Zampini     IS                     row, col, isused = NULL;
2975a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
2976a198735bSStefano Zampini 
29771f4df5f7SStefano Zampini     if (pressures) {
29781f4df5f7SStefano Zampini       isused = pressures;
29791f4df5f7SStefano Zampini     } else {
29804edc6404Sstefano_zampini       isused = zerodiag_save;
29811f4df5f7SStefano Zampini     }
29829566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
29839566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
29849566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
29857827d75bSBarry 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");
2986a198735bSStefano Zampini     n_isused = 0;
298748a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
29889566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
2989a198735bSStefano Zampini     st = st - n_isused;
29901ae86dd6SStefano Zampini     if (n) {
2991a198735bSStefano Zampini       const PetscInt *gidxs;
2992a198735bSStefano Zampini 
29939566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
29949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
2995a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
29969566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
29979566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
29989566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
29991ae86dd6SStefano Zampini     } else {
30009566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
30019566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
30029566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
3003a198735bSStefano Zampini     }
30049566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
30059566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
30069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
30079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
30089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
30099566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
30109566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
30119566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
30129566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
30139566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
30149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30159566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
30169566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
30179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
30189566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
30199566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
30201ae86dd6SStefano Zampini   }
30219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
30229566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
30233b03f7bbSStefano Zampini   if (bzerodiag) {
30243b03f7bbSStefano Zampini     PetscInt i;
3025b3afcdbeSStefano Zampini 
302648a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
30279566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
30283b03f7bbSStefano Zampini   }
30293b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
30303b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
30313b03f7bbSStefano Zampini 
30323b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
30333b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
3034462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
30353b03f7bbSStefano Zampini 
30363b03f7bbSStefano Zampini project_b0:
30379566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
3038b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
30393b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
30404f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
30414f1b2e48SStefano Zampini 
3042339f8db1SStefano Zampini     /* local change of basis for pressures */
30439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
30449566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
30459566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
30469566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
30479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
3048aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
30494f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
3050aa0d93e9SStefano Zampini       const PetscInt *idxs;
30514f1b2e48SStefano Zampini       PetscInt        nzs, j;
30524f1b2e48SStefano Zampini 
30539566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
30549566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
30554f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
30564f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
30579566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
30584f1b2e48SStefano Zampini     }
30599566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
30609566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
30619566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
3062aa0d93e9SStefano Zampini     /* set identity by default */
306348a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
30649566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
30659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
3066339f8db1SStefano Zampini     /* set change on pressures */
30674f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
30684f1b2e48SStefano Zampini       PetscScalar    *array;
3069aa0d93e9SStefano Zampini       const PetscInt *idxs;
30704f1b2e48SStefano Zampini       PetscInt        nzs;
30714f1b2e48SStefano Zampini 
30729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
30739566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
30744f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
3075339f8db1SStefano Zampini         PetscScalar vals[2];
3076339f8db1SStefano Zampini         PetscInt    cols[2];
3077339f8db1SStefano Zampini 
3078339f8db1SStefano Zampini         cols[0] = idxs[i];
30794f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
3080339f8db1SStefano Zampini         vals[0] = 1.;
3081b0f5fe93SStefano Zampini         vals[1] = 1.;
30829566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
3083339f8db1SStefano Zampini       }
30849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
30854f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
30864f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
30879566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
30884f1b2e48SStefano Zampini       /* store local idxs for p0 */
30894f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
30909566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
30919566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
30924f1b2e48SStefano Zampini     }
30939566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
30949566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
30953b03f7bbSStefano Zampini 
3096a3df083aSStefano Zampini     /* project if needed */
3097a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
30981dd7afcfSStefano Zampini       Mat M;
30991dd7afcfSStefano Zampini 
31009566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
31019566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
31029566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
31039566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
3104a3df083aSStefano Zampini     }
31054f1b2e48SStefano Zampini     /* store global idxs for p0 */
31069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
3107339f8db1SStefano Zampini   }
3108339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
31093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3110339f8db1SStefano Zampini }
3111339f8db1SStefano Zampini 
3112d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
3113d71ae5a4SJacob Faibussowitsch {
3114efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
3115de9d7bd0SStefano Zampini   PetscScalar *array;
3116efc2fbd9SStefano Zampini 
3117efc2fbd9SStefano Zampini   PetscFunctionBegin;
3118efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
31199566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
31209566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
3121efc2fbd9SStefano Zampini   }
3122de9d7bd0SStefano Zampini   if (get) {
31239566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
31249566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
31259566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
31269566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
3127de9d7bd0SStefano Zampini   } else {
31289566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
31299566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
31309566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
31319566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
3132efc2fbd9SStefano Zampini   }
31333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3134efc2fbd9SStefano Zampini }
3135efc2fbd9SStefano Zampini 
3136d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
3137d71ae5a4SJacob Faibussowitsch {
3138c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3139c263805aSStefano Zampini 
3140c263805aSStefano Zampini   PetscFunctionBegin;
3141c263805aSStefano Zampini   /* TODO: add error checking
3142c263805aSStefano Zampini     - avoid nested pop (or push) calls.
3143c263805aSStefano Zampini     - cannot push before pop.
31441c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
3145c263805aSStefano Zampini   */
31463ba16761SJacob Faibussowitsch   if (!pcbddc->benign_n) PetscFunctionReturn(PETSC_SUCCESS);
3147c263805aSStefano Zampini   if (pop) {
3148a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
31494f1b2e48SStefano Zampini       IS       is_p0;
31504f1b2e48SStefano Zampini       MatReuse reuse;
3151c263805aSStefano Zampini 
3152c263805aSStefano Zampini       /* extract B_0 */
31534f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
3154ad540459SPierre Jolivet       if (pcbddc->benign_B0) reuse = MAT_REUSE_MATRIX;
31559566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
31569566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
3157c263805aSStefano Zampini       /* remove rows and cols from local problem */
31589566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
31599566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
31609566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
31619566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
3162a3df083aSStefano Zampini     } else {
3163a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
3164a3df083aSStefano Zampini       PetscScalar *vals;
3165a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
3166a3df083aSStefano Zampini 
31679566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
31689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
3169a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
31700b5adadeSStefano Zampini         PetscInt *nnz;
31719566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
31729566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
31739566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
31749566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
3175331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
31769566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
3177331e053bSStefano Zampini           nnz[i] = n - nnz[i];
3178331e053bSStefano Zampini         }
31799566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
31809566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
31819566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
3182331e053bSStefano Zampini       }
3183a3df083aSStefano Zampini 
3184a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
3185a3df083aSStefano Zampini         PetscScalar *array;
3186a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
3187a3df083aSStefano Zampini 
31889566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
31899566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
31909566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3191a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
31929566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
31939566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
31949566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
31959566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
31969566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
31979566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
3198a3df083aSStefano Zampini         cum = 0;
3199a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
320022db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
3201a3df083aSStefano Zampini             vals[cum]     = array[j];
3202a3df083aSStefano Zampini             idxs_ins[cum] = j;
3203a3df083aSStefano Zampini             cum++;
3204a3df083aSStefano Zampini           }
3205a3df083aSStefano Zampini         }
32069566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
32079566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
32089566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3209a3df083aSStefano Zampini       }
32109566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
32119566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
32129566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
3213a3df083aSStefano Zampini     }
3214c263805aSStefano Zampini   } else { /* push */
32154f1b2e48SStefano Zampini 
32160fdf79fbSJacob Faibussowitsch     PetscCheck(pcbddc->benign_change_explicit, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
32170fdf79fbSJacob Faibussowitsch     for (PetscInt i = 0; i < pcbddc->benign_n; i++) {
32184f1b2e48SStefano Zampini       PetscScalar *B0_vals;
32194f1b2e48SStefano Zampini       PetscInt    *B0_cols, B0_ncol;
32204f1b2e48SStefano Zampini 
32219566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
32229566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
32239566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
32249566063dSJacob Faibussowitsch       PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
32259566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
32264f1b2e48SStefano Zampini     }
32279566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
32289566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
3229c263805aSStefano Zampini   }
32303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3231c263805aSStefano Zampini }
3232c263805aSStefano Zampini 
3233d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
3234d71ae5a4SJacob Faibussowitsch {
3235b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
323608122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
323708122e43SStefano Zampini   PetscBLASInt    B_dummyint, B_neigs, B_ierr, B_lwork;
323808122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
323908122e43SStefano Zampini   PetscScalar    *work, lwork;
324008122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
324108122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
3242bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
32431b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
324432fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
324508122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
324608122e43SStefano Zampini   PetscReal *rwork;
324708122e43SStefano Zampini #endif
3248b1b3d7a2SStefano Zampini 
3249b1b3d7a2SStefano Zampini   PetscFunctionBegin;
32503ba16761SJacob Faibussowitsch   if (!pcbddc->adaptive_selection) PetscFunctionReturn(PETSC_SUCCESS);
325128b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
325232fe681dSStefano 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");
32539371c9d4SSatish 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,
32549371c9d4SSatish Balay              sub_schurs->is_posdef);
32559566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
325606a4e24aSStefano Zampini 
3257fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
325832fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
32599566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
32609566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
32619566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
32629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
3263fd14bc51SStefano Zampini   }
3264fd14bc51SStefano Zampini 
326548a46eb9SPierre 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));
3266e496cd5dSStefano Zampini 
326708122e43SStefano Zampini   /* max size of subsets */
326808122e43SStefano Zampini   mss = 0;
326908122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
327008122e43SStefano Zampini     PetscInt subset_size;
3271862806e4SStefano Zampini 
32729566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
327308122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
327408122e43SStefano Zampini   }
327508122e43SStefano Zampini 
327608122e43SStefano Zampini   /* min/max and threshold */
327708122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3278f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
327908122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3280f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3281bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3282f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3283f6f667cfSStefano Zampini   }
328408122e43SStefano Zampini 
328508122e43SStefano Zampini   /* allocate lapack workspace */
328608122e43SStefano Zampini   cum = cum2 = 0;
328708122e43SStefano Zampini   maxneigs   = 0;
328808122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
328908122e43SStefano Zampini     PetscInt n, subset_size;
3290f6f667cfSStefano Zampini 
32919566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
329208122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
32939162d606SStefano Zampini     cum += subset_size;
32949162d606SStefano Zampini     cum2 += subset_size * n;
329508122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
329608122e43SStefano Zampini   }
32977ebab0bbSStefano Zampini   lwork = 0;
329808122e43SStefano Zampini   if (mss) {
32997ebab0bbSStefano Zampini     PetscScalar  sdummy  = 0.;
330008122e43SStefano Zampini     PetscBLASInt B_itype = 1;
33016497c311SBarry Smith     PetscBLASInt B_N, idummy = 0;
33027ebab0bbSStefano Zampini     PetscReal    rdummy = 0., zero = 0.0;
33034c6709b3SStefano Zampini     PetscReal    eps = 0.0; /* dlamch? */
330408122e43SStefano Zampini 
33050fdf79fbSJacob Faibussowitsch     PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
33066497c311SBarry Smith     PetscCall(PetscBLASIntCast(mss, &B_N));
330708122e43SStefano Zampini     B_lwork = -1;
33087ebab0bbSStefano Zampini     /* some implementations may complain about NULL pointers, even if we are querying */
33097ebab0bbSStefano Zampini     S       = &sdummy;
33107ebab0bbSStefano Zampini     St      = &sdummy;
33117ebab0bbSStefano Zampini     eigs    = &rdummy;
33127ebab0bbSStefano Zampini     eigv    = &sdummy;
33137ebab0bbSStefano Zampini     B_iwork = &idummy;
33147ebab0bbSStefano Zampini     B_ifail = &idummy;
3315d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
33167ebab0bbSStefano Zampini     rwork = &rdummy;
3317d1710679SStefano Zampini #endif
33188bec7fa6SStefano Zampini     thresh = 1.0;
33199566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
332008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3321792fecdfSBarry 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));
332208122e43SStefano Zampini #else
3323792fecdfSBarry 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));
332408122e43SStefano Zampini #endif
3325835f2295SStefano Zampini     PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %" PetscBLASInt_FMT, B_ierr);
33269566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
332708122e43SStefano Zampini   }
332808122e43SStefano Zampini 
332908122e43SStefano Zampini   nv = 0;
3330d62866d3SStefano 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) */
33319566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
333208122e43SStefano Zampini   }
33339566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
333448a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
33359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
333608122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
33379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
333808122e43SStefano Zampini #endif
33399371c9d4SSatish 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,
33409371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
33419566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
334208122e43SStefano Zampini 
334308122e43SStefano Zampini   maxneigs = 0;
334472b8c272SStefano Zampini   cum = cumarray                           = 0;
33459162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
33469162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3347d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
334808122e43SStefano Zampini     const PetscInt *idxs;
334908122e43SStefano Zampini 
33509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
335108122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
335208122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
335308122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
335408122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
33559162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
33569162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
335708122e43SStefano Zampini     }
33589566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
335908122e43SStefano Zampini   }
336008122e43SStefano Zampini 
336108122e43SStefano Zampini   if (mss) { /* multilevel */
336232fe681dSStefano Zampini     if (sub_schurs->gdsw) {
336332fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
336432fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
336532fe681dSStefano Zampini     } else {
33669566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
33679566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
336808122e43SStefano Zampini     }
336932fe681dSStefano Zampini   }
337008122e43SStefano Zampini 
3371bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3372bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
337332fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
337408122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
337508122e43SStefano Zampini     const PetscInt *idxs;
33769d54b7f4SStefano Zampini     PetscReal       upper, lower;
3377862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
337808122e43SStefano Zampini     PetscBLASInt    B_N;
3379aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3380bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
338108122e43SStefano Zampini 
338232fe681dSStefano Zampini     if (upart) {
33839d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3384bd2a564bSStefano Zampini       lower = uthresh;
33859d54b7f4SStefano Zampini     } else {
338632fe681dSStefano Zampini       if (sub_schurs->gdsw) {
338732fe681dSStefano Zampini         upper = uthresh;
338832fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
338932fe681dSStefano Zampini       } else {
339028b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3391bd2a564bSStefano Zampini         upper = 1. / uthresh;
33929d54b7f4SStefano Zampini         lower = 0.;
33939d54b7f4SStefano Zampini       }
339432fe681dSStefano Zampini     }
33959566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
33969566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
33979566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3398bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3399bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3400bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3401bd2a564bSStefano Zampini       Mat T;
3402bd2a564bSStefano Zampini 
3403bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3404bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
34059566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
34069566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
34079566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
34089566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
34099566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
34109566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3411bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3412bd2a564bSStefano Zampini             PetscInt        nz, k;
3413bd2a564bSStefano Zampini             const PetscInt *idxs;
3414bd2a564bSStefano Zampini 
34159566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
34169566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3417bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3418bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3419bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3420bd2a564bSStefano Zampini             }
34219566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3422bd2a564bSStefano Zampini           }
3423bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3424bd2a564bSStefano Zampini           break;
3425bd2a564bSStefano Zampini         }
3426bd2a564bSStefano Zampini       }
3427bd2a564bSStefano Zampini     }
3428bd2a564bSStefano Zampini 
3429f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3430bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3431aff50787SStefano Zampini         PetscInt j, k;
3432580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
34339566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
34349566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
343508122e43SStefano Zampini         }
343608122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3437aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3438aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3439aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3440aff50787SStefano Zampini           }
344108122e43SStefano Zampini         }
344208122e43SStefano Zampini       } else {
34439566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34449566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
344508122e43SStefano Zampini       }
34468bec7fa6SStefano Zampini     } else {
3447f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3448f6f667cfSStefano Zampini       St = Starray + cumarray;
34498bec7fa6SStefano Zampini     }
3450aff50787SStefano Zampini     /* see if we can save some work */
345148a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3452aff50787SStefano Zampini 
3453b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3454aff50787SStefano Zampini       B_neigs = 0;
3455aff50787SStefano Zampini     } else {
345608122e43SStefano Zampini       PetscBLASInt B_itype = 1;
3457f6f667cfSStefano Zampini       PetscBLASInt B_IL, B_IU;
34584c6709b3SStefano Zampini       PetscReal    eps = -1.0; /* dlamch? */
34599552c7c7SStefano Zampini       PetscInt     nmin_s;
3460bd2a564bSStefano Zampini       PetscBool    compute_range;
3461bd2a564bSStefano Zampini 
34620fdf79fbSJacob Faibussowitsch       PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
34639036ceccSStefano Zampini       B_neigs       = 0;
3464bd2a564bSStefano Zampini       compute_range = (PetscBool)!same_data;
3465bd2a564bSStefano Zampini       if (nmin >= subset_size) compute_range = PETSC_FALSE;
346608122e43SStefano Zampini 
3467fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
3468a4cdd7efSStefano Zampini         PetscInt nc = 0, c = pcbddc->mat_graph->nodes[idxs[0]].count, w = pcbddc->mat_graph->nodes[idxs[0]].which_dof;
3469d16cbb6bSStefano Zampini 
347048a46eb9SPierre Jolivet         if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
34719de2952eSStefano Zampini         PetscCall(
34729de2952eSStefano Zampini           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, sub_schurs->n_subs, subset_size, c, w, compute_range, nc));
3473b7ab4a40SStefano Zampini       }
3474b7ab4a40SStefano Zampini 
34759566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3476b7ab4a40SStefano Zampini       if (compute_range) {
3477d16cbb6bSStefano Zampini         /* ask for eigenvalues larger than thresh */
3478bd2a564bSStefano Zampini         if (sub_schurs->is_posdef) {
347908122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3480792fecdfSBarry 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));
348108122e43SStefano Zampini #else
3482792fecdfSBarry 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));
348308122e43SStefano Zampini #endif
34849566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3485bd2a564bSStefano Zampini         } else { /* no theory so far, but it works nicely */
34869036ceccSStefano Zampini           PetscInt  recipe = 0, recipe_m = 1;
3487bd2a564bSStefano Zampini           PetscReal bb[2];
3488bd2a564bSStefano Zampini 
34899566063dSJacob Faibussowitsch           PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3490bd2a564bSStefano Zampini           switch (recipe) {
3491bd2a564bSStefano Zampini           case 0:
34929371c9d4SSatish Balay             if (scal) {
34939371c9d4SSatish Balay               bb[0] = PETSC_MIN_REAL;
34949371c9d4SSatish Balay               bb[1] = lthresh;
34959371c9d4SSatish Balay             } else {
34969371c9d4SSatish Balay               bb[0] = uthresh;
34979371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
34989371c9d4SSatish Balay             }
3499bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3500792fecdfSBarry 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));
3501bd2a564bSStefano Zampini #else
3502792fecdfSBarry 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));
3503bd2a564bSStefano Zampini #endif
35049566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3505bd2a564bSStefano Zampini             break;
3506d71ae5a4SJacob Faibussowitsch           case 1:
3507d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3508d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh * lthresh;
3509bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3510792fecdfSBarry 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));
3511bd2a564bSStefano Zampini #else
3512792fecdfSBarry 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));
3513bd2a564bSStefano Zampini #endif
35149566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3515bd2a564bSStefano Zampini             if (!scal) {
35169036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
3517bd2a564bSStefano Zampini 
35189371c9d4SSatish Balay               bb[0] = PetscMax(lthresh * lthresh, uthresh);
35199371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
35209566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35219566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3522bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3523792fecdfSBarry 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));
3524bd2a564bSStefano Zampini #else
3525792fecdfSBarry 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));
3526bd2a564bSStefano Zampini #endif
35279566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3528bd2a564bSStefano Zampini               B_neigs += B_neigs2;
3529bd2a564bSStefano Zampini             }
3530bd2a564bSStefano Zampini             break;
35319036ceccSStefano Zampini           case 2:
35329036ceccSStefano Zampini             if (scal) {
35339036ceccSStefano Zampini               bb[0] = PETSC_MIN_REAL;
35349036ceccSStefano Zampini               bb[1] = 0;
35359036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3536792fecdfSBarry 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));
35379036ceccSStefano Zampini #else
3538792fecdfSBarry 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));
35399036ceccSStefano Zampini #endif
35409566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35419036ceccSStefano Zampini             } else {
35429036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
354313bcc0bdSJacob Faibussowitsch               PetscBool    do_copy  = PETSC_FALSE;
35449036ceccSStefano Zampini 
35459036ceccSStefano Zampini               lthresh = PetscMax(lthresh, 0.0);
35469036ceccSStefano Zampini               if (lthresh > 0.0) {
35479036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
35489036ceccSStefano Zampini                 bb[1] = lthresh * lthresh;
35499036ceccSStefano Zampini 
355013bcc0bdSJacob Faibussowitsch                 do_copy = PETSC_TRUE;
35519036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3552792fecdfSBarry 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));
35539036ceccSStefano Zampini #else
3554792fecdfSBarry 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));
35559036ceccSStefano Zampini #endif
35569566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35579036ceccSStefano Zampini               }
35589036ceccSStefano Zampini               bb[0] = PetscMax(lthresh * lthresh, uthresh);
35599036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
356013bcc0bdSJacob Faibussowitsch               if (do_copy) {
35619566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35629566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
35639036ceccSStefano Zampini               }
35649036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3565792fecdfSBarry 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));
35669036ceccSStefano Zampini #else
3567792fecdfSBarry 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));
35689036ceccSStefano Zampini #endif
35699566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35709036ceccSStefano Zampini               B_neigs += B_neigs2;
35719036ceccSStefano Zampini             }
35729036ceccSStefano Zampini             break;
35739036ceccSStefano Zampini           case 3:
35749036ceccSStefano Zampini             if (scal) {
35759566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
35769036ceccSStefano Zampini             } else {
35779566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
35789036ceccSStefano Zampini             }
35799036ceccSStefano Zampini             if (!scal) {
35809036ceccSStefano Zampini               bb[0] = uthresh;
35819036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
35829036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3583792fecdfSBarry 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));
35849036ceccSStefano Zampini #else
3585792fecdfSBarry 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));
35869036ceccSStefano Zampini #endif
35879566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35889036ceccSStefano Zampini             }
35899036ceccSStefano Zampini             if (recipe_m > 0 && B_N - B_neigs > 0) {
35909036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
35919036ceccSStefano Zampini 
35929036ceccSStefano Zampini               B_IL = 1;
35939566063dSJacob Faibussowitsch               PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
35949566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35959566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
35969036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3597792fecdfSBarry 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));
35989036ceccSStefano Zampini #else
3599792fecdfSBarry 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));
36009036ceccSStefano Zampini #endif
36019566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
36029036ceccSStefano Zampini               B_neigs += B_neigs2;
36039036ceccSStefano Zampini             }
36049036ceccSStefano Zampini             break;
3605d71ae5a4SJacob Faibussowitsch           case 4:
3606d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3607d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh;
360848cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3609792fecdfSBarry 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));
361048cebe81SStefano Zampini #else
3611792fecdfSBarry 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));
361248cebe81SStefano Zampini #endif
36139566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
361448cebe81SStefano Zampini             {
361548cebe81SStefano Zampini               PetscBLASInt B_neigs2 = 0;
361648cebe81SStefano Zampini 
36179371c9d4SSatish Balay               bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
36189371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
36199566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
36209566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
362148cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3622792fecdfSBarry 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));
362348cebe81SStefano Zampini #else
3624792fecdfSBarry 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));
362548cebe81SStefano Zampini #endif
36269566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
362748cebe81SStefano Zampini               B_neigs += B_neigs2;
362848cebe81SStefano Zampini             }
362948cebe81SStefano Zampini             break;
363080db8efeSStefano Zampini           case 5: /* same as before: first compute all eigenvalues, then filter */
363180db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3632792fecdfSBarry 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));
363380db8efeSStefano Zampini #else
3634792fecdfSBarry 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));
363580db8efeSStefano Zampini #endif
36369566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
363780db8efeSStefano Zampini             {
363880db8efeSStefano Zampini               PetscInt e, k, ne;
363980db8efeSStefano Zampini               for (e = 0, ne = 0; e < B_neigs; e++) {
364080db8efeSStefano Zampini                 if (eigs[e] < lthresh || eigs[e] > uthresh) {
364180db8efeSStefano Zampini                   for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
364280db8efeSStefano Zampini                   eigs[ne] = eigs[e];
364380db8efeSStefano Zampini                   ne++;
364480db8efeSStefano Zampini                 }
364580db8efeSStefano Zampini               }
36469566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(eigv, S, B_N * ne));
36476497c311SBarry Smith               PetscCall(PetscBLASIntCast(ne, &B_neigs));
364880db8efeSStefano Zampini             }
364980db8efeSStefano Zampini             break;
3650d71ae5a4SJacob Faibussowitsch           default:
3651d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3652bd2a564bSStefano Zampini           }
3653bd2a564bSStefano Zampini         }
3654bd2a564bSStefano Zampini       } else if (!same_data) { /* this is just to see all the eigenvalues */
36556497c311SBarry Smith         PetscCall(PetscBLASIntCast(PetscMax(1, PetscMin(B_N, nmax)), &B_IU));
3656d16cbb6bSStefano Zampini         B_IL = 1;
3657d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3658792fecdfSBarry 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));
3659d16cbb6bSStefano Zampini #else
3660792fecdfSBarry 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));
3661d16cbb6bSStefano Zampini #endif
36629566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3663b03ebc13SStefano Zampini       } else { /* same_data is true, so just get the adaptive functional requested by the user */
3664b7ab4a40SStefano Zampini         PetscInt k;
366528b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
36669566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
36679566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3668b7ab4a40SStefano Zampini         nmin = nmax;
36699566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3670b7ab4a40SStefano Zampini         for (k = 0; k < nmax; k++) {
3671b7ab4a40SStefano Zampini           eigs[k]                     = 1. / PETSC_SMALL;
3672b7ab4a40SStefano Zampini           eigv[k * (subset_size + 1)] = 1.0;
3673b7ab4a40SStefano Zampini         }
3674d16cbb6bSStefano Zampini       }
36759566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
367608122e43SStefano Zampini       if (B_ierr) {
367763a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
367863a3b9bcSJacob 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);
367963a3b9bcSJacob 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);
368008122e43SStefano Zampini       }
368108122e43SStefano Zampini 
368208122e43SStefano Zampini       if (B_neigs > nmax) {
368348a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
368432fe681dSStefano Zampini         if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
36856497c311SBarry Smith         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
368608122e43SStefano Zampini       }
368708122e43SStefano Zampini 
36889552c7c7SStefano Zampini       nmin_s = PetscMin(nmin, B_N);
36899552c7c7SStefano Zampini       if (B_neigs < nmin_s) {
36909036ceccSStefano Zampini         PetscBLASInt B_neigs2 = 0;
369108122e43SStefano Zampini 
369232fe681dSStefano Zampini         if (upart) {
3693bd2a564bSStefano Zampini           if (scal) {
36946497c311SBarry Smith             PetscCall(PetscBLASIntCast(nmin_s, &B_IU));
3695bd2a564bSStefano Zampini             B_IL = B_neigs + 1;
3696bd2a564bSStefano Zampini           } else {
36976497c311SBarry Smith             PetscCall(PetscBLASIntCast(B_N - nmin_s + 1, &B_IL));
36989d54b7f4SStefano Zampini             B_IU = B_N - B_neigs;
3699bd2a564bSStefano Zampini           }
37009d54b7f4SStefano Zampini         } else {
37019d54b7f4SStefano Zampini           B_IL = B_neigs + 1;
37026497c311SBarry Smith           PetscCall(PetscBLASIntCast(nmin_s, &B_IU));
37039d54b7f4SStefano Zampini         }
3704fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
370563a3b9bcSJacob 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));
3706fd14bc51SStefano Zampini         }
3707bd2a564bSStefano Zampini         if (sub_schurs->is_symmetric) {
37081ae86dd6SStefano Zampini           PetscInt j, k;
370908122e43SStefano Zampini           for (j = 0; j < subset_size; j++) {
37101ae86dd6SStefano Zampini             for (k = j; k < subset_size; k++) {
37111ae86dd6SStefano Zampini               S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
37121ae86dd6SStefano Zampini               St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
371308122e43SStefano Zampini             }
371408122e43SStefano Zampini           }
371508122e43SStefano Zampini         } else {
37169566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
37179566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
371808122e43SStefano Zampini         }
37199566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
372008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3721792fecdfSBarry 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));
372208122e43SStefano Zampini #else
3723792fecdfSBarry 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));
372408122e43SStefano Zampini #endif
37259566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
37269566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
372708122e43SStefano Zampini         B_neigs += B_neigs2;
372808122e43SStefano Zampini       }
372908122e43SStefano Zampini       if (B_ierr) {
373063a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
373163a3b9bcSJacob 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);
373263a3b9bcSJacob 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);
373308122e43SStefano Zampini       }
3734fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
373563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
373608122e43SStefano Zampini         for (j = 0; j < B_neigs; j++) {
373732fe681dSStefano Zampini           if (!sub_schurs->gdsw) {
373808122e43SStefano Zampini             if (eigs[j] == 0.0) {
37399566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
374008122e43SStefano Zampini             } else {
374132fe681dSStefano Zampini               if (upart) {
374263a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
37439d54b7f4SStefano Zampini               } else {
3744835f2295SStefano Zampini                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1 / eigs[j + eigs_start])));
37459d54b7f4SStefano Zampini               }
3746fd14bc51SStefano Zampini             }
374732fe681dSStefano Zampini           } else {
374832fe681dSStefano Zampini             double pg = (double)eigs[j + eigs_start];
374932fe681dSStefano Zampini             if (pg < 2 * PETSC_SMALL) pg = 0.0;
375032fe681dSStefano Zampini             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
375132fe681dSStefano Zampini           }
375208122e43SStefano Zampini         }
375308122e43SStefano Zampini       }
3754aff50787SStefano Zampini     }
37556c3e6151SStefano Zampini     /* change the basis back to the original one */
37566c3e6151SStefano Zampini     if (sub_schurs->change) {
375772b8c272SStefano Zampini       Mat change, phi, phit;
37586c3e6151SStefano Zampini 
375903dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
37606c3e6151SStefano Zampini         PetscInt ii;
37616c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
376263a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
37636c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3764684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3765684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3766684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
376763a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3768684229deSStefano Zampini #else
376963a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3770684229deSStefano Zampini #endif
37716c3e6151SStefano Zampini           }
37726c3e6151SStefano Zampini         }
37736c3e6151SStefano Zampini       }
37749566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
37759566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
3776fb842aefSJose E. Roman       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &phi));
37779566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
37789566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
37799566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
37806c3e6151SStefano Zampini     }
37818bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
37828bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
37839162d606SStefano Zampini     if (B_neigs) {
37849566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3785fd14bc51SStefano Zampini 
3786fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
37879552c7c7SStefano Zampini         PetscInt ii;
37889552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
378963a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
37909552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3791ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3792ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3793ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
379463a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3795ac47001eSStefano Zampini #else
379663a3b9bcSJacob 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]])));
3797ac47001eSStefano Zampini #endif
37989552c7c7SStefano Zampini           }
37999552c7c7SStefano Zampini         }
3800fd14bc51SStefano Zampini       }
38019566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
38029162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
38039162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
38049162d606SStefano Zampini       cum++;
380508122e43SStefano Zampini     }
38069566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
380708122e43SStefano Zampini     /* shift for next computation */
380808122e43SStefano Zampini     cumarray += subset_size * subset_size;
380908122e43SStefano Zampini   }
38101baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
381108122e43SStefano Zampini 
381208122e43SStefano Zampini   if (mss) {
381332fe681dSStefano Zampini     if (sub_schurs->gdsw) {
381432fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
381532fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
381632fe681dSStefano Zampini     } else {
38179566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
38189566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3819f6f667cfSStefano Zampini       /* destroy matrices (junk) */
38209566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
38219566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
382208122e43SStefano Zampini     }
382332fe681dSStefano Zampini   }
38241baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
38259566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
382608122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
38279566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
382808122e43SStefano Zampini #endif
382908122e43SStefano Zampini   if (pcbddc->dbg_flag) {
38301b968477SStefano Zampini     PetscInt maxneigs_r;
3831462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
383263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
383308122e43SStefano Zampini   }
38349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
38353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
383608122e43SStefano Zampini }
3837b1b3d7a2SStefano Zampini 
3838d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3839d71ae5a4SJacob Faibussowitsch {
38409de2952eSStefano Zampini   Mat coarse_submat;
3841c8587f34SStefano Zampini 
3842c8587f34SStefano Zampini   PetscFunctionBegin;
3843f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
38445e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
38459566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3846c8587f34SStefano Zampini 
3847684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
38480fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
38499566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3850c8587f34SStefano Zampini 
38518629588bSStefano Zampini   /*
38528629588bSStefano Zampini      Setup local correction and local part of coarse basis.
38538629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
38548629588bSStefano Zampini   */
38559de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat));
38568629588bSStefano Zampini 
38578629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
38589de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat));
38599de2952eSStefano Zampini   PetscCall(MatDestroy(&coarse_submat));
38603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3861c8587f34SStefano Zampini }
3862c8587f34SStefano Zampini 
3863d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetCustomization(PC pc)
3864d71ae5a4SJacob Faibussowitsch {
3865674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3866674ae819SStefano Zampini 
3867674ae819SStefano Zampini   PetscFunctionBegin;
38689566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
38699566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
38709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
38719566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
38729566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
38739566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
38749566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
38759566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
38769566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
38779566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
38783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3879674ae819SStefano Zampini }
3880674ae819SStefano Zampini 
3881d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetTopography(PC pc)
3882d71ae5a4SJacob Faibussowitsch {
3883674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
38844f1b2e48SStefano Zampini   PetscInt i;
3885674ae819SStefano Zampini 
3886674ae819SStefano Zampini   PetscFunctionBegin;
38879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
38889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
38899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
38909566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
38919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
38929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
38939566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
38949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
38959566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
38969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
38979566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
389848a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
3899e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
39009566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
39019566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
3902c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
39038af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
39041c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
39053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3906674ae819SStefano Zampini }
3907674ae819SStefano Zampini 
3908d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetSolvers(PC pc)
3909d71ae5a4SJacob Faibussowitsch {
3910674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3911674ae819SStefano Zampini 
3912674ae819SStefano Zampini   PetscFunctionBegin;
39139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
39149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
39159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
39169566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
39179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
39189566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
39199566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
39209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
39219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
39229566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
39239566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
39249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
39259566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
39269566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
39279566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
39289566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
39299566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
39309566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
39319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
39329566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
39339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
39349566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
39359566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
39369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
39379566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
39389566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
39399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
39409566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
3941ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
3942ca92afb2SStefano Zampini     PetscInt i;
394348a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
39449566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
3945ca92afb2SStefano Zampini   }
39469566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
39473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3948674ae819SStefano Zampini }
3949674ae819SStefano Zampini 
3950d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
3951d71ae5a4SJacob Faibussowitsch {
39526bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
39536bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
39546bfb1811SStefano Zampini   VecType  impVecType;
39554f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
39566bfb1811SStefano Zampini 
39576bfb1811SStefano Zampini   PetscFunctionBegin;
39584f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3959b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
39609566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
3961e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
3962e7b262bdSStefano Zampini   /* R nodes */
3963e7b262bdSStefano Zampini   old_size = -1;
396448a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
3965e7b262bdSStefano Zampini   if (n_R != old_size) {
39669566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
39679566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
39689566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
39699566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
39709566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
39719566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
3972e7b262bdSStefano Zampini   }
3973e7b262bdSStefano Zampini   /* local primal dofs */
3974e7b262bdSStefano Zampini   old_size = -1;
397548a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
3976e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
39779566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
39789566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
39799566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
39809566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
3981e7b262bdSStefano Zampini   }
3982e7b262bdSStefano Zampini   /* local explicit constraints */
3983e7b262bdSStefano Zampini   old_size = -1;
398448a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
3985e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
39869566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
39879566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
39889566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
39899566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
399083b7ccabSStefano Zampini   }
39913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39926bfb1811SStefano Zampini }
39936bfb1811SStefano Zampini 
39949de2952eSStefano Zampini static PetscErrorCode MatSetValuesSubMat(Mat A, Mat S, PetscInt nr, const PetscInt rows[], PetscInt nc, const PetscInt cols[], InsertMode imode)
3995d71ae5a4SJacob Faibussowitsch {
39969de2952eSStefano Zampini   PetscBool          flg;
39979de2952eSStefano Zampini   const PetscScalar *a;
39989de2952eSStefano Zampini 
39999de2952eSStefano Zampini   PetscFunctionBegin;
40009de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQDENSE, &flg));
40019de2952eSStefano Zampini   if (flg) {
40029de2952eSStefano Zampini     PetscCall(MatDenseGetArrayRead(S, &a));
40039de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_FALSE));
40049de2952eSStefano Zampini     PetscCall(MatSetValues(A, nr, rows, nc, cols, a, imode));
40059de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_TRUE));
40069de2952eSStefano Zampini     PetscCall(MatDenseRestoreArrayRead(S, &a));
40079de2952eSStefano Zampini   } else {
40089de2952eSStefano Zampini     const PetscInt *ii, *jj;
40099de2952eSStefano Zampini     PetscInt        n;
40109de2952eSStefano Zampini     PetscInt        buf[8192], *bufc = NULL;
40119de2952eSStefano Zampini     PetscBool       freeb = PETSC_FALSE;
40129de2952eSStefano Zampini     Mat             Sm    = S;
40139de2952eSStefano Zampini 
40149de2952eSStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQAIJ, &flg));
40159de2952eSStefano Zampini     if (!flg) PetscCall(MatConvert(S, MATSEQAIJ, MAT_INITIAL_MATRIX, &Sm));
40169de2952eSStefano Zampini     else PetscCall(PetscObjectReference((PetscObject)S));
40179de2952eSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(Sm, &a));
40189de2952eSStefano Zampini     PetscCall(MatGetRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
40199de2952eSStefano Zampini     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot get IJ structure");
40209de2952eSStefano Zampini     if (nc <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
40219de2952eSStefano Zampini       bufc = buf;
40229de2952eSStefano Zampini     } else {
40239de2952eSStefano Zampini       PetscCall(PetscMalloc1(nc, &bufc));
40249de2952eSStefano Zampini       freeb = PETSC_TRUE;
40259de2952eSStefano Zampini     }
40269de2952eSStefano Zampini 
40279de2952eSStefano Zampini     for (PetscInt i = 0; i < n; i++) {
40289de2952eSStefano Zampini       const PetscInt nci = ii[i + 1] - ii[i];
40299de2952eSStefano Zampini 
40309de2952eSStefano Zampini       for (PetscInt j = 0; j < nci; j++) bufc[j] = cols[jj[ii[i] + j]];
40319de2952eSStefano Zampini       PetscCall(MatSetValues(A, 1, rows + i, nci, bufc, a + ii[i], imode));
40329de2952eSStefano Zampini     }
40339de2952eSStefano Zampini     PetscCall(MatRestoreRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
40349de2952eSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(Sm, &a));
40359de2952eSStefano Zampini     PetscCall(MatDestroy(&Sm));
40369de2952eSStefano Zampini     if (freeb) PetscCall(PetscFree(bufc));
40379de2952eSStefano Zampini   }
40389de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY));
40399de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY));
40409de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
40419de2952eSStefano Zampini }
40429de2952eSStefano Zampini 
40439de2952eSStefano Zampini static PetscErrorCode MatCreateSeqAIJFromDenseExpand(Mat D, PetscInt n, const PetscInt j[], Mat *mat)
40449de2952eSStefano Zampini {
40459de2952eSStefano Zampini   Mat_SeqAIJ        *aij;
40469de2952eSStefano Zampini   PetscInt          *ii, *jj;
40479de2952eSStefano Zampini   PetscScalar       *aa;
40489de2952eSStefano Zampini   PetscInt           nnz = 0, m, nc;
40499de2952eSStefano Zampini   const PetscScalar *a;
40509de2952eSStefano Zampini   const PetscScalar  zero = 0.0;
40519de2952eSStefano Zampini 
40529de2952eSStefano Zampini   PetscFunctionBegin;
40539de2952eSStefano Zampini   PetscCall(MatGetLocalSize(D, &m, &nc));
40549de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(D, &a));
40559de2952eSStefano Zampini   PetscCall(PetscMalloc1(m + 1, &ii));
40569de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &jj));
40579de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &aa));
40589de2952eSStefano Zampini   ii[0] = 0;
40599de2952eSStefano Zampini   for (PetscInt k = 0; k < m; k++) {
40609de2952eSStefano Zampini     for (PetscInt s = 0; s < nc; s++) {
40619de2952eSStefano Zampini       const PetscInt    c = s + k * nc;
40629de2952eSStefano Zampini       const PetscScalar v = a[k + s * m];
40639de2952eSStefano Zampini 
40649de2952eSStefano Zampini       if (PetscUnlikely(j[c] < 0 || v == zero)) continue;
40659de2952eSStefano Zampini       jj[nnz] = j[c];
40669de2952eSStefano Zampini       aa[nnz] = a[k + s * m];
40679de2952eSStefano Zampini       nnz++;
40689de2952eSStefano Zampini     }
40699de2952eSStefano Zampini     ii[k + 1] = nnz;
40709de2952eSStefano Zampini   }
40719de2952eSStefano Zampini 
40729de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)D), m, n, ii, jj, aa, mat));
40739de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(D, &a));
40749de2952eSStefano Zampini 
40759de2952eSStefano Zampini   aij          = (Mat_SeqAIJ *)(*mat)->data;
40769de2952eSStefano Zampini   aij->free_a  = PETSC_TRUE;
40779de2952eSStefano Zampini   aij->free_ij = PETSC_TRUE;
40789de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
40799de2952eSStefano Zampini }
40809de2952eSStefano Zampini 
40819de2952eSStefano Zampini /* adapted from MatInvertVariableBlockDiagonal_SeqAIJ */
40829de2952eSStefano Zampini static PetscErrorCode MatSeqAIJInvertVariableBlockDiagonalMat(Mat A, PetscInt nblocks, const PetscInt *bsizes, Mat *B)
40839de2952eSStefano Zampini {
40849de2952eSStefano Zampini   PetscInt        n = A->rmap->n, ncnt = 0, ncnt2 = 0, bsizemax = 0, *v_pivots = NULL;
40859de2952eSStefano Zampini   const PetscBool allowzeropivot    = PETSC_FALSE;
40869de2952eSStefano Zampini   PetscBool       zeropivotdetected = PETSC_FALSE;
40879de2952eSStefano Zampini   const PetscReal shift             = 0.0;
40889de2952eSStefano Zampini   PetscInt        ipvt[5], *ii, *jj, *indi, *indj;
40899de2952eSStefano Zampini   PetscScalar     work[25], *v_work = NULL, *aa, *diag;
40909de2952eSStefano Zampini   PetscLogDouble  flops = 0.0;
40919de2952eSStefano Zampini 
40929de2952eSStefano Zampini   PetscFunctionBegin;
40939de2952eSStefano Zampini   PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Not for rectangular matrices");
40949de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
40959de2952eSStefano Zampini     ncnt += bsizes[i];
40969de2952eSStefano Zampini     ncnt2 += PetscSqr(bsizes[i]);
40979de2952eSStefano Zampini   }
40989de2952eSStefano Zampini   PetscCheck(ncnt == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total blocksizes %" PetscInt_FMT " doesn't match number matrix rows %" PetscInt_FMT, ncnt, n);
40999de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]);
41009de2952eSStefano Zampini   if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots));
41019de2952eSStefano Zampini 
41029de2952eSStefano Zampini   PetscCall(PetscMalloc1(n + 1, &ii));
41039de2952eSStefano Zampini   PetscCall(PetscMalloc1(ncnt2, &jj));
41049de2952eSStefano Zampini   PetscCall(PetscCalloc1(ncnt2, &aa));
41059de2952eSStefano Zampini 
41069de2952eSStefano Zampini   ncnt  = 0;
41079de2952eSStefano Zampini   ii[0] = 0;
41089de2952eSStefano Zampini   indi  = ii;
41099de2952eSStefano Zampini   indj  = jj;
41109de2952eSStefano Zampini   diag  = aa;
41119de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
41129de2952eSStefano Zampini     const PetscInt bs = bsizes[i];
41139de2952eSStefano Zampini 
41149de2952eSStefano Zampini     for (PetscInt k = 0; k < bs; k++) {
41159de2952eSStefano Zampini       indi[k + 1] = indi[k] + bs;
41169de2952eSStefano Zampini       for (PetscInt j = 0; j < bs; j++) indj[k * bs + j] = ncnt + j;
41179de2952eSStefano Zampini     }
41189de2952eSStefano Zampini     PetscCall(MatGetValues(A, bs, indj, bs, indj, diag));
41199de2952eSStefano Zampini     switch (bs) {
41209de2952eSStefano Zampini     case 1:
41219de2952eSStefano Zampini       *diag = 1.0 / (*diag);
41229de2952eSStefano Zampini       break;
41239de2952eSStefano Zampini     case 2:
41249de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
41259de2952eSStefano Zampini       break;
41269de2952eSStefano Zampini     case 3:
41279de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
41289de2952eSStefano Zampini       break;
41299de2952eSStefano Zampini     case 4:
41309de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
41319de2952eSStefano Zampini       break;
41329de2952eSStefano Zampini     case 5:
41339de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
41349de2952eSStefano Zampini       break;
41359de2952eSStefano Zampini     case 6:
41369de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
41379de2952eSStefano Zampini       break;
41389de2952eSStefano Zampini     case 7:
41399de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
41409de2952eSStefano Zampini       break;
41419de2952eSStefano Zampini     default:
41429de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
41439de2952eSStefano Zampini     }
41449de2952eSStefano Zampini     ncnt += bs;
41459de2952eSStefano Zampini     flops += 2.0 * PetscPowInt(bs, 3) / 3.0;
41469de2952eSStefano Zampini     diag += bs * bs;
41479de2952eSStefano Zampini     indj += bs * bs;
41489de2952eSStefano Zampini     indi += bs;
41499de2952eSStefano Zampini   }
41509de2952eSStefano Zampini   PetscCall(PetscLogFlops(flops));
41519de2952eSStefano Zampini   PetscCall(PetscFree2(v_work, v_pivots));
41529de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, n, ii, jj, aa, B));
41539de2952eSStefano Zampini   {
41549de2952eSStefano Zampini     Mat_SeqAIJ *aij = (Mat_SeqAIJ *)(*B)->data;
41559de2952eSStefano Zampini     aij->free_a     = PETSC_TRUE;
41569de2952eSStefano Zampini     aij->free_ij    = PETSC_TRUE;
41579de2952eSStefano Zampini   }
41589de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
41599de2952eSStefano Zampini }
41609de2952eSStefano Zampini 
41619de2952eSStefano Zampini static PetscErrorCode MatDenseScatter(Mat A, PetscSF sf, Mat B)
41629de2952eSStefano Zampini {
41639de2952eSStefano Zampini   const PetscScalar *rarr;
41649de2952eSStefano Zampini   PetscScalar       *larr;
41659de2952eSStefano Zampini   PetscSF            vsf;
41669de2952eSStefano Zampini   PetscInt           n, rld, lld;
41679de2952eSStefano Zampini 
41689de2952eSStefano Zampini   PetscFunctionBegin;
41699de2952eSStefano Zampini   PetscCall(MatGetSize(A, NULL, &n));
41709de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(A, &rld));
41719de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(B, &lld));
41729de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(A, &rarr));
41739de2952eSStefano Zampini   PetscCall(MatDenseGetArrayWrite(B, &larr));
41749de2952eSStefano Zampini   PetscCall(PetscSFCreateStridedSF(sf, n, rld, lld, &vsf));
41759de2952eSStefano Zampini   PetscCall(PetscSFBcastBegin(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
41769de2952eSStefano Zampini   PetscCall(PetscSFBcastEnd(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
41779de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(A, &rarr));
41789de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayWrite(B, &larr));
41799de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&vsf));
41809de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
41819de2952eSStefano Zampini }
41829de2952eSStefano Zampini 
41839de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCorrection(PC pc, Mat *coarse_submat)
41849de2952eSStefano Zampini {
418588ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
418688ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
41879de2952eSStefano Zampini   PCBDDCGraph     graph      = pcbddc->mat_graph;
4188d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
418925084f0cSStefano Zampini   /* submatrices of local problem */
41909de2952eSStefano Zampini   Mat A_RV = NULL, A_VR, A_VV, local_auxmat2_R = NULL;
419106656605SStefano Zampini   /* submatrices of local coarse problem */
41929de2952eSStefano Zampini   Mat S_CV = NULL, S_VC = NULL, S_CC = NULL;
419325084f0cSStefano Zampini   /* working matrices */
419406656605SStefano Zampini   Mat C_CR;
41959de2952eSStefano Zampini 
419625084f0cSStefano Zampini   /* additional working stuff */
419706656605SStefano Zampini   PC              pc_R;
41989de2952eSStefano Zampini   IS              is_R, is_V, is_C;
41999de2952eSStefano Zampini   const PetscInt *idx_V, *idx_C;
4200c58f9fdbSStefano Zampini   Mat             F, Brhs = NULL;
42015cbda25cSStefano Zampini   Vec             dummy_vec;
42027ebab0bbSStefano Zampini   PetscBool       isLU, isCHOL, need_benign_correction, sparserhs;
420306656605SStefano Zampini   PetscInt       *idx_V_B;
42049de2952eSStefano Zampini   PetscInt        lda_rhs, n_vertices, n_constraints, *p0_lidx_I;
42059de2952eSStefano Zampini   PetscInt        n_eff_vertices, n_eff_constraints;
420606656605SStefano Zampini   PetscInt        i, n_R, n_D, n_B;
420706656605SStefano Zampini   PetscScalar     one = 1.0, m_one = -1.0;
420888ebb749SStefano Zampini 
42099de2952eSStefano Zampini   /* Multi-element support */
42109de2952eSStefano Zampini   PetscBool multi_element = graph->multi_element;
42119de2952eSStefano Zampini   PetscInt *V_to_eff_V = NULL, *C_to_eff_C = NULL;
42129de2952eSStefano Zampini   PetscInt *B_eff_V_J = NULL, *R_eff_V_J = NULL, *B_eff_C_J = NULL, *R_eff_C_J = NULL;
42139de2952eSStefano Zampini   IS        is_C_perm = NULL;
42149de2952eSStefano Zampini   PetscInt  n_C_bss = 0, *C_bss = NULL;
42159de2952eSStefano Zampini   Mat       coarse_phi_multi;
42169de2952eSStefano Zampini 
421788ebb749SStefano Zampini   PetscFunctionBegin;
42187827d75bSBarry 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");
42199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
4220ffd830a3SStefano Zampini 
4221ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
4222b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
42234f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
4224b371cd4fSStefano Zampini   n_B           = pcis->n_B;
4225b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
422688ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
422788ebb749SStefano Zampini 
422888ebb749SStefano Zampini   /* vertices in boundary numbering */
42299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
42309566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
423163a3b9bcSJacob 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);
423288ebb749SStefano Zampini 
42339de2952eSStefano Zampini   /* these two cases still need to be optimized */
42349de2952eSStefano Zampini   if (pcbddc->benign_saddle_point || !pcbddc->symmetric_primal) multi_element = PETSC_FALSE;
42359de2952eSStefano Zampini 
423606656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
42379de2952eSStefano Zampini   if (multi_element) {
42389de2952eSStefano Zampini     PetscCheck(!pcbddc->benign_n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
42399de2952eSStefano Zampini 
42409de2952eSStefano Zampini     PetscCall(MatCreate(PETSC_COMM_SELF, coarse_submat));
42419de2952eSStefano Zampini     PetscCall(MatSetSizes(*coarse_submat, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size));
42429de2952eSStefano Zampini     PetscCall(MatSetType(*coarse_submat, MATSEQAIJ));
42439de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
42449de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
42459de2952eSStefano Zampini 
42469de2952eSStefano Zampini     /* group vertices and constraints by subdomain id */
42479de2952eSStefano Zampini     const PetscInt *vidxs = pcbddc->primal_indices_local_idxs;
42489de2952eSStefano Zampini     const PetscInt *cidxs = pcbddc->primal_indices_local_idxs + n_vertices;
42499de2952eSStefano Zampini     PetscInt       *count_eff, *V_eff_to_V, *C_eff_to_C, *nnz;
42509de2952eSStefano Zampini     PetscInt        n_el = PetscMax(graph->n_local_subs, 1);
42519de2952eSStefano Zampini 
42529de2952eSStefano Zampini     PetscCall(PetscCalloc1(2 * n_el, &count_eff));
42539de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices, &V_to_eff_V));
42549de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &C_to_eff_C));
42559de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
42569de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
42579de2952eSStefano Zampini 
42589de2952eSStefano Zampini       V_to_eff_V[i] = count_eff[s];
42599de2952eSStefano Zampini       count_eff[s] += 1;
42609de2952eSStefano Zampini     }
42619de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
42629de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub + 1;
42639de2952eSStefano Zampini 
42649de2952eSStefano Zampini       C_to_eff_C[i] = count_eff[s];
42659de2952eSStefano Zampini       count_eff[s] += 1;
42669de2952eSStefano Zampini     }
42679de2952eSStefano Zampini 
42689de2952eSStefano Zampini     /* preallocation */
42699de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices + n_constraints, &nnz));
42709de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
42719de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
42729de2952eSStefano Zampini 
42739de2952eSStefano Zampini       nnz[i] = count_eff[s] + count_eff[s + 1];
42749de2952eSStefano Zampini     }
42759de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
42769de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub;
42779de2952eSStefano Zampini 
42789de2952eSStefano Zampini       nnz[i + n_vertices] = count_eff[s] + count_eff[s + 1];
42799de2952eSStefano Zampini     }
42809de2952eSStefano Zampini     PetscCall(MatSeqAIJSetPreallocation(*coarse_submat, 0, nnz));
42819de2952eSStefano Zampini     PetscCall(PetscFree(nnz));
42829de2952eSStefano Zampini 
42839de2952eSStefano Zampini     n_eff_vertices    = 0;
42849de2952eSStefano Zampini     n_eff_constraints = 0;
42859de2952eSStefano Zampini     for (PetscInt i = 0; i < n_el; i++) {
42869de2952eSStefano Zampini       n_eff_vertices       = PetscMax(n_eff_vertices, count_eff[2 * i]);
42879de2952eSStefano Zampini       n_eff_constraints    = PetscMax(n_eff_constraints, count_eff[2 * i + 1]);
42889de2952eSStefano Zampini       count_eff[2 * i]     = 0;
42899de2952eSStefano Zampini       count_eff[2 * i + 1] = 0;
42909de2952eSStefano Zampini     }
42919de2952eSStefano Zampini 
42929de2952eSStefano Zampini     const PetscInt *idx;
42939de2952eSStefano Zampini     PetscCall(PetscMalloc2(n_el * n_eff_vertices, &V_eff_to_V, n_el * n_eff_constraints, &C_eff_to_C));
42949de2952eSStefano Zampini 
42959de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
42969de2952eSStefano Zampini       const PetscInt e = graph->nodes[vidxs[i]].local_sub;
42979de2952eSStefano Zampini       const PetscInt s = 2 * e;
42989de2952eSStefano Zampini 
42999de2952eSStefano Zampini       V_eff_to_V[e * n_eff_vertices + count_eff[s]] = i;
43009de2952eSStefano Zampini       count_eff[s] += 1;
43019de2952eSStefano Zampini     }
43029de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
43039de2952eSStefano Zampini       const PetscInt e = graph->nodes[cidxs[i]].local_sub;
43049de2952eSStefano Zampini       const PetscInt s = 2 * e + 1;
43059de2952eSStefano Zampini 
43069de2952eSStefano Zampini       C_eff_to_C[e * n_eff_constraints + count_eff[s]] = i;
43079de2952eSStefano Zampini       count_eff[s] += 1;
43089de2952eSStefano Zampini     }
43099de2952eSStefano Zampini 
43109de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_vertices, &R_eff_V_J));
43119de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_constraints, &R_eff_C_J));
43129de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_vertices, &B_eff_V_J));
43139de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_constraints, &B_eff_C_J));
43149de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_vertices; i++) R_eff_V_J[i] = -1;
43159de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_constraints; i++) R_eff_C_J[i] = -1;
43169de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_vertices; i++) B_eff_V_J[i] = -1;
43179de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_constraints; i++) B_eff_C_J[i] = -1;
43189de2952eSStefano Zampini 
43199de2952eSStefano Zampini     PetscCall(ISGetIndices(pcbddc->is_R_local, &idx));
43209de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R; i++) {
43219de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
43229de2952eSStefano Zampini       const PetscInt s = 2 * e;
43239de2952eSStefano Zampini       PetscInt       j;
43249de2952eSStefano Zampini 
43259de2952eSStefano Zampini       for (j = 0; j < count_eff[s]; j++) R_eff_V_J[i * n_eff_vertices + j] = V_eff_to_V[e * n_eff_vertices + j];
43269de2952eSStefano Zampini       for (j = 0; j < count_eff[s + 1]; j++) R_eff_C_J[i * n_eff_constraints + j] = C_eff_to_C[e * n_eff_constraints + j];
43279de2952eSStefano Zampini     }
43289de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idx));
43299de2952eSStefano Zampini     PetscCall(ISGetIndices(pcis->is_B_local, &idx));
43309de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B; i++) {
43319de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
43329de2952eSStefano Zampini       const PetscInt s = 2 * e;
43339de2952eSStefano Zampini       PetscInt       j;
43349de2952eSStefano Zampini 
43359de2952eSStefano Zampini       for (j = 0; j < count_eff[s]; j++) B_eff_V_J[i * n_eff_vertices + j] = V_eff_to_V[e * n_eff_vertices + j];
43369de2952eSStefano Zampini       for (j = 0; j < count_eff[s + 1]; j++) B_eff_C_J[i * n_eff_constraints + j] = C_eff_to_C[e * n_eff_constraints + j];
43379de2952eSStefano Zampini     }
43389de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcis->is_B_local, &idx));
43399de2952eSStefano Zampini 
43409de2952eSStefano Zampini     /* permutation and blocksizes for block invert of S_CC */
43419de2952eSStefano Zampini     PetscInt *idxp;
43429de2952eSStefano Zampini 
43439de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &idxp));
43449de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_el, &C_bss));
43459de2952eSStefano Zampini     n_C_bss = 0;
43469de2952eSStefano Zampini     for (PetscInt e = 0, cnt = 0; e < n_el; e++) {
43479de2952eSStefano Zampini       const PetscInt nc = count_eff[2 * e + 1];
43489de2952eSStefano Zampini 
43499de2952eSStefano Zampini       if (nc) C_bss[n_C_bss++] = nc;
43509de2952eSStefano Zampini       for (PetscInt c = 0; c < nc; c++) { idxp[cnt + c] = C_eff_to_C[e * n_eff_constraints + c]; }
43519de2952eSStefano Zampini       cnt += nc;
43529de2952eSStefano Zampini     }
43539de2952eSStefano Zampini 
43549de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_constraints, idxp, PETSC_OWN_POINTER, &is_C_perm));
43559de2952eSStefano Zampini 
43569de2952eSStefano Zampini     PetscCall(PetscFree2(V_eff_to_V, C_eff_to_C));
43579de2952eSStefano Zampini     PetscCall(PetscFree(count_eff));
43589de2952eSStefano Zampini   } else {
43599de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, NULL, coarse_submat));
43609de2952eSStefano Zampini     n_eff_constraints = n_constraints;
43619de2952eSStefano Zampini     n_eff_vertices    = n_vertices;
43629de2952eSStefano Zampini   }
436306656605SStefano Zampini 
436406656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
43659566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
43669566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
43679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
43689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
4369ffd830a3SStefano Zampini   lda_rhs                = n_R;
4370a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
43717ebab0bbSStefano Zampini   if (isLU || isCHOL) {
43729566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
4373b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
4374df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4375d62866d3SStefano Zampini     MatFactorType      type;
4376d62866d3SStefano Zampini 
4377df4d28bfSStefano Zampini     F = reuse_solver->F;
43789566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
4379d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
43807ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
43819566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
438222db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
43837ebab0bbSStefano Zampini   } else F = NULL;
438406656605SStefano Zampini 
4385c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
4386c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
43879de2952eSStefano Zampini   if (F && !multi_element) {
4388ea799195SBarry Smith     MatSolverType solver;
4389c58f9fdbSStefano Zampini 
43909566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
43919566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
4392c58f9fdbSStefano Zampini   }
4393c58f9fdbSStefano Zampini 
43945cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
43955cbda25cSStefano Zampini   dummy_vec = NULL;
43965cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
43979566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
43989566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
43999566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
44005cbda25cSStefano Zampini   }
44015cbda25cSStefano Zampini 
44029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
44039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
44047ebab0bbSStefano Zampini 
44059de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &is_R));
44069de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_vertices, 0, 1, &is_V));
44079de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_C));
44089de2952eSStefano Zampini   PetscCall(ISGetIndices(is_V, &idx_V));
44099de2952eSStefano Zampini   PetscCall(ISGetIndices(is_C, &idx_C));
44109de2952eSStefano Zampini 
441188ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
441288ebb749SStefano Zampini   if (n_constraints) {
44139de2952eSStefano Zampini     Mat C_B;
441406656605SStefano Zampini 
441525084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
44169de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
44179de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
441888ebb749SStefano Zampini 
441980677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
442080677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
4421c58f9fdbSStefano Zampini     if (!sparserhs) {
44229de2952eSStefano Zampini       PetscScalar *marr;
44239de2952eSStefano Zampini 
44249de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &Brhs));
44259de2952eSStefano Zampini       PetscCall(MatDenseGetArrayWrite(Brhs, &marr));
442688ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
442706656605SStefano Zampini         const PetscScalar *row_cmat_values;
442806656605SStefano Zampini         const PetscInt    *row_cmat_indices;
44299de2952eSStefano Zampini         PetscInt           size_of_constraint, j, col = C_to_eff_C ? C_to_eff_C[i] : i;
443088ebb749SStefano Zampini 
44319566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
44329de2952eSStefano Zampini         for (j = 0; j < size_of_constraint; j++) marr[row_cmat_indices[j] + col * lda_rhs] = -row_cmat_values[j];
44339566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
443406656605SStefano Zampini       }
44359de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayWrite(Brhs, &marr));
4436c58f9fdbSStefano Zampini     } else {
4437c58f9fdbSStefano Zampini       Mat tC_CR;
4438c58f9fdbSStefano Zampini 
44399566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
4440c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
4441c58f9fdbSStefano Zampini         PetscScalar *aa;
4442c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
4443c58f9fdbSStefano Zampini         PetscBool    done;
4444c58f9fdbSStefano Zampini 
44459566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
444628b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
44479566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
44489566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
44499566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
445028b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4451c58f9fdbSStefano Zampini       } else {
44529566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
4453c58f9fdbSStefano Zampini         tC_CR = C_CR;
4454c58f9fdbSStefano Zampini       }
44559566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
44569566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
4457c58f9fdbSStefano Zampini     }
44589de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &local_auxmat2_R));
445906656605SStefano Zampini     if (F) {
4460a3df083aSStefano Zampini       if (need_benign_correction) {
4461df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4462a3df083aSStefano Zampini 
446372b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
44649566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
4465a3df083aSStefano Zampini       }
44669566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
4467a3df083aSStefano Zampini       if (need_benign_correction) {
4468a3df083aSStefano Zampini         PetscScalar       *marr;
4469df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4470a3df083aSStefano Zampini 
44719de2952eSStefano Zampini         /* XXX multi_element? */
44729566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
44735cbda25cSStefano Zampini         if (lda_rhs != n_R) {
44749de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
44759566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
44769566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
44779566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
44785cbda25cSStefano Zampini           }
44795cbda25cSStefano Zampini         } else {
44809de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
44819566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
44829566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
44839566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
4484a3df083aSStefano Zampini           }
44855cbda25cSStefano Zampini         }
44869566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
4487a3df083aSStefano Zampini       }
448806656605SStefano Zampini     } else {
44899de2952eSStefano Zampini       const PetscScalar *barr;
449080677318SStefano Zampini       PetscScalar       *marr;
449180677318SStefano Zampini 
44929de2952eSStefano Zampini       PetscCall(MatDenseGetArrayRead(Brhs, &barr));
44939566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
44949de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
44959de2952eSStefano Zampini         PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
44969566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
44979566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
44989566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
44999566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
45009566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
450106656605SStefano Zampini       }
45029de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
45039566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
450406656605SStefano Zampini     }
45051baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
45069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
45079de2952eSStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
450880677318SStefano Zampini     if (!pcbddc->switch_static) {
45099de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_constraints, NULL, &pcbddc->local_auxmat2));
45109de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
4511ab2d12f3SJunchao Zhang         Vec r, b;
45129566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
45139566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
45149566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
45159566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
45169566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
45179566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
451880677318SStefano Zampini       }
45199de2952eSStefano Zampini       if (multi_element) {
45209de2952eSStefano Zampini         Mat T;
4521ffd830a3SStefano Zampini 
45229de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
45239de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
45249de2952eSStefano Zampini         local_auxmat2_R = T;
45259de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(pcbddc->local_auxmat2, n_constraints, B_eff_C_J, &T));
45269de2952eSStefano Zampini         PetscCall(MatDestroy(&pcbddc->local_auxmat2));
45279de2952eSStefano Zampini         pcbddc->local_auxmat2 = T;
45289de2952eSStefano Zampini       }
4529fb842aefSJose E. Roman       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_CC));
45309de2952eSStefano Zampini     } else {
45319de2952eSStefano Zampini       if (multi_element) {
45329de2952eSStefano Zampini         Mat T;
45339de2952eSStefano Zampini 
45349de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
45359de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
45369de2952eSStefano Zampini         local_auxmat2_R = T;
45379de2952eSStefano Zampini       }
45389de2952eSStefano Zampini       if (lda_rhs != n_R) {
45399de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(local_auxmat2_R, is_R, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
4540ffd830a3SStefano Zampini       } else {
45419566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
454280677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
4543ffd830a3SStefano Zampini       }
4544fb842aefSJose E. Roman       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_CC));
454580677318SStefano Zampini     }
45469de2952eSStefano Zampini     PetscCall(MatScale(S_CC, m_one));
45479de2952eSStefano Zampini     if (multi_element) {
45489de2952eSStefano Zampini       Mat T, T2;
45499de2952eSStefano Zampini       IS  isp, ispi;
45509de2952eSStefano Zampini 
45519de2952eSStefano Zampini       isp = is_C_perm;
45529de2952eSStefano Zampini 
45539de2952eSStefano Zampini       PetscCall(ISInvertPermutation(isp, PETSC_DECIDE, &ispi));
45549de2952eSStefano Zampini       PetscCall(MatPermute(S_CC, isp, isp, &T));
45559de2952eSStefano Zampini       PetscCall(MatSeqAIJInvertVariableBlockDiagonalMat(T, n_C_bss, C_bss, &T2));
45569de2952eSStefano Zampini       PetscCall(MatDestroy(&T));
45579de2952eSStefano Zampini       PetscCall(MatDestroy(&S_CC));
45589de2952eSStefano Zampini       PetscCall(MatPermute(T2, ispi, ispi, &S_CC));
45599de2952eSStefano Zampini       PetscCall(MatDestroy(&T2));
45609de2952eSStefano Zampini       PetscCall(ISDestroy(&ispi));
456180677318SStefano Zampini     } else {
45629de2952eSStefano Zampini       if (isCHOL) {
45639de2952eSStefano Zampini         PetscCall(MatCholeskyFactor(S_CC, NULL, NULL));
45649de2952eSStefano Zampini       } else {
45659de2952eSStefano Zampini         PetscCall(MatLUFactor(S_CC, NULL, NULL, NULL));
456680677318SStefano Zampini       }
45679de2952eSStefano Zampini       PetscCall(MatSeqDenseInvertFactors_Private(S_CC));
45689de2952eSStefano Zampini     }
456980677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
4570fb842aefSJose E. Roman     PetscCall(MatMatMult(S_CC, C_B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &pcbddc->local_auxmat1));
45719566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
45729de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, S_CC, n_constraints, idx_C, n_constraints, idx_C, INSERT_VALUES));
4573f4ddd8eeSStefano Zampini   }
4574fc227af8SStefano Zampini 
4575fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
457688ebb749SStefano Zampini   if (n_vertices) {
45777ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
45787ebab0bbSStefano Zampini     PetscBool oldpin;
45797ebab0bbSStefano Zampini #endif
458006656605SStefano Zampini     IS is_aux;
45813a50541eSStefano Zampini 
4582b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
45836816873aSStefano Zampini       IS tis;
45846816873aSStefano Zampini 
45859566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
45869566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
45879566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
45889566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
45896816873aSStefano Zampini     } else {
45909566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
45916816873aSStefano Zampini     }
45927ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4593b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
45947ebab0bbSStefano Zampini #endif
45959566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
45969566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
45979566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
45989de2952eSStefano Zampini     /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
45999566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
46009566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
46017ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
46029566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
46037ebab0bbSStefano Zampini #endif
46049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
460588ebb749SStefano Zampini   }
46069de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C_perm));
46079de2952eSStefano Zampini   PetscCall(PetscFree(C_bss));
460888ebb749SStefano Zampini 
46094f1b2e48SStefano Zampini   p0_lidx_I = NULL;
46104f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4611d12edf2fSStefano Zampini     const PetscInt *idxs;
4612d12edf2fSStefano Zampini 
46139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
46149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
461548a46eb9SPierre 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]));
46169566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4617d12edf2fSStefano Zampini   }
4618d16cbb6bSStefano Zampini 
46199de2952eSStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
46209de2952eSStefano Zampini 
46219de2952eSStefano Zampini   /* Matrices of coarse basis functions (local) */
46229de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
46239de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
46249de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
46259de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
46269de2952eSStefano Zampini   if (!multi_element) {
46279de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_B));
46289de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_D));
46299de2952eSStefano Zampini     coarse_phi_multi = NULL;
46309de2952eSStefano Zampini   } else { /* Create temporary NEST matrix to hold coarse basis functions blocks */
46319de2952eSStefano Zampini     IS is_rows[2] = {pcbddc->is_R_local, NULL};
46329de2952eSStefano Zampini     IS is_cols[2] = {is_V, is_C};
46339de2952eSStefano Zampini 
46349de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_vertices, pcbddc->local_primal_ref_node, PETSC_USE_POINTER, &is_rows[1]));
46359de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, 2, is_rows, 2, is_cols, NULL, &coarse_phi_multi));
46369de2952eSStefano Zampini     PetscCall(ISDestroy(&is_rows[1]));
46379de2952eSStefano Zampini   }
46389de2952eSStefano Zampini 
463906656605SStefano Zampini   /* vertices */
464006656605SStefano Zampini   if (n_vertices) {
4641c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
46429de2952eSStefano Zampini     Mat       A_RRmA_RV  = NULL;
464316f15bc4SStefano Zampini 
46449de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, A_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
46459de2952eSStefano Zampini     PetscCall(MatDestroy(&A_VV));
464604708bb6SStefano Zampini 
464716f15bc4SStefano Zampini     if (n_R) {
46489de2952eSStefano Zampini       Mat A_RV_bcorr = NULL, S_VV;
464906656605SStefano Zampini 
46509566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
465114393ed6SStefano Zampini       if (need_benign_correction) {
465214393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
465314393ed6SStefano Zampini         IS                     is_p0;
465414393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
465514393ed6SStefano Zampini 
46569566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
46579566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
46589566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
465963a3b9bcSJacob 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);
46609566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
46619566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
46629566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
46639566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
466414393ed6SStefano Zampini       }
466514393ed6SStefano Zampini 
46669de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &A_RRmA_RV));
4667c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
46689de2952eSStefano Zampini         if (lda_rhs == n_R && !multi_element) {
46699566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4670ffd830a3SStefano Zampini         } else {
46719de2952eSStefano Zampini           Mat             T;
4672ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4673ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4674ca92afb2SStefano Zampini           PetscInt        n;
4675ca92afb2SStefano Zampini           PetscBool       flg_row;
4676ffd830a3SStefano Zampini 
46779de2952eSStefano Zampini           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &T));
46789de2952eSStefano Zampini           PetscCall(MatDenseGetArrayWrite(T, &array));
46799566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
46809566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
46819566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4682ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4683ca92afb2SStefano Zampini             PetscInt j;
46849de2952eSStefano Zampini             for (j = xadj[i]; j < xadj[i + 1]; j++) array[lda_rhs * (V_to_eff_V ? V_to_eff_V[adjncy[j]] : adjncy[j]) + i] = av[j];
4685ffd830a3SStefano Zampini           }
46869566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
46879de2952eSStefano Zampini           PetscCall(MatDenseRestoreArrayWrite(T, &array));
46889566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
46899de2952eSStefano Zampini           A_RV = T;
4690ffd830a3SStefano Zampini         }
4691a3df083aSStefano Zampini         if (need_benign_correction) {
4692df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4693a3df083aSStefano Zampini           PetscScalar       *marr;
4694a3df083aSStefano Zampini 
46959de2952eSStefano Zampini           /* XXX multi_element */
46969566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
469714393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
469814393ed6SStefano Zampini 
469914393ed6SStefano Zampini                  | 0 0  0 | (V)
470014393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
470114393ed6SStefano Zampini                  | 0 0 -1 | (p0)
470214393ed6SStefano Zampini 
470314393ed6SStefano Zampini           */
4704df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
470514393ed6SStefano Zampini             const PetscScalar *vals;
470614393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
470714393ed6SStefano Zampini             PetscInt           n, j, nz;
470814393ed6SStefano Zampini 
47099566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
47109566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
47119566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
471214393ed6SStefano Zampini             for (j = 0; j < n; j++) {
471314393ed6SStefano Zampini               PetscScalar val = vals[j];
471414393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
471514393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
471614393ed6SStefano Zampini             }
47179566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
47189566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
471914393ed6SStefano Zampini           }
47209566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
472172b8c272SStefano Zampini         }
47229566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4723c58f9fdbSStefano Zampini         Brhs = A_RV;
4724c58f9fdbSStefano Zampini       } else {
4725c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4726c58f9fdbSStefano Zampini 
4727c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4728fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
47299566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4730c58f9fdbSStefano Zampini         } else {
4731c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
47329566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
47339566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4734c58f9fdbSStefano Zampini           A_RVT = A_VR;
4735c58f9fdbSStefano Zampini         }
4736c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4737c58f9fdbSStefano Zampini           PetscScalar *aa;
4738c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4739c58f9fdbSStefano Zampini           PetscBool    done;
4740c58f9fdbSStefano Zampini 
47419566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
474228b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
47439566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
47449566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
47459566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
474628b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4747c58f9fdbSStefano Zampini         } else {
47489566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4749c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4750c58f9fdbSStefano Zampini         }
47519566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
47529566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
47539566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4754c58f9fdbSStefano Zampini       }
475572b8c272SStefano Zampini       if (F) {
475614393ed6SStefano Zampini         /* need to correct the rhs */
475772b8c272SStefano Zampini         if (need_benign_correction) {
475872b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
475972b8c272SStefano Zampini           PetscScalar       *marr;
476072b8c272SStefano Zampini 
47619566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
47625cbda25cSStefano Zampini           if (lda_rhs != n_R) {
47639de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47649566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
47659566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
47669566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
47675cbda25cSStefano Zampini             }
47685cbda25cSStefano Zampini           } else {
47699de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47709566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
47719566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
47729566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4773a3df083aSStefano Zampini             }
47745cbda25cSStefano Zampini           }
47759566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4776a3df083aSStefano Zampini         }
47779566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
47781baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
477914393ed6SStefano Zampini         /* need to correct the solution */
4780a3df083aSStefano Zampini         if (need_benign_correction) {
4781df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4782a3df083aSStefano Zampini           PetscScalar       *marr;
4783a3df083aSStefano Zampini 
47849566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
47855cbda25cSStefano Zampini           if (lda_rhs != n_R) {
47869de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47879566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
47889566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
47899566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
47905cbda25cSStefano Zampini             }
47915cbda25cSStefano Zampini           } else {
47929de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47939566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
47949566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
47959566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4796a3df083aSStefano Zampini             }
47975cbda25cSStefano Zampini           }
47989566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4799a3df083aSStefano Zampini         }
480006656605SStefano Zampini       } else {
48019de2952eSStefano Zampini         const PetscScalar *barr;
48029de2952eSStefano Zampini         PetscScalar       *marr;
48039de2952eSStefano Zampini 
48049de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(Brhs, &barr));
48059de2952eSStefano Zampini         PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
48069de2952eSStefano Zampini         for (i = 0; i < n_eff_vertices; i++) {
48079de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
48089de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
48099566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
48109566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
48119566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
48129566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
481306656605SStefano Zampini         }
48149de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
48159de2952eSStefano Zampini         PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
481606656605SStefano Zampini       }
48179566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
48189566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4819ffd830a3SStefano Zampini       /* S_VV and S_CV */
482006656605SStefano Zampini       if (n_constraints) {
482106656605SStefano Zampini         Mat B;
482280677318SStefano Zampini 
48239de2952eSStefano Zampini         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_vertices, NULL, &B));
48249de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, B));
48259de2952eSStefano Zampini 
48269de2952eSStefano Zampini         /* S_CV = pcbddc->local_auxmat1 * B */
48279de2952eSStefano Zampini         if (multi_element) {
48289de2952eSStefano Zampini           Mat T;
48299de2952eSStefano Zampini 
48309de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(B, n_vertices, B_eff_V_J, &T));
48319de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
48329de2952eSStefano Zampini           B = T;
483380677318SStefano Zampini         }
48349de2952eSStefano Zampini         PetscCall(MatProductCreate(pcbddc->local_auxmat1, B, NULL, &S_CV));
48359566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
48369566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
48379566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
48389566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
48399566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
48409566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
48419de2952eSStefano Zampini 
48429de2952eSStefano Zampini         /* B = local_auxmat2_R * S_CV */
48439de2952eSStefano Zampini         PetscCall(MatProductCreate(local_auxmat2_R, S_CV, NULL, &B));
48449566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
48459566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
48469566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
48479566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
48484222ddf1SHong Zhang 
48499566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
48509de2952eSStefano Zampini         PetscCall(MatSetValuesSubMat(*coarse_submat, S_CV, n_constraints, idx_C, n_vertices, idx_V, INSERT_VALUES));
485114393ed6SStefano Zampini 
48529de2952eSStefano Zampini         if (multi_element) {
48539de2952eSStefano Zampini           Mat T;
48549de2952eSStefano Zampini 
48559de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
48569de2952eSStefano Zampini           PetscCall(MatDestroy(&A_RRmA_RV));
48579de2952eSStefano Zampini           A_RRmA_RV = T;
48589de2952eSStefano Zampini         }
48599de2952eSStefano Zampini         PetscCall(MatAXPY(A_RRmA_RV, 1.0, B, UNKNOWN_NONZERO_PATTERN)); /* XXX ? */
48609de2952eSStefano Zampini         PetscCall(MatDestroy(&B));
48619de2952eSStefano Zampini       } else if (multi_element) {
48629de2952eSStefano Zampini         Mat T;
48639de2952eSStefano Zampini 
48649de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
48659de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
48669de2952eSStefano Zampini         A_RRmA_RV = T;
48679de2952eSStefano Zampini       }
48689de2952eSStefano Zampini 
48699de2952eSStefano Zampini       if (lda_rhs != n_R) {
48709de2952eSStefano Zampini         Mat T;
48719de2952eSStefano Zampini 
48729de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(A_RRmA_RV, is_R, NULL, MAT_INITIAL_MATRIX, &T));
48739de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
48749de2952eSStefano Zampini         A_RRmA_RV = T;
48759de2952eSStefano Zampini       }
48769de2952eSStefano Zampini 
48779de2952eSStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
48789de2952eSStefano Zampini       if (need_benign_correction) { /* XXX SPARSE */
48799de2952eSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
48809de2952eSStefano Zampini         PetscScalar       *sums;
48819de2952eSStefano Zampini         const PetscScalar *marr;
48829de2952eSStefano Zampini 
48839de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(A_RRmA_RV, &marr));
48849566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
4885df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
488614393ed6SStefano Zampini           const PetscScalar *vals;
488714393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
488814393ed6SStefano Zampini           PetscInt           n, j, nz;
488914393ed6SStefano Zampini 
48909566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
48919566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
489214393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
489314393ed6SStefano Zampini             sums[j] = 0.;
48949de2952eSStefano Zampini             for (PetscInt k = 0; k < nz; k++) sums[j] += marr[idxs_zero[k] + j * n_R];
489514393ed6SStefano Zampini           }
48969566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
489714393ed6SStefano Zampini           for (j = 0; j < n; j++) {
489814393ed6SStefano Zampini             PetscScalar val = vals[j];
48999de2952eSStefano Zampini             for (PetscInt k = 0; k < n_vertices; k++) PetscCall(MatSetValue(*coarse_submat, idx_V[idxs[j]], idx_V[k], val * sums[k], ADD_VALUES));
490014393ed6SStefano Zampini           }
49019566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
49029566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
490314393ed6SStefano Zampini         }
49049566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
49059566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
49069de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(A_RRmA_RV, &marr));
490714393ed6SStefano Zampini       }
49089de2952eSStefano Zampini 
4909fb842aefSJose E. Roman       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_VV));
49109de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
49119de2952eSStefano Zampini       PetscCall(MatDestroy(&S_VV));
4912d16cbb6bSStefano Zampini     }
4913d16cbb6bSStefano Zampini 
491406656605SStefano Zampini     /* coarse basis functions */
49159de2952eSStefano Zampini     if (coarse_phi_multi) {
49169de2952eSStefano Zampini       Mat Vid;
491716f15bc4SStefano Zampini 
49189de2952eSStefano Zampini       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, n_vertices, n_vertices, 1, NULL, &Vid));
49199de2952eSStefano Zampini       PetscCall(MatShift_Basic(Vid, 1.0));
49209de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 0, A_RRmA_RV));
49219de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 1, 0, Vid));
49229de2952eSStefano Zampini       PetscCall(MatDestroy(&Vid));
49239de2952eSStefano Zampini     } else {
49249de2952eSStefano Zampini       if (A_RRmA_RV) {
49259de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, pcbddc->coarse_phi_B));
492606656605SStefano Zampini         if (pcbddc->switch_static || pcbddc->dbg_flag) {
49279de2952eSStefano Zampini           PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_D, pcbddc->coarse_phi_D));
49289de2952eSStefano Zampini           if (pcbddc->benign_n) {
49299de2952eSStefano Zampini             for (i = 0; i < n_vertices; i++) { PetscCall(MatSetValues(pcbddc->coarse_phi_D, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES)); }
4930*8a162dc6SStefano Zampini             PetscCall(MatAssemblyBegin(pcbddc->coarse_phi_D, MAT_FINAL_ASSEMBLY));
4931*8a162dc6SStefano Zampini             PetscCall(MatAssemblyEnd(pcbddc->coarse_phi_D, MAT_FINAL_ASSEMBLY));
4932ab2d12f3SJunchao Zhang           }
493306656605SStefano Zampini         }
493406656605SStefano Zampini       }
49359de2952eSStefano Zampini       for (i = 0; i < n_vertices; i++) PetscCall(MatSetValues(pcbddc->coarse_phi_B, 1, &idx_V_B[i], 1, &i, &one, INSERT_VALUES));
49369de2952eSStefano Zampini       PetscCall(MatAssemblyBegin(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
49379de2952eSStefano Zampini       PetscCall(MatAssemblyEnd(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
49389de2952eSStefano Zampini     }
49399de2952eSStefano Zampini     PetscCall(MatDestroy(&A_RRmA_RV));
49409de2952eSStefano Zampini   }
49419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RV));
49429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
494306656605SStefano Zampini 
494406656605SStefano Zampini   if (n_constraints) {
49459de2952eSStefano Zampini     Mat B, B2;
494606656605SStefano Zampini 
49479566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
49489de2952eSStefano Zampini     PetscCall(MatProductCreate(local_auxmat2_R, S_CC, NULL, &B));
49499566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
49509566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
49519566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
49529566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
4953a961b312SStefano Zampini 
495406656605SStefano Zampini     if (n_vertices) {
495503dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
49569de2952eSStefano Zampini         PetscCall(MatTranspose(S_CV, MAT_INITIAL_MATRIX, &S_VC));
495780677318SStefano Zampini       } else {
4958ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
49599de2952eSStefano Zampini           Mat tB;
496006656605SStefano Zampini 
49619de2952eSStefano Zampini           PetscCall(MatCreateSubMatrix(B, is_R, NULL, MAT_INITIAL_MATRIX, &tB));
49629de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
49639de2952eSStefano Zampini           B = tB;
49649de2952eSStefano Zampini         }
4965fb842aefSJose E. Roman         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_VC));
49669de2952eSStefano Zampini       }
49679de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VC, n_vertices, idx_V, n_constraints, idx_C, INSERT_VALUES));
49689de2952eSStefano Zampini     }
49699de2952eSStefano Zampini 
49709de2952eSStefano Zampini     /* coarse basis functions */
49719de2952eSStefano Zampini     if (coarse_phi_multi) {
49729de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 1, B));
49739de2952eSStefano Zampini     } else {
49749de2952eSStefano Zampini       PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_B, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
49759de2952eSStefano Zampini       PetscCall(MatDenseScatter(B, pcbddc->R_to_B, B2));
49769de2952eSStefano Zampini       PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_B, &B2));
497706656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
49789de2952eSStefano Zampini         PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_D, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
49799de2952eSStefano Zampini         PetscCall(MatDenseScatter(B, pcbddc->R_to_D, B2));
49809de2952eSStefano Zampini         if (pcbddc->benign_n) {
49819de2952eSStefano Zampini           for (i = 0; i < n_constraints; i++) { PetscCall(MatSetValues(B2, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES)); }
498206656605SStefano Zampini         }
49839de2952eSStefano Zampini         PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_D, &B2));
498406656605SStefano Zampini       }
498506656605SStefano Zampini     }
49869de2952eSStefano Zampini     PetscCall(MatDestroy(&B));
49879de2952eSStefano Zampini   }
49889de2952eSStefano Zampini 
49899de2952eSStefano Zampini   /* assemble sparse coarse basis functions */
49909de2952eSStefano Zampini   if (coarse_phi_multi) {
49919de2952eSStefano Zampini     Mat T;
49929de2952eSStefano Zampini 
49939de2952eSStefano Zampini     PetscCall(MatConvert(coarse_phi_multi, MATSEQAIJ, MAT_INITIAL_MATRIX, &T));
49949de2952eSStefano Zampini     PetscCall(MatDestroy(&coarse_phi_multi));
49959de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(T, pcis->is_B_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_B));
49969de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) { PetscCall(MatCreateSubMatrix(T, pcis->is_I_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_D)); }
49979de2952eSStefano Zampini     PetscCall(MatDestroy(&T));
49989de2952eSStefano Zampini   }
49999de2952eSStefano Zampini   PetscCall(MatDestroy(&local_auxmat2_R));
50009566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
500172b8c272SStefano Zampini 
500272b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
500372b8c272SStefano Zampini   if (pcbddc->benign_n) {
500472b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
500572b8c272SStefano Zampini     IS                 is_dummy;
50061683a169SBarry Smith     const PetscScalar *data;
500772b8c272SStefano Zampini     PetscInt           j;
500872b8c272SStefano Zampini 
50099566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
50109566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
50119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
50129566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
50139566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
50149566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
501572b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
501672b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
501772b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
50189de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, primal_idx, i, data[i * pcbddc->benign_n + j], INSERT_VALUES));
50199de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, i, primal_idx, data[i * pcbddc->benign_n + j], INSERT_VALUES));
502072b8c272SStefano Zampini       }
502172b8c272SStefano Zampini     }
50229566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
50239566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
50249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
502572b8c272SStefano Zampini   }
5026019a44ceSStefano Zampini 
502706656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
50283301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
5029ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
50309de2952eSStefano Zampini     PetscScalar *marray, *work;
503106656605SStefano Zampini 
50329de2952eSStefano Zampini     /* TODO multi_element MatDenseScatter */
503306656605SStefano Zampini     if (n_constraints) {
5034ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
503506656605SStefano Zampini 
50369de2952eSStefano Zampini       PetscCall(MatScale(S_CC, m_one));
50379566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
50389566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
5039fb842aefSJose E. Roman       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &B_C));
50409de2952eSStefano Zampini       PetscCall(MatConvert(B_C, MATDENSE, MAT_INPLACE_MATRIX, &B_C));
50419566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
504206656605SStefano Zampini       if (n_vertices) {
5043ffd830a3SStefano Zampini         Mat S_VCT;
504406656605SStefano Zampini 
50459566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
5046fb842aefSJose E. Roman         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &B_V));
50479566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
50489de2952eSStefano Zampini         PetscCall(MatConvert(B_V, MATDENSE, MAT_INPLACE_MATRIX, &B_V));
504906656605SStefano Zampini       }
50509566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
50515b782168SStefano Zampini     } else {
50529566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
505306656605SStefano Zampini     }
505416f15bc4SStefano Zampini     if (n_vertices && n_R) {
5055ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
5056ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
5057ffd830a3SStefano Zampini       PetscInt        n;
5058ffd830a3SStefano Zampini       PetscBool       flg_row;
505906656605SStefano Zampini 
5060ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
50619566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
50629566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
50639566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
50649566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
5065ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
5066ffd830a3SStefano Zampini         PetscInt j;
5067ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
5068ffd830a3SStefano Zampini       }
50699566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
50709566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
50719566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
507206656605SStefano Zampini     }
507306656605SStefano Zampini 
5074ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
50759de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * pcbddc->local_primal_size, &work));
5076abc8f43dSstefano_zampini     if (n_vertices) {
50779566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
5078ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
50799566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
50809566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
50819566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
50829566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
50839566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
50849566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
508506656605SStefano Zampini       }
50869566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
5087abc8f43dSstefano_zampini     }
50885b782168SStefano Zampini     if (B_C) {
50899566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
5090ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
50919566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
50929566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
50939566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
50949566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
50959566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
50969566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
509706656605SStefano Zampini       }
50989566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
50995b782168SStefano Zampini     }
510006656605SStefano Zampini     /* coarse basis functions */
51019de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_B));
51029de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_D));
510306656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
5104ab2d12f3SJunchao Zhang       Vec v;
510506656605SStefano Zampini 
51069566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
51079566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
51089566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
51099566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
511006656605SStefano Zampini       if (i < n_vertices) {
5111ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
51129566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
51139566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
51149566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
511506656605SStefano Zampini       }
51169566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
511706656605SStefano Zampini 
511806656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
51199566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
51209566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
51219566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
51229566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
512306656605SStefano Zampini       }
51249566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
512506656605SStefano Zampini     }
51269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
51279566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
51289de2952eSStefano Zampini     PetscCall(PetscFree(work));
51299de2952eSStefano Zampini   } else {
51309de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
51319de2952eSStefano Zampini     pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
51329de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
51339de2952eSStefano Zampini     pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
513406656605SStefano Zampini   }
51359de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(*coarse_submat, MAT_FINAL_ASSEMBLY));
51369de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(*coarse_submat, MAT_FINAL_ASSEMBLY));
5137a6e023c1Sstefano_zampini 
5138d62866d3SStefano Zampini   /* free memory */
51399de2952eSStefano Zampini   PetscCall(PetscFree(V_to_eff_V));
51409de2952eSStefano Zampini   PetscCall(PetscFree(C_to_eff_C));
51419de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_V_J));
51429de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_C_J));
51439de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_V_J));
51449de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_C_J));
51459de2952eSStefano Zampini   PetscCall(ISDestroy(&is_R));
51469de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_V, &idx_V));
51479de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_C, &idx_C));
51489de2952eSStefano Zampini   PetscCall(ISDestroy(&is_V));
51499de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C));
51509566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
51519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
51529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
51539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
515448a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
515548a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
51569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
51578ead10e4SStefano Zampini 
5158da81f932SPierre Jolivet   /* Checking coarse_sub_mat and coarse basis functions */
515988ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
516088ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
5161d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
516225084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
516388ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
516488ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
516588ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
51668bec7fa6SStefano Zampini     Mat       C_B, CPHI;
51678bec7fa6SStefano Zampini     IS        is_dummy;
51688bec7fa6SStefano Zampini     Vec       mones;
516988ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
517088ebb749SStefano Zampini     PetscReal real_value;
517188ebb749SStefano Zampini 
5172a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
5173a3df083aSStefano Zampini       Mat A;
51749566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
51759566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
51769566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
51779566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
51789566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
51799566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
5180a3df083aSStefano Zampini     } else {
51819566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
51829566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
51839566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
51849566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
5185a3df083aSStefano Zampini     }
51869566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
51879566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
5188ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
51899566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
51909566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
519188ebb749SStefano Zampini     }
51929566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
51939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
51949566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5195ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
51969566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51979566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
51989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
51999566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
52009566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
52019566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
52029566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
52039566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
52049566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
52059566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
52069566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
52079566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
520888ebb749SStefano Zampini     } else {
52099566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
52109566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
52119566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
52129566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
52139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
52149566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
52159566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
52169566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
521788ebb749SStefano Zampini     }
52189566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
52199566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
52209566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
52219566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
52224f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5223fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
52241683a169SBarry Smith       const PetscScalar *data2;
52251683a169SBarry Smith       PetscScalar       *data;
52264f1b2e48SStefano Zampini       PetscInt           j;
5227d12edf2fSStefano Zampini 
52289566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
52299566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
52309566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
52319566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
52329566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
52339566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
52344f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
52354f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
5236d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
52374f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
52384f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
52394f1b2e48SStefano Zampini         }
5240d12edf2fSStefano Zampini       }
52419566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
52429566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
52439566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
52449566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
52459566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
5246d12edf2fSStefano Zampini     }
52479de2952eSStefano Zampini     PetscCall(MatAXPY(TM1, m_one, *coarse_submat, DIFFERENT_NONZERO_PATTERN));
52489566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
52499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
525063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
52518bec7fa6SStefano Zampini 
52528bec7fa6SStefano Zampini     /* check constraints */
52539566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
52549566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
52554f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
52569566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
5257a00504b5SStefano Zampini     } else {
5258a00504b5SStefano Zampini       PetscScalar *data;
5259a00504b5SStefano Zampini       Mat          tmat;
52609566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
52619566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
52629566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
52639566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
52649566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
5265a00504b5SStefano Zampini     }
52669566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
52679566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
52689566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
52699566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
527063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
5271ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
52729566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
52739566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
52749566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
52759566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
527663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
527788ebb749SStefano Zampini     }
52789566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
52799566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
52809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
52819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
52829566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
52839566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
52849566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
52859566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
52869566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
52879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
52889566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
52899566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
52909566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
52919566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
52929566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
5293ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
52949566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
52959566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
529688ebb749SStefano Zampini     }
529788ebb749SStefano Zampini   }
52987ebab0bbSStefano Zampini 
52999de2952eSStefano Zampini #if 0
53009de2952eSStefano Zampini   {
53019de2952eSStefano Zampini     PetscViewer viewer;
53029de2952eSStefano Zampini     char filename[256];
53039de2952eSStefano Zampini 
53049de2952eSStefano Zampini     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level));
53059de2952eSStefano Zampini     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
53069de2952eSStefano Zampini     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
53079de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)*coarse_submat,"coarse submat"));
53089de2952eSStefano Zampini     PetscCall(MatView(*coarse_submat,viewer));
53099de2952eSStefano Zampini     if (pcbddc->coarse_phi_B) {
53109de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
53119de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
53129de2952eSStefano Zampini     }
53139de2952eSStefano Zampini     if (pcbddc->coarse_phi_D) {
53149de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
53159de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
53169de2952eSStefano Zampini     }
53179de2952eSStefano Zampini     if (pcbddc->coarse_psi_B) {
53189de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
53199de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
53209de2952eSStefano Zampini     }
53219de2952eSStefano Zampini     if (pcbddc->coarse_psi_D) {
53229de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
53239de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
53249de2952eSStefano Zampini     }
53259de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
53269de2952eSStefano Zampini     PetscCall(MatView(pcbddc->local_mat,viewer));
53279de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
53289de2952eSStefano Zampini     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
53299de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
53309de2952eSStefano Zampini     PetscCall(ISView(pcis->is_I_local,viewer));
53319de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
53329de2952eSStefano Zampini     PetscCall(ISView(pcis->is_B_local,viewer));
53339de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
53349de2952eSStefano Zampini     PetscCall(ISView(pcbddc->is_R_local,viewer));
5335648c30bcSBarry Smith     PetscCall(PetscViewerDestroy(&viewer));
53369de2952eSStefano Zampini   }
53379de2952eSStefano Zampini #endif
53389de2952eSStefano Zampini 
53399de2952eSStefano Zampini   /* device support */
53409de2952eSStefano Zampini   {
53419de2952eSStefano Zampini     PetscBool iscuda, iship, iskokkos;
53429de2952eSStefano Zampini     MatType   mtype = NULL;
53439de2952eSStefano Zampini 
53449de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iscuda, VECCUDA, VECMPICUDA, VECSEQCUDA, ""));
53459de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iship, VECHIP, VECMPIHIP, VECSEQHIP, ""));
53469de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iskokkos, VECKOKKOS, VECMPIKOKKOS, VECSEQKOKKOS, ""));
53479de2952eSStefano Zampini     if (iskokkos) {
53489de2952eSStefano Zampini       if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_CUDA)) iscuda = PETSC_TRUE;
53499de2952eSStefano Zampini       else if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_HIP)) iship = PETSC_TRUE;
53509de2952eSStefano Zampini     }
53519de2952eSStefano Zampini     if (iskokkos) mtype = multi_element ? MATSEQAIJKOKKOS : (iscuda ? MATSEQDENSECUDA : MATSEQDENSEHIP);
53529de2952eSStefano Zampini     else if (iship) mtype = multi_element ? MATSEQAIJHIPSPARSE : MATSEQDENSEHIP;
53539de2952eSStefano Zampini     else if (iscuda) mtype = multi_element ? MATSEQAIJCUSPARSE : MATSEQDENSECUDA;
53549de2952eSStefano Zampini     if (mtype) {
53559de2952eSStefano Zampini       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
53569de2952eSStefano Zampini       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
53579de2952eSStefano Zampini       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
53589de2952eSStefano Zampini       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
53599de2952eSStefano Zampini       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
53609de2952eSStefano Zampini       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
53617ebab0bbSStefano Zampini     }
53627ebab0bbSStefano Zampini   }
53633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
536488ebb749SStefano Zampini }
536588ebb749SStefano Zampini 
5366d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B)
5367d71ae5a4SJacob Faibussowitsch {
5368d65f70fdSStefano Zampini   Mat      *work_mat;
5369d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
5370d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
5371c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
5372aa0d41d4SStefano Zampini 
5373aa0d41d4SStefano Zampini   PetscFunctionBegin;
53749566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
53759566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
53769566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
53779566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
5378aa0d41d4SStefano Zampini 
5379d65f70fdSStefano Zampini   if (!rsorted) {
5380906d46d4SStefano Zampini     const PetscInt *idxs;
5381906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
5382aa0d41d4SStefano Zampini 
53839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
53849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
5385ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_perm_r[i] = i;
53869566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
53879566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
5388ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_sorted[i] = idxs[idxs_perm_r[i]];
53899566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
53909566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
5391d65f70fdSStefano Zampini   } else {
53929566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
5393d65f70fdSStefano Zampini     isrow_s = isrow;
5394aa0d41d4SStefano Zampini   }
5395906d46d4SStefano Zampini 
5396d65f70fdSStefano Zampini   if (!csorted) {
5397d65f70fdSStefano Zampini     if (isrow == iscol) {
53989566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
5399d65f70fdSStefano Zampini       iscol_s = isrow_s;
5400d65f70fdSStefano Zampini     } else {
5401d65f70fdSStefano Zampini       const PetscInt *idxs;
5402d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
5403906d46d4SStefano Zampini 
54049566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
54059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
5406ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_perm_c[i] = i;
54079566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
54089566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
5409ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_sorted[i] = idxs[idxs_perm_c[i]];
54109566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
54119566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
5412d65f70fdSStefano Zampini     }
5413d65f70fdSStefano Zampini   } else {
54149566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
5415d65f70fdSStefano Zampini     iscol_s = iscol;
5416d65f70fdSStefano Zampini   }
5417d65f70fdSStefano Zampini 
54189566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
5419d65f70fdSStefano Zampini 
5420d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
5421906d46d4SStefano Zampini     Mat new_mat;
5422d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
5423906d46d4SStefano Zampini 
5424d65f70fdSStefano Zampini     if (!rsorted) {
5425d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
54269566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
5427ad540459SPierre Jolivet       for (i = 0; i < rsize; i++) idxs_r[idxs_perm_r[i]] = i;
54289566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
54299566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
5430d65f70fdSStefano Zampini     } else {
54319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
5432906d46d4SStefano Zampini     }
54339566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
5434d65f70fdSStefano Zampini 
5435d65f70fdSStefano Zampini     if (!csorted) {
5436d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
54379566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
5438d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
5439d65f70fdSStefano Zampini       } else {
5440d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
544128b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
54429566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
5443ad540459SPierre Jolivet         for (i = 0; i < csize; i++) idxs_c[idxs_perm_c[i]] = i;
54449566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
54459566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
5446d65f70fdSStefano Zampini       }
5447d65f70fdSStefano Zampini     } else {
54489566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
5449d65f70fdSStefano Zampini     }
54509566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
5451d65f70fdSStefano Zampini 
54529566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
54539566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
5454d65f70fdSStefano Zampini     work_mat[0] = new_mat;
54559566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
54569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
5457d65f70fdSStefano Zampini   }
5458d65f70fdSStefano Zampini 
54599566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
5460d65f70fdSStefano Zampini   *B = work_mat[0];
54619566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
54629566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
54639566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
54643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5465d65f70fdSStefano Zampini }
5466d65f70fdSStefano Zampini 
5467d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
5468d71ae5a4SJacob Faibussowitsch {
5469aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
54705e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
5471022d8d2bSstefano_zampini   Mat       new_mat, lA;
54725e8657edSStefano Zampini   IS        is_local, is_global;
5473d65f70fdSStefano Zampini   PetscInt  local_size;
5474b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
5475aa0d41d4SStefano Zampini 
5476aa0d41d4SStefano Zampini   PetscFunctionBegin;
54779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
54789566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
54799de2952eSStefano Zampini   if (pcbddc->mat_graph->multi_element) {
54809de2952eSStefano Zampini     Mat     *mats, *bdiags;
54819de2952eSStefano Zampini     IS      *gsubs;
54829de2952eSStefano Zampini     PetscInt nsubs = pcbddc->n_local_subs;
54839de2952eSStefano Zampini 
54849de2952eSStefano Zampini     PetscCall(PetscCalloc1(nsubs * nsubs, &mats));
54859de2952eSStefano Zampini     PetscCall(PetscMalloc1(nsubs, &gsubs));
54869de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, pcbddc->local_subs[i], &gsubs[i]));
54879de2952eSStefano Zampini     PetscCall(MatCreateSubMatrices(ChangeOfBasisMatrix, nsubs, gsubs, gsubs, MAT_INITIAL_MATRIX, &bdiags));
54889de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISDestroy(&gsubs[i]));
54899de2952eSStefano Zampini     PetscCall(PetscFree(gsubs));
54909de2952eSStefano Zampini 
54919de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) mats[i * (1 + nsubs)] = bdiags[i];
54929de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, nsubs, pcbddc->local_subs, nsubs, pcbddc->local_subs, mats, &new_mat));
54939de2952eSStefano Zampini     PetscCall(MatConvert(new_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &new_mat));
54949de2952eSStefano Zampini     PetscCall(MatDestroySubMatrices(nsubs, &bdiags));
54959de2952eSStefano Zampini     PetscCall(PetscFree(mats));
54969de2952eSStefano Zampini   } else {
54979566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
54989566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
54999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_local));
55009566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
55019566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_global));
55029de2952eSStefano Zampini   }
5503906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
5504906d46d4SStefano Zampini     Vec       x, x_change;
5505906d46d4SStefano Zampini     PetscReal error;
5506906d46d4SStefano Zampini 
55079566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
55089566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
55099566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
55109566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
55119566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
55129566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
551388428137SStefano Zampini     if (!pcbddc->change_interior) {
551488428137SStefano Zampini       const PetscScalar *x, *y, *v;
551588428137SStefano Zampini       PetscReal          lerror = 0.;
551688428137SStefano Zampini       PetscInt           i;
551788428137SStefano Zampini 
55189566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
55199566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
55209566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
552188428137SStefano Zampini       for (i = 0; i < local_size; i++)
55229371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
55239566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
55249566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
55259566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
5526462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
5527637e8532SStefano Zampini       if (error > PETSC_SMALL) {
5528637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
552963a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
5530637e8532SStefano Zampini         } else {
553163a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
5532637e8532SStefano Zampini         }
5533637e8532SStefano Zampini       }
553488428137SStefano Zampini     }
55359566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
55369566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
55379566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
55389566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
5539637e8532SStefano Zampini     if (error > PETSC_SMALL) {
5540637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
554163a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
5542637e8532SStefano Zampini       } else {
554363a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
5544637e8532SStefano Zampini       }
5545637e8532SStefano Zampini     }
55469566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
55479566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
5548906d46d4SStefano Zampini   }
5549906d46d4SStefano Zampini 
5550022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
55519566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
5552022d8d2bSstefano_zampini 
555322d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
55549566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
555522d5777bSStefano Zampini   if (isseqaij) {
55569566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
55579566063dSJacob Faibussowitsch     PetscCall(MatPtAP(matis->A, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
5558022d8d2bSstefano_zampini     if (lA) {
5559022d8d2bSstefano_zampini       Mat work;
55609566063dSJacob Faibussowitsch       PetscCall(MatPtAP(lA, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
55619566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
55629566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5563022d8d2bSstefano_zampini     }
5564aa0d41d4SStefano Zampini   } else {
5565a00504b5SStefano Zampini     Mat work_mat;
55661cf9b237SStefano Zampini 
55679566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
55689566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
55699566063dSJacob Faibussowitsch     PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
55709566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
5571022d8d2bSstefano_zampini     if (lA) {
5572022d8d2bSstefano_zampini       Mat work;
55739566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
55749566063dSJacob Faibussowitsch       PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
55759566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
55769566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5577022d8d2bSstefano_zampini     }
5578aa0d41d4SStefano Zampini   }
5579b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
5580b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
55819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
55823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5583aa0d41d4SStefano Zampini }
5584aa0d41d4SStefano Zampini 
5585d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
5586d71ae5a4SJacob Faibussowitsch {
5587f4f49eeaSPierre Jolivet   PC_IS          *pcis        = (PC_IS *)pc->data;
5588a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
5589d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
559053892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
55913a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
55923a50541eSStefano Zampini   PetscInt        vbs, bs;
55936816873aSStefano Zampini   PetscBT         bitmask = NULL;
5594a64d13efSStefano Zampini 
5595a64d13efSStefano Zampini   PetscFunctionBegin;
5596b23d619eSStefano Zampini   /*
5597b23d619eSStefano Zampini     No need to setup local scatters if
5598b23d619eSStefano Zampini       - primal space is unchanged
5599b23d619eSStefano Zampini         AND
5600b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
5601b23d619eSStefano Zampini         AND
5602b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
5603b23d619eSStefano Zampini   */
56043ba16761SJacob Faibussowitsch   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) PetscFunctionReturn(PETSC_SUCCESS);
5605f4ddd8eeSStefano Zampini   /* destroy old objects */
56069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
56079566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
56089566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
5609a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
5610b371cd4fSStefano Zampini   n_B        = pcis->n_B;
5611b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
5612b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
56133a50541eSStefano Zampini 
5614e602f447SPierre Jolivet   /* Dohrmann's notation: dofs split in R (Remaining: all dofs but the vertices) and V (Vertices) */
56156816873aSStefano Zampini 
561653892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
5617b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
56189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
56199566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
562048a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
56214641a718SStefano Zampini 
5622a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
5623ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, i)) idx_R_local[n_R++] = i;
5624a64d13efSStefano Zampini     }
5625df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5626df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
56276816873aSStefano Zampini 
56289566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
56299566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
56306816873aSStefano Zampini   }
56313a50541eSStefano Zampini 
56323a50541eSStefano Zampini   /* Block code */
56333a50541eSStefano Zampini   vbs = 1;
56349566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
56353a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
56363a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
56373a50541eSStefano Zampini     PetscInt *vary;
5638b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
56399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
56409566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
5641d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5642d3df7717SStefano 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 */
56430e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5644d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
56453a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
56463a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
56473a50541eSStefano Zampini           break;
56483a50541eSStefano Zampini         }
56493a50541eSStefano Zampini       }
56509566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5651d3df7717SStefano Zampini     } else {
5652d3df7717SStefano Zampini       /* Verify directly the R set */
5653d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5654d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5655d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5656d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5657d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5658d3df7717SStefano Zampini             break;
5659d3df7717SStefano Zampini           }
5660d3df7717SStefano Zampini         }
5661d3df7717SStefano Zampini       }
5662d3df7717SStefano Zampini     }
56633a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
56643a50541eSStefano Zampini       vbs = bs;
5665ad540459SPierre Jolivet       for (i = 0; i < n_R / vbs; i++) idx_R_local[i] = idx_R_local[vbs * i] / vbs;
56663a50541eSStefano Zampini     }
56673a50541eSStefano Zampini   }
56689566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5669b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5670df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
567153892102SStefano Zampini 
56729566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
56739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
56749566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5675df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
567653892102SStefano Zampini   } else {
56779566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
567853892102SStefano Zampini   }
5679a64d13efSStefano Zampini 
5680a64d13efSStefano Zampini   /* print some info if requested */
5681a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
56829566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
56839566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
56849566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
56859566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
568663a3b9bcSJacob 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));
56879371c9d4SSatish 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,
56889371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
56899566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5690a64d13efSStefano Zampini   }
5691a64d13efSStefano Zampini 
5692a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5693b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
56946816873aSStefano Zampini     IS        is_aux1, is_aux2;
56956816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
56966816873aSStefano Zampini 
56979566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
56989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
56999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
57009566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
570148a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
57029566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5703a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
5704ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5705a64d13efSStefano Zampini     }
57069566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
57079566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5708a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
5709ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, is_indices[i])) aux_array2[j++] = i;
5710a64d13efSStefano Zampini     }
57119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
57129566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
57139566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
57149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
57159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5716a64d13efSStefano Zampini 
57178eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
57189566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5719a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
5720ad540459SPierre Jolivet         if (PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5721a64d13efSStefano Zampini       }
57229566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
57239566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
57249566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5725a64d13efSStefano Zampini     }
57269566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
57279566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5728d62866d3SStefano Zampini   } else {
5729df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
57306816873aSStefano Zampini     IS                 tis;
57316816873aSStefano Zampini     PetscInt           schur_size;
57326816873aSStefano Zampini 
57339566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
57349566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
57359566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
57369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
57376816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
57389566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
57399566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
57409566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5741d62866d3SStefano Zampini     }
5742d62866d3SStefano Zampini   }
57433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5744a64d13efSStefano Zampini }
5745a64d13efSStefano Zampini 
5746d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B)
5747d71ae5a4SJacob Faibussowitsch {
574892cccca0SStefano Zampini   MatNullSpace NullSpace;
574992cccca0SStefano Zampini   Mat          dmat;
575092cccca0SStefano Zampini   const Vec   *nullvecs;
575192cccca0SStefano Zampini   Vec          v, v2, *nullvecs2;
57526d9e27e4SStefano Zampini   VecScatter   sct = NULL;
5753eb06acf8SStefano Zampini   PetscScalar *ddata;
5754295df10fSStefano Zampini   PetscInt     k, nnsp_size, bsiz, bsiz2, n, N, bs;
575592cccca0SStefano Zampini   PetscBool    nnsp_has_cnst;
575692cccca0SStefano Zampini 
575792cccca0SStefano Zampini   PetscFunctionBegin;
57586d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
57596d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
57606d9e27e4SStefano Zampini 
576148a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
57626d9e27e4SStefano Zampini     sct = matis->cctx;
57639566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
57646d9e27e4SStefano Zampini   } else {
57659566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
576648a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
57673ba16761SJacob Faibussowitsch     if (NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
57686d9e27e4SStefano Zampini   }
57699566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
577048a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
57713ba16761SJacob Faibussowitsch   if (!NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
57726d9e27e4SStefano Zampini 
57739566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
57749566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
577548a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
5776835f2295SStefano Zampini   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, &nullvecs));
5777295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
57789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
57799566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
57809566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
57819566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
57829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
578392cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
57849566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
57859566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
57869566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
578792cccca0SStefano Zampini   }
578892cccca0SStefano Zampini   if (nnsp_has_cnst) {
57899566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
57909566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
579192cccca0SStefano Zampini   }
57929566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
57939566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5794295df10fSStefano Zampini 
57959566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
579649abdd8aSBarry Smith   PetscCall(PetscObjectContainerCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", ddata, PetscCtxDestroyDefault));
57979566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
57989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5799eb06acf8SStefano Zampini 
580048a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
58019566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
58029566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
58039566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
58049566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
58059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
58069566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
58073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
580892cccca0SStefano Zampini }
5809304d26faSStefano Zampini 
5810d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5811d71ae5a4SJacob Faibussowitsch {
5812304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5813304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5814304d26faSStefano Zampini   PC           pc_temp;
5815304d26faSStefano Zampini   Mat          A_RR;
581692cccca0SStefano Zampini   MatNullSpace nnsp;
5817f4ddd8eeSStefano Zampini   MatReuse     reuse;
5818304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5819304d26faSStefano Zampini   PetscReal    value;
582004708bb6SStefano Zampini   PetscInt     n_D, n_R;
5821b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
58220cd8b6e2SStefano Zampini   PetscBool    f = PETSC_FALSE;
5823312be037SStefano Zampini   char         dir_prefix[256], neu_prefix[256], str_level[16];
5824e604994aSStefano Zampini   size_t       len;
5825304d26faSStefano Zampini 
5826304d26faSStefano Zampini   PetscFunctionBegin;
58279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
58286d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
58296d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
58306d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
58316d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
58326d9e27e4SStefano Zampini 
58339566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
58349566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
58359566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
58366d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
5837462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&lhas, &ghas, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
583848a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
58396d9e27e4SStefano Zampini   }
58406d9e27e4SStefano Zampini 
5841e604994aSStefano Zampini   /* compute prefixes */
5842c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(dir_prefix, "", sizeof(dir_prefix)));
5843c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(neu_prefix, "", sizeof(neu_prefix)));
5844e604994aSStefano Zampini   if (!pcbddc->current_level) {
58459566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
58469566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
58479566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
58489566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5849e604994aSStefano Zampini   } else {
5850835f2295SStefano Zampini     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%" PetscInt_FMT "_", pcbddc->current_level));
58519566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
5852e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
5853312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
5854312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
5855a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
58569566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
58579566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
58589566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
58599566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
58609566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
58619566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
5862e604994aSStefano Zampini   }
5863e604994aSStefano Zampini 
5864304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
5865684f6988SStefano Zampini   if (dirichlet) {
5866d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5867450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
58687827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
5869450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
5870a3df083aSStefano Zampini         Mat A_IIn;
5871a3df083aSStefano Zampini 
58729566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
58739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
5874a3df083aSStefano Zampini         pcis->A_II = A_IIn;
5875a3df083aSStefano Zampini       }
5876450f8f5eSStefano Zampini     }
5877b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5878b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
5879b94d7dedSBarry Smith 
5880ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
5881964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
588292cccca0SStefano Zampini     opts = PETSC_FALSE;
5883304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
588492cccca0SStefano Zampini       opts = PETSC_TRUE;
58859566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
58863821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_D, pc->kspnestlevel));
58879566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
5888304d26faSStefano Zampini       /* default */
58899566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
58909566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
58919566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
58929566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
58939577ea80SStefano Zampini       if (issbaij) {
58949566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
58959577ea80SStefano Zampini       } else {
58969566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
58979577ea80SStefano Zampini       }
58989566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
589992cccca0SStefano Zampini     }
59009566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
59019de2952eSStefano Zampini     PetscCall(MatViewFromOptions(pcis->pA_II, NULL, "-mat_view"));
59029566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
5903304d26faSStefano Zampini     /* Allow user's customization */
59041baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
59059566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
59066d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
59079566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
590892cccca0SStefano Zampini     }
59099566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
59109566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
59110cd8b6e2SStefano Zampini     PetscCall(PetscObjectHasFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
591292cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5913cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5914cd18cfedSStefano Zampini       const PetscInt *idxs;
5915cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5916cd18cfedSStefano Zampini 
59179566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
59189566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
59199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5920cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5921ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5922cd18cfedSStefano Zampini       }
59239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
59249566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
59259566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5926cd18cfedSStefano Zampini     }
5927b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
5928df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5929d62866d3SStefano Zampini 
59309566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
5931d5574798SStefano Zampini     }
593292cccca0SStefano Zampini 
5933304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5934304d26faSStefano Zampini     if (!n_D) {
59359566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
59369566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5937304d26faSStefano Zampini     }
59389566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
5939304d26faSStefano Zampini     /* set ksp_D into pcis data */
59409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
59419566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
5942304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
5943684f6988SStefano Zampini   }
5944304d26faSStefano Zampini 
5945304d26faSStefano Zampini   /* NEUMANN PROBLEM */
59460a545947SLisandro Dalcin   A_RR = NULL;
5947684f6988SStefano Zampini   if (neumann) {
5948d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
594904708bb6SStefano Zampini     PetscInt        ibs, mbs;
5950b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
595104708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
59520aa714b2SStefano Zampini 
59530aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
59540aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
59550aa714b2SStefano Zampini       IS iP;
59560aa714b2SStefano Zampini 
59570aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
59589566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
59590aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
59600aa714b2SStefano Zampini     }
5961f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
59629566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
5963f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
5964f4ddd8eeSStefano Zampini       PetscInt nn_R;
59659566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
59669566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
59679566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
5968f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
59699566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
59709566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5971f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5972f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5973727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
59749566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
5975f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
5976f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
5977f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
5978f4ddd8eeSStefano Zampini         }
5979f4ddd8eeSStefano Zampini       }
5980f4ddd8eeSStefano Zampini       /* last check */
5981d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
59829566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5983f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5984f4ddd8eeSStefano Zampini       }
5985f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
5986f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
5987f4ddd8eeSStefano Zampini     }
5988365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
5989365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
59909566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
59919566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
59929566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
599304708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
599404708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
59959566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
59969566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
5997af732b37SStefano Zampini       } else {
59989566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
59996816873aSStefano Zampini       }
60004cf0e950SBarry Smith     } else if (issbaij) { /* need to convert to BAIJ to get off-diagonal blocks */
600104708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
60029566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
60039566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
600404708bb6SStefano Zampini       } else {
60059566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
600604708bb6SStefano Zampini       }
600704708bb6SStefano Zampini     }
6008a00504b5SStefano Zampini     /* extract A_RR */
60090aa714b2SStefano Zampini     if (reuse_neumann_solver) {
6010a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6011a00504b5SStefano Zampini 
6012a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
60139566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
6014a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
60159566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
601616e386b8SStefano Zampini         } else {
60179566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
6018a00504b5SStefano Zampini         }
6019a00504b5SStefano Zampini       } else {
60209566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
60219566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
60229566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
6023a00504b5SStefano Zampini       }
6024a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
60259566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
602616e386b8SStefano Zampini     }
6027b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
6028b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
602992cccca0SStefano Zampini     opts = PETSC_FALSE;
6030f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
603192cccca0SStefano Zampini       opts = PETSC_TRUE;
60329566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
60333821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_R, pc->kspnestlevel));
60349566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
6035304d26faSStefano Zampini       /* default */
60369566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
60379566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
60389566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
60399566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
60409577ea80SStefano Zampini       if (issbaij) {
60419566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
60429577ea80SStefano Zampini       } else {
60439566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
60449577ea80SStefano Zampini       }
60459566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
604692cccca0SStefano Zampini     }
60479566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
60489de2952eSStefano Zampini     PetscCall(MatViewFromOptions(A_RR, NULL, "-mat_view"));
60499de2952eSStefano Zampini     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
605092cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
60519566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
605292cccca0SStefano Zampini     }
60539566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
60546d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
60559566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
605692cccca0SStefano Zampini     }
60579566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
60589566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
60590cd8b6e2SStefano Zampini     PetscCall(PetscObjectHasFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
606092cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
6061cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
6062cd18cfedSStefano Zampini       const PetscInt *idxs;
6063cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
6064cd18cfedSStefano Zampini 
60659566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
60669566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
60679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
6068cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
6069ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
6070cd18cfedSStefano Zampini       }
60719566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
60729566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
60739566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
6074cd18cfedSStefano Zampini     }
607592cccca0SStefano Zampini 
6076304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
6077304d26faSStefano Zampini     if (!n_R) {
60789566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
60799566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
6080304d26faSStefano Zampini     }
6081df4d28bfSStefano Zampini     /* Reuse solver if it is present */
60820aa714b2SStefano Zampini     if (reuse_neumann_solver) {
6083df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6084d62866d3SStefano Zampini 
60859566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
6086d62866d3SStefano Zampini     }
60879566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
6088684f6988SStefano Zampini   }
6089304d26faSStefano Zampini 
6090684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
60919566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
60929566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
60939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
6094684f6988SStefano Zampini   }
60959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
6096c7017625SStefano Zampini 
6097c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
609848a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
609948a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
610048a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
6101c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
6102c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
6103684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
61049566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
61059566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
61069566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
61079566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
61089566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
61099566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
6110f4f49eeaSPierre 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));
61119566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6112304d26faSStefano Zampini     }
6113684f6988SStefano Zampini     if (neumann) { /* Neumann */
61149566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
61159566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
61169566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
61179566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
61189566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
61199566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
6120f4f49eeaSPierre 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));
61219566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6122304d26faSStefano Zampini     }
6123684f6988SStefano Zampini   }
61245cbda25cSStefano Zampini   /* free Neumann problem's matrix */
61259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
61263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6127304d26faSStefano Zampini }
6128304d26faSStefano Zampini 
6129d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
6130d71ae5a4SJacob Faibussowitsch {
6131f4f49eeaSPierre Jolivet   PC_BDDC        *pcbddc       = (PC_BDDC *)pc->data;
6132be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
6133b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
6134674ae819SStefano Zampini 
6135674ae819SStefano Zampini   PetscFunctionBegin;
613648a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
613780677318SStefano Zampini   if (!pcbddc->switch_static) {
613880677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
61399566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
61409566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
614120c7b377SStefano Zampini     }
6142b334f244SStefano Zampini     if (!reuse_solver) {
61439566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
61449566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
614520c7b377SStefano Zampini     } else {
6146df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6147be83ff47SStefano Zampini 
61489566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
61499566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
615020c7b377SStefano Zampini     }
6151be83ff47SStefano Zampini   } else {
61529566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
61539566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
61549566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
61559566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
615680677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
61579566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
61589566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
61599566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
61609566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
6161674ae819SStefano Zampini     }
6162674ae819SStefano Zampini   }
61639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
6164b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
616580677318SStefano Zampini     if (applytranspose) {
61669566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
616780677318SStefano Zampini     } else {
61689566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
616980677318SStefano Zampini     }
61709566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
6171be83ff47SStefano Zampini   } else {
6172df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6173be83ff47SStefano Zampini 
6174be83ff47SStefano Zampini     if (applytranspose) {
61759566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6176be83ff47SStefano Zampini     } else {
61779566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6178be83ff47SStefano Zampini     }
6179be83ff47SStefano Zampini   }
61809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
61819566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
618280677318SStefano Zampini   if (!pcbddc->switch_static) {
6183b334f244SStefano Zampini     if (!reuse_solver) {
61849566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61859566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
6186be83ff47SStefano Zampini     } else {
6187df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6188be83ff47SStefano Zampini 
61899566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
61909566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
6191be83ff47SStefano Zampini     }
619280677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
61939566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
61949566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
619580677318SStefano Zampini     }
619680677318SStefano Zampini   } else {
61979566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61989566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61999566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
62009566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
620180677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
62029566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
62039566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
620480677318SStefano Zampini     }
62059566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
62069566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
62079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
62089566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
6209674ae819SStefano Zampini   }
62103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6211674ae819SStefano Zampini }
6212674ae819SStefano Zampini 
6213dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
6214d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
6215d71ae5a4SJacob Faibussowitsch {
6216f4f49eeaSPierre Jolivet   PC_BDDC          *pcbddc = (PC_BDDC *)pc->data;
6217f4f49eeaSPierre Jolivet   PC_IS            *pcis   = (PC_IS *)pc->data;
6218674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
6219674ae819SStefano Zampini 
6220674ae819SStefano Zampini   PetscFunctionBegin;
6221dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
62224fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6223dc359a40SStefano Zampini     if (applytranspose) {
62249566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
62259566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
6226dc359a40SStefano Zampini     } else {
62279566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
62289566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
622915aaf578SStefano Zampini     }
62304fee134fSStefano Zampini   } else {
62319566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
62324fee134fSStefano Zampini   }
6233efc2fbd9SStefano Zampini 
6234efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
62354f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
6236efc2fbd9SStefano Zampini     PetscScalar *array;
62374f1b2e48SStefano Zampini     PetscInt     j;
6238efc2fbd9SStefano Zampini 
62399566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
62404f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
62419566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6242efc2fbd9SStefano Zampini   }
6243efc2fbd9SStefano Zampini 
624412edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
62459566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
62469566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
62479566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
624812edc857SStefano Zampini 
62499f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
6250a1cb837bSStefano Zampini   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
625112edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
625251694757SStefano Zampini     Mat          coarse_mat;
6253964fefecSStefano Zampini     Vec          rhs, sol;
625451694757SStefano Zampini     MatNullSpace nullsp;
625527b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
6256964fefecSStefano Zampini 
625727b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
625827b6a85dSStefano Zampini       PC coarse_pc;
625927b6a85dSStefano Zampini 
62609566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
62619566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
626227b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
626327b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
6264f4f49eeaSPierre Jolivet         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)coarse_pc->data;
626527b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
62663bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
626727b6a85dSStefano Zampini       }
626827b6a85dSStefano Zampini     }
62699566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
62709566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
62719566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
627212edc857SStefano Zampini     if (applytranspose) {
627328b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
62749566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
62759566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
62769566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
62771baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
62782701bc32SStefano Zampini     } else {
62799566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
62801f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
62812701bc32SStefano Zampini         PC coarse_pc;
62822701bc32SStefano Zampini 
62831baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
62849566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
62859566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
62869566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
62879566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
628812edc857SStefano Zampini       } else {
62899566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
62909566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
62911baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
629212edc857SStefano Zampini       }
62932701bc32SStefano Zampini     }
62941d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
629527b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
629627b6a85dSStefano Zampini       PC       coarse_pc;
629727b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
629827b6a85dSStefano Zampini 
62999566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
6300f4f49eeaSPierre Jolivet       coarsepcbddc                           = (PC_BDDC *)coarse_pc->data;
630127b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
63023bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
630327b6a85dSStefano Zampini     }
630412edc857SStefano Zampini   }
6305a1cb837bSStefano Zampini   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
6306674ae819SStefano Zampini 
6307674ae819SStefano Zampini   /* Local solution on R nodes */
6308a1cb837bSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
63099f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
63109566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
63119566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
6312674ae819SStefano Zampini 
63134fee134fSStefano Zampini   /* Sum contributions from the two levels */
63144fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6315dc359a40SStefano Zampini     if (applytranspose) {
63169566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
63179566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6318dc359a40SStefano Zampini     } else {
63199566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
63209566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6321dc359a40SStefano Zampini     }
6322efc2fbd9SStefano Zampini     /* store p0 */
63234f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
6324efc2fbd9SStefano Zampini       PetscScalar *array;
63254f1b2e48SStefano Zampini       PetscInt     j;
6326efc2fbd9SStefano Zampini 
63279566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
63284f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
63299566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6330efc2fbd9SStefano Zampini     }
63314fee134fSStefano Zampini   } else { /* expand the coarse solution */
63324fee134fSStefano Zampini     if (applytranspose) {
63339566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
63344fee134fSStefano Zampini     } else {
63359566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
63364fee134fSStefano Zampini     }
63374fee134fSStefano Zampini   }
63383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6339674ae819SStefano Zampini }
6340674ae819SStefano Zampini 
6341d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode)
6342d71ae5a4SJacob Faibussowitsch {
6343f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
634412edc857SStefano Zampini   Vec                from, to;
63457ebab0bbSStefano Zampini   const PetscScalar *array;
6346674ae819SStefano Zampini 
6347674ae819SStefano Zampini   PetscFunctionBegin;
634812edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
634912edc857SStefano Zampini     from = pcbddc->coarse_vec;
635012edc857SStefano Zampini     to   = pcbddc->vec1_P;
635112edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
635212edc857SStefano Zampini       Vec tvec;
635358da7f69SStefano Zampini 
63549566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
63559566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
63569566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
63579566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
63589566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
63599566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
636012edc857SStefano Zampini     }
6361dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
636212edc857SStefano Zampini     from = pcbddc->vec1_P;
636312edc857SStefano Zampini     to   = pcbddc->coarse_vec;
636412edc857SStefano Zampini   }
63659566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
63663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6367674ae819SStefano Zampini }
6368674ae819SStefano Zampini 
6369d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
6370d71ae5a4SJacob Faibussowitsch {
6371f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
637212edc857SStefano Zampini   Vec                from, to;
63737ebab0bbSStefano Zampini   const PetscScalar *array;
6374674ae819SStefano Zampini 
6375674ae819SStefano Zampini   PetscFunctionBegin;
637612edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
637712edc857SStefano Zampini     from = pcbddc->coarse_vec;
637812edc857SStefano Zampini     to   = pcbddc->vec1_P;
6379dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
638012edc857SStefano Zampini     from = pcbddc->vec1_P;
638112edc857SStefano Zampini     to   = pcbddc->coarse_vec;
638212edc857SStefano Zampini   }
63839566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
638412edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
638512edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
638612edc857SStefano Zampini       Vec tvec;
638758da7f69SStefano Zampini 
63889566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
63899566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
63909566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
63919566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
639258da7f69SStefano Zampini     }
639358da7f69SStefano Zampini   } else {
639458da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
63959566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
639612edc857SStefano Zampini     }
639712edc857SStefano Zampini   }
63983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6399674ae819SStefano Zampini }
6400674ae819SStefano Zampini 
6401d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
6402d71ae5a4SJacob Faibussowitsch {
6403f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
6404674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
6405674ae819SStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
6406984c4197SStefano Zampini   /* one and zero */
6407984c4197SStefano Zampini   PetscScalar one = 1.0, zero = 0.0;
6408984c4197SStefano Zampini   /* space to store constraints and their local indices */
64099162d606SStefano Zampini   PetscScalar *constraints_data;
64109162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
64119162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
64129162d606SStefano Zampini   PetscInt    *constraints_n;
6413984c4197SStefano Zampini   /* iterators */
6414b3d85658SStefano Zampini   PetscInt i, j, k, total_counts, total_counts_cc, cum;
6415984c4197SStefano Zampini   /* BLAS integers */
6416e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
6417e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
6418c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
6419727cdba6SStefano Zampini   /* reuse */
64200e6343abSStefano Zampini   PetscInt  olocal_primal_size, olocal_primal_size_cc;
64210e6343abSStefano Zampini   PetscInt *olocal_primal_ref_node, *olocal_primal_ref_mult;
6422984c4197SStefano Zampini   /* change of basis */
6423b3d85658SStefano Zampini   PetscBool qr_needed;
64249162d606SStefano Zampini   PetscBT   change_basis, qr_needed_idx;
6425984c4197SStefano Zampini   /* auxiliary stuff */
642664efe560SStefano Zampini   PetscInt *nnz, *is_indices;
64278a0068c3SStefano Zampini   PetscInt  ncc;
6428984c4197SStefano Zampini   /* some quantities */
642945a1bb75SStefano Zampini   PetscInt  n_vertices, total_primal_vertices, valid_constraints;
6430a58a30b4SStefano Zampini   PetscInt  size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
643157715f18SStefano Zampini   PetscReal tol; /* tolerance for retaining eigenmodes */
6432984c4197SStefano Zampini 
6433674ae819SStefano Zampini   PetscFunctionBegin;
643457715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
64358e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
64369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
64379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
64389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
6439088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
6440088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
64410e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
64429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
64439566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
64449566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
64459566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
64469566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
6447cf5a6209SStefano Zampini 
6448cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
64499162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
6450cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
6451cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
6452cf5a6209SStefano Zampini     Vec         *localnearnullsp;
6453cf5a6209SStefano Zampini     PetscScalar *array;
645432fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
6455cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
6456674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
6457b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
6458674ae819SStefano Zampini     PetscScalar *work;
6459674ae819SStefano Zampini     PetscReal   *singular_vals;
6460674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
6461674ae819SStefano Zampini     PetscReal *rwork;
6462674ae819SStefano Zampini #endif
646355080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
6464964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
6465964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
646655080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
6467674ae819SStefano Zampini 
646855080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
6469b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
647055080a34SStefano Zampini     use_pod = PETSC_TRUE;
647155080a34SStefano Zampini #endif
6472674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
64739566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
647432fe681dSStefano Zampini     o_nf       = n_ISForFaces;
647532fe681dSStefano Zampini     o_ne       = n_ISForEdges;
647632fe681dSStefano Zampini     n_vertices = 0;
647732fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
6478e4d548c7SStefano Zampini     /* print some info */
64795c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
648032fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
64819566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
64829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
64839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
648432fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
648563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
648663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
64879566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
64889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
6489e4d548c7SStefano Zampini     }
6490e4d548c7SStefano Zampini 
649132fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
649232fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
649332fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
649470022509SStefano Zampini 
6495674ae819SStefano Zampini     /* check if near null space is attached to global mat */
64966d9e27e4SStefano Zampini     if (pcbddc->use_nnsp) {
64979566063dSJacob Faibussowitsch       PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
64986d9e27e4SStefano Zampini     } else nearnullsp = NULL;
64996d9e27e4SStefano Zampini 
6500674ae819SStefano Zampini     if (nearnullsp) {
65019566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
6502f4ddd8eeSStefano Zampini       /* remove any stored info */
65039566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
65049566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
6505f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
65069566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
6507f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
65089566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
650948a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
6510984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
6511984c4197SStefano Zampini       nnsp_size     = 0;
6512674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
6513674ae819SStefano Zampini     }
6514984c4197SStefano Zampini     /* get max number of constraints on a single cc */
6515984c4197SStefano Zampini     max_constraints = nnsp_size;
6516984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
6517984c4197SStefano Zampini 
6518674ae819SStefano Zampini     /*
6519674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
65209162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
65219162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
65229162d606SStefano Zampini          There can be multiple constraints per connected component
6523674ae819SStefano Zampini                                                                                                                                                            */
65249162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
65259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
65269162d606SStefano Zampini 
65279162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
65289162d606SStefano Zampini     total_counts *= max_constraints;
6529674ae819SStefano Zampini     total_counts += n_vertices;
65309566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
65319162d606SStefano Zampini 
6532674ae819SStefano Zampini     total_counts           = 0;
6533674ae819SStefano Zampini     max_size_of_constraint = 0;
6534674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
65359162d606SStefano Zampini       IS used_is;
6536674ae819SStefano Zampini       if (i < n_ISForEdges) {
65379162d606SStefano Zampini         used_is = ISForEdges[i];
6538674ae819SStefano Zampini       } else {
65399162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
6540674ae819SStefano Zampini       }
65419566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
6542674ae819SStefano Zampini       total_counts += j;
6543674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
6544674ae819SStefano Zampini     }
65459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
65469162d606SStefano Zampini 
6547984c4197SStefano Zampini     /* get local part of global near null space vectors */
65489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
6549984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
65509566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
65519566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
65529566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
6553984c4197SStefano Zampini     }
6554674ae819SStefano Zampini 
6555242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
6556242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
6557a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
6558242a89d7SStefano Zampini 
6559984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
6560a773dcb8SStefano Zampini     if (!skip_lapack) {
6561674ae819SStefano Zampini       PetscScalar temp_work;
6562911cabfeSStefano Zampini 
656355080a34SStefano Zampini       if (use_pod) {
6564984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
65659566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
65669566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
65679566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
6568674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
65699566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
6570674ae819SStefano Zampini #endif
6571674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
65729566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
65739566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
6574674ae819SStefano Zampini         lwork = -1;
65759566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6576674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6577792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
6578674ae819SStefano Zampini #else
6579792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
6580674ae819SStefano Zampini #endif
65819566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
6582835f2295SStefano Zampini         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %" PetscBLASInt_FMT, lierr);
658355080a34SStefano Zampini       } else {
658455080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
6585674ae819SStefano Zampini         /* SVD */
6586674ae819SStefano Zampini         PetscInt max_n, min_n;
6587674ae819SStefano Zampini         max_n = max_size_of_constraint;
6588984c4197SStefano Zampini         min_n = max_constraints;
6589984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
6590674ae819SStefano Zampini           min_n = max_size_of_constraint;
6591984c4197SStefano Zampini           max_n = max_constraints;
6592674ae819SStefano Zampini         }
65939566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
6594674ae819SStefano Zampini   #if defined(PETSC_USE_COMPLEX)
65959566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
6596674ae819SStefano Zampini   #endif
6597674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
6598674ae819SStefano Zampini         lwork = -1;
65999566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
66009566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
66019566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
66029566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6603674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6604792fecdfSBarry 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));
6605674ae819SStefano Zampini   #else
6606792fecdfSBarry 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));
6607674ae819SStefano Zampini   #endif
66089566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
6609835f2295SStefano Zampini         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %" PetscBLASInt_FMT, lierr);
661055080a34SStefano Zampini #else
661155080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6612984c4197SStefano Zampini #endif /* on missing GESVD */
661355080a34SStefano Zampini       }
6614674ae819SStefano Zampini       /* Allocate optimal workspace */
66159566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
66169566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
6617674ae819SStefano Zampini     }
6618674ae819SStefano Zampini     /* Now we can loop on constraining sets */
6619674ae819SStefano Zampini     total_counts            = 0;
66209162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
66219162d606SStefano Zampini     constraints_data_ptr[0] = 0;
6622674ae819SStefano Zampini     /* vertices */
66239162d606SStefano Zampini     if (n_vertices) {
66249566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
66259566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
6626674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
66279162d606SStefano Zampini         constraints_n[total_counts]            = 1;
66289162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
66299162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
66309162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
6631674ae819SStefano Zampini         total_counts++;
6632674ae819SStefano Zampini       }
66339566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
6634674ae819SStefano Zampini     }
6635984c4197SStefano Zampini 
6636674ae819SStefano Zampini     /* edges and faces */
66379162d606SStefano Zampini     total_counts_cc = total_counts;
6638911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
66399162d606SStefano Zampini       IS        used_is;
66409162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
66419162d606SStefano Zampini 
6642911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
66439162d606SStefano Zampini         used_is       = ISForEdges[ncc];
6644984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
6645674ae819SStefano Zampini       } else {
66469162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6647984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6648674ae819SStefano Zampini       }
6649674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
66509162d606SStefano Zampini 
66519566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
665232fe681dSStefano Zampini       if (!size_of_constraint) continue;
66539566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6654674ae819SStefano Zampini       if (nnsp_has_cnst) {
66555b08dc53SStefano Zampini         PetscScalar quad_value;
66569162d606SStefano Zampini 
66579566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
66589162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
66599162d606SStefano Zampini 
6660a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6661674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6662a773dcb8SStefano Zampini         } else {
6663a773dcb8SStefano Zampini           quad_value = 1.0;
6664a773dcb8SStefano Zampini         }
6665ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value;
66669162d606SStefano Zampini         temp_constraints++;
6667674ae819SStefano Zampini         total_counts++;
6668674ae819SStefano Zampini       }
6669674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6670984c4197SStefano Zampini         PetscReal    real_value;
66719162d606SStefano Zampini         PetscScalar *ptr_to_data;
66729162d606SStefano Zampini 
66739566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
66749162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
6675ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) ptr_to_data[j] = array[is_indices[j]];
66769566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6677984c4197SStefano Zampini         /* check if array is null on the connected component */
66789566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6679792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
668057715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6681674ae819SStefano Zampini           temp_constraints++;
6682674ae819SStefano Zampini           total_counts++;
66839162d606SStefano Zampini           if (!idxs_copied) {
66849566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
66859162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6686674ae819SStefano Zampini           }
6687674ae819SStefano Zampini         }
66889162d606SStefano Zampini       }
66899566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
669045a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6691eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6692a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
66939162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
66949162d606SStefano Zampini 
66959162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
66969566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6697792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6698a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6699792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6700a773dcb8SStefano Zampini         } else { /* perform SVD */
67019162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6702674ae819SStefano Zampini 
670355080a34SStefano Zampini           if (use_pod) {
6704984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6705984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6706984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6707984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6708984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6709984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6710984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
67119566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6712674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
67139566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
67149566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6715674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
671648a46eb9SPierre 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));
6717674ae819SStefano Zampini             }
6718e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
67199566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
67209566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6721674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6722792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6723674ae819SStefano Zampini #else
6724792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6725674ae819SStefano Zampini #endif
67269566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6727835f2295SStefano Zampini             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %" PetscBLASInt_FMT, lierr);
6728984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6729674ae819SStefano Zampini             j = 0;
673087b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6731674ae819SStefano Zampini             total_counts      = total_counts - j;
673245a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6733e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
67349566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
67359566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
67369566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
67379566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
67389566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
67399566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6740674ae819SStefano Zampini             if (j < temp_constraints) {
6741984c4197SStefano Zampini               PetscInt ii;
6742984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
67439566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6744792fecdfSBarry 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));
67459566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6746984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
6747ad540459SPierre 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];
6748674ae819SStefano Zampini               }
6749674ae819SStefano Zampini             }
675055080a34SStefano Zampini           } else {
675155080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
67529566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
67539566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
67549566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
67559566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6756674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6757792fecdfSBarry 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));
6758674ae819SStefano Zampini   #else
6759792fecdfSBarry 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));
6760674ae819SStefano Zampini   #endif
6761835f2295SStefano Zampini             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %" PetscBLASInt_FMT, lierr);
67629566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6763984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6764e310c8b4SStefano Zampini             k = temp_constraints;
6765e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6766674ae819SStefano Zampini             j = 0;
676787b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
676845a1bb75SStefano Zampini             valid_constraints = k - j;
6769911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
677055080a34SStefano Zampini #else
677155080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6772984c4197SStefano Zampini #endif /* on missing GESVD */
6773674ae819SStefano Zampini           }
6774a773dcb8SStefano Zampini         }
677555080a34SStefano Zampini       }
67769162d606SStefano Zampini       /* update pointers information */
67779162d606SStefano Zampini       if (valid_constraints) {
67789162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
67799162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
67809162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
67819162d606SStefano Zampini         /* set change_of_basis flag */
67823ba16761SJacob Faibussowitsch         if (boolforchange) PetscCall(PetscBTSet(change_basis, total_counts_cc));
6783b3d85658SStefano Zampini         total_counts_cc++;
678445a1bb75SStefano Zampini       }
678545a1bb75SStefano Zampini     }
6786984c4197SStefano Zampini     /* free workspace */
67878f1c130eSStefano Zampini     if (!skip_lapack) {
67889566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6789984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
67909566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6791984c4197SStefano Zampini #endif
67929566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
67939566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
67949566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6795984c4197SStefano Zampini     }
679648a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
67979566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6798cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
679932fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
680008122e43SStefano Zampini   } else {
680108122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6802984c4197SStefano Zampini 
680308122e43SStefano Zampini     total_counts = 0;
680408122e43SStefano Zampini     n_vertices   = 0;
680548a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
680608122e43SStefano Zampini     max_constraints = 0;
68079162d606SStefano Zampini     total_counts_cc = 0;
680808122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
680908122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
68109162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
681108122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
681208122e43SStefano Zampini     }
68139162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
68149162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
68159162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
68169162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
681774d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
68189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
68199162d606SStefano Zampini     total_counts_cc = 0;
68209162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
6821ad540459SPierre Jolivet       if (pcbddc->adaptive_constraints_n[i]) constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
682208122e43SStefano Zampini     }
682308122e43SStefano Zampini 
68248bec7fa6SStefano Zampini     max_size_of_constraint = 0;
68259162d606SStefano 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]);
68269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
682708122e43SStefano Zampini     /* Change of basis */
68289566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
682908122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
683008122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
683148a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
683208122e43SStefano Zampini       }
683308122e43SStefano Zampini     }
683408122e43SStefano Zampini   }
6835984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
68369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
683708122e43SStefano Zampini 
68389162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
683932fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
68409566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
684163a3b9bcSJacob 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);
684232fe681dSStefano Zampini   }
6843674ae819SStefano Zampini 
6844674ae819SStefano Zampini   /* Create constraint matrix */
68459566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
68469566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
68479566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6848984c4197SStefano Zampini 
6849984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6850a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
68515a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
68529566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
6853984c4197SStefano Zampini   total_primal_vertices        = 0;
6854b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
68559162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
68569162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
685772b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
68589162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6859b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
686064efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
6861ad540459SPierre Jolivet       for (k = 0; k < constraints_n[i]; k++) pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k];
6862b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
686391af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
68643ba16761SJacob Faibussowitsch         PetscCall(PetscBTSet(qr_needed_idx, i));
6865a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
6866a717540cSStefano Zampini       }
6867fa434743SStefano Zampini     } else {
6868b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
6869fa434743SStefano Zampini     }
6870a717540cSStefano Zampini   }
6871b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6872b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
6873674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
68749566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
68759566063dSJacob 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));
68769566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
68770e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
6878984c4197SStefano Zampini 
6879984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
688074d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
68819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
6882984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
688374d5cdf7SStefano Zampini 
6884984c4197SStefano Zampini   j            = total_primal_vertices;
688574d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
6886b3d85658SStefano Zampini   cum          = total_primal_vertices;
68879162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
68884641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
6889b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6890b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6891b3d85658SStefano Zampini       cum++;
68929162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
689374d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
689474d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
689574d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
689674d5cdf7SStefano Zampini       }
68979162d606SStefano Zampini       j += constraints_n[i];
6898674ae819SStefano Zampini     }
6899674ae819SStefano Zampini   }
69009566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
69019566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
69029566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
6903088faed8SStefano Zampini 
6904674ae819SStefano Zampini   /* set values in constraint matrix */
690548a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
6906984c4197SStefano Zampini   total_counts = total_primal_vertices;
69079162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
69084641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
69099162d606SStefano Zampini       PetscInt *cols;
69109162d606SStefano Zampini 
69119162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
69129162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
69139162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
69149162d606SStefano Zampini         PetscInt     row = total_counts + k;
69159162d606SStefano Zampini         PetscScalar *vals;
69169162d606SStefano Zampini 
69179162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
69189566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
69199162d606SStefano Zampini       }
69209162d606SStefano Zampini       total_counts += constraints_n[i];
6921674ae819SStefano Zampini     }
6922674ae819SStefano Zampini   }
6923674ae819SStefano Zampini   /* assembling */
69249566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
69259566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
69269566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
6927088faed8SStefano Zampini 
6928674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6929674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
6930026de310SStefano Zampini     /* dual and primal dofs on a single cc */
6931984c4197SStefano Zampini     PetscInt dual_dofs, primal_dofs;
6932984c4197SStefano Zampini     /* working stuff for GEQRF */
69335a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
6934984c4197SStefano Zampini     PetscBLASInt lqr_work;
6935984c4197SStefano Zampini     /* working stuff for UNGQR */
69363c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
6937984c4197SStefano Zampini     PetscBLASInt lgqr_work;
6938984c4197SStefano Zampini     /* working stuff for TRTRS */
69395a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
69403f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
6941984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
6942984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
6943984c4197SStefano Zampini     PetscScalar *start_vals;
6944984c4197SStefano Zampini     /* working stuff for values insertion */
69454641a718SStefano Zampini     PetscBT   is_primal;
694664efe560SStefano Zampini     PetscInt *aux_primal_numbering_B;
6947906d46d4SStefano Zampini     /* matrix sizes */
6948906d46d4SStefano Zampini     PetscInt global_size, local_size;
6949906d46d4SStefano Zampini     /* temporary change of basis */
6950906d46d4SStefano Zampini     Mat localChangeOfBasisMatrix;
6951cf5a6209SStefano Zampini     /* extra space for debugging */
69525a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
6953984c4197SStefano Zampini 
69549566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
69559566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
69569566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
6957906d46d4SStefano Zampini     /* nonzeros for local mat */
69589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
69591dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6960bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
69611dd7afcfSStefano Zampini     } else {
69621dd7afcfSStefano Zampini       const PetscInt *ii;
69631dd7afcfSStefano Zampini       PetscInt        n;
69641dd7afcfSStefano Zampini       PetscBool       flg_row;
69659566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
69661dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
69679566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
69681dd7afcfSStefano Zampini     }
69699162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
6970a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
69719162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
6972a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
69739162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
6974a717540cSStefano Zampini         } else {
69759162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
69769162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
6977a717540cSStefano Zampini         }
6978a717540cSStefano Zampini       }
6979a717540cSStefano Zampini     }
69809566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
69819566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
69829566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
69831dd7afcfSStefano Zampini     /* Set interior change in the matrix */
69841dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
698548a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
69861dd7afcfSStefano Zampini     } else {
69871dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
69881dd7afcfSStefano Zampini       PetscScalar    *aa;
69891dd7afcfSStefano Zampini       PetscInt        n;
69901dd7afcfSStefano Zampini       PetscBool       flg_row;
69919566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
69929566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
699348a46eb9SPierre 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));
69949566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
69959566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
69961dd7afcfSStefano Zampini     }
6997a717540cSStefano Zampini 
6998a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
69999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
70009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
7001a717540cSStefano Zampini     }
7002a717540cSStefano Zampini 
7003a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
7004a717540cSStefano Zampini     /*
7005a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
7006a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
7007a717540cSStefano Zampini 
70087c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
7009a717540cSStefano Zampini 
70107c625d9fSStefano 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)
7011a6b551f4SStefano Zampini 
7012a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
7013a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
7014a717540cSStefano Zampini             |              ...                        |
7015a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
7016a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
7017a717540cSStefano Zampini 
7018a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
7019a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
7020a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
7021a6b551f4SStefano Zampini 
7022a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
7023a717540cSStefano Zampini     */
70245a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
7025984c4197SStefano Zampini       /* space to store Q */
70269566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
70274e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
70289566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
7029984c4197SStefano Zampini       /* first we issue queries for optimal work */
70309566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
70319566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
70329566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
7033984c4197SStefano Zampini       lqr_work = -1;
7034792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
7035835f2295SStefano Zampini       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %" PetscBLASInt_FMT, lierr);
70369566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
703759b05608SBarry Smith       PetscCall(PetscMalloc1(lqr_work, &qr_work));
7038984c4197SStefano Zampini       lgqr_work = -1;
70399566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
70409566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
70419566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
70429566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
70433f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
7044792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
7045835f2295SStefano Zampini       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %" PetscBLASInt_FMT, lierr);
70469566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
704759b05608SBarry Smith       PetscCall(PetscMalloc1(lgqr_work, &gqr_work));
7048984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
70499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
7050a717540cSStefano Zampini       /* allocating workspace for check */
705148a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
7052a717540cSStefano Zampini     }
7053984c4197SStefano Zampini     /* array to store whether a node is primal or not */
70549566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
70559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
70569566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
705763a3b9bcSJacob 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);
705848a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
70599566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
7060984c4197SStefano Zampini 
7061a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
70629162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
70639162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
70644641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
7065984c4197SStefano Zampini         /* get constraint info */
70669162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
7067984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
7068984c4197SStefano Zampini 
706948a46eb9SPierre 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));
7070984c4197SStefano Zampini 
7071fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
7072a717540cSStefano Zampini 
7073a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
707448a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7075984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
70769566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7077984c4197SStefano Zampini 
7078984c4197SStefano Zampini           /* compute QR decomposition of constraints */
70799566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
70809566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
70819566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70829566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7083792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
7084835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %" PetscBLASInt_FMT, lierr);
70859566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7086984c4197SStefano Zampini 
7087a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
70889566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
7089984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
70909566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
70919566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
70929566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70939566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
70949566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7095792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
7096835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %" PetscBLASInt_FMT, lierr);
70979566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7098984c4197SStefano Zampini 
7099a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
71009566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
71019566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
71029566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
71039566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
71049566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7105792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
7106835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %" PetscBLASInt_FMT, lierr);
71079566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7108984c4197SStefano Zampini 
7109984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
7110984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
7111984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
71129566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
71139566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
71149566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
71159566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
71169566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
71179566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
71189566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7119792fecdfSBarry 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));
71209566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
71219566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7122984c4197SStefano Zampini 
7123984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
71249162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
7125984c4197SStefano Zampini           /* insert cols for primal dofs */
7126984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
7127984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
71289162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
71299566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7130984c4197SStefano Zampini           }
7131984c4197SStefano Zampini           /* insert cols for dual dofs */
7132984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
71339162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
7134984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
71359162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
71369566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7137984c4197SStefano Zampini               j++;
7138674ae819SStefano Zampini             }
7139674ae819SStefano Zampini           }
7140984c4197SStefano Zampini 
7141984c4197SStefano Zampini           /* check change of basis */
7142984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
7143984c4197SStefano Zampini             PetscInt  ii, jj;
7144984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
71459566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
71469566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
71479566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
71489566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
71499566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
71509566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
71519566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7152792fecdfSBarry 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));
71539566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
7154984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
7155984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
7156cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
7157c068d9bbSLisandro 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;
7158674ae819SStefano Zampini               }
7159674ae819SStefano Zampini             }
7160984c4197SStefano Zampini             if (!valid_qr) {
71619566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
7162984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
7163984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
7164cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
716563a3b9bcSJacob 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])));
7166674ae819SStefano Zampini                   }
7167c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
716863a3b9bcSJacob 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])));
7169984c4197SStefano Zampini                   }
7170984c4197SStefano Zampini                 }
7171984c4197SStefano Zampini               }
7172674ae819SStefano Zampini             } else {
71739566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
7174674ae819SStefano Zampini             }
7175674ae819SStefano Zampini           }
7176a717540cSStefano Zampini         } else { /* simple transformation block */
7177a717540cSStefano Zampini           PetscInt    row, col;
7178a6b551f4SStefano Zampini           PetscScalar val, norm;
7179a6b551f4SStefano Zampini 
71809566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
7181792fecdfSBarry 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));
7182a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
71839162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
71849162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
7185bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
71869162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
71879566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
71889566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
7189a717540cSStefano Zampini             } else {
7190a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
71919162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
7192a717540cSStefano Zampini                 if (row != col) {
71939162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
7194a717540cSStefano Zampini                 } else {
71959162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
7196a717540cSStefano Zampini                 }
71979566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
7198a717540cSStefano Zampini               }
7199a717540cSStefano Zampini             }
7200a717540cSStefano Zampini           }
720148a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
7202a717540cSStefano Zampini         }
7203984c4197SStefano Zampini       } else {
720448a46eb9SPierre 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));
7205674ae819SStefano Zampini       }
7206674ae819SStefano Zampini     }
7207a717540cSStefano Zampini 
7208a717540cSStefano Zampini     /* free workspace */
7209a717540cSStefano Zampini     if (qr_needed) {
72101baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
72119566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
72129566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
72139566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
72149566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
72159566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
7216674ae819SStefano Zampini     }
72179566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
72189566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
72199566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
7220906d46d4SStefano Zampini 
7221906d46d4SStefano Zampini     /* assembling of global change of variable */
722288c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
7223bbb9e6c6SStefano Zampini       Mat      tmat;
722416f15bc4SStefano Zampini       PetscInt bs;
722516f15bc4SStefano Zampini 
72269566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
72279566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
72289566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
72299566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
72309566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
72319566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
72329566063dSJacob Faibussowitsch       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->ChangeOfBasisMatrix));
72339566063dSJacob Faibussowitsch       PetscCall(MatSetType(pcbddc->ChangeOfBasisMatrix, MATAIJ));
72349566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(pc->pmat, &bs));
72359566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(pcbddc->ChangeOfBasisMatrix, bs));
72369566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(pcbddc->ChangeOfBasisMatrix, local_size, local_size, global_size, global_size));
72379566063dSJacob Faibussowitsch       PetscCall(MatISSetMPIXAIJPreallocation_Private(tmat, pcbddc->ChangeOfBasisMatrix, PETSC_TRUE));
72389566063dSJacob Faibussowitsch       PetscCall(MatConvert(tmat, MATAIJ, MAT_REUSE_MATRIX, &pcbddc->ChangeOfBasisMatrix));
72399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
72409566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
72419566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
72429566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
72439566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
72449566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
72459566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
724688c03ad3SStefano Zampini 
7247906d46d4SStefano Zampini       /* check */
7248906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
7249906d46d4SStefano Zampini         PetscReal error;
7250906d46d4SStefano Zampini         Vec       x, x_change;
7251906d46d4SStefano Zampini 
72529566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
72539566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
72549566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
72559566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
72569566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
72579566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
72589566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
72599566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
72609566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
72619566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
72629566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
72639566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
7264049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
72659566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
72669566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
7267906d46d4SStefano Zampini       }
7268b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
7269b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
7270b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
7271bf3a8328SStefano Zampini 
727208401ef6SPierre 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");
7273b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
7274ac632422SStefano Zampini           Mat S_new, tmat;
7275bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
7276bbb9e6c6SStefano Zampini 
72779566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
72789566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
7279bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7280bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
7281bf3a8328SStefano Zampini             IS                     is_V;
72829566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
72839566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
72849566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
72859566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
72869566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
7287bf3a8328SStefano Zampini           }
72889566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
72899566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
72909566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
72919566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
7292bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7293bf3a8328SStefano Zampini             const PetscScalar *array;
7294bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
7295bf3a8328SStefano Zampini             PetscInt           i, n_V;
7296bf3a8328SStefano Zampini 
72979566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
72989566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
72999566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
73009566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
73019566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
7302b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
7303b087196eSStefano Zampini               PetscScalar val;
7304b087196eSStefano Zampini               PetscInt    idx;
7305b087196eSStefano Zampini 
7306b087196eSStefano Zampini               idx = idxs_V[i];
7307b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
73089566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
7309b087196eSStefano Zampini             }
73109566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
73119566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
73129566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
73139566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
73149566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
7315bf3a8328SStefano Zampini           }
7316ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
73179566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
7318ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
73199566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
73209566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
73219566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
73221baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
7323ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
73249566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
7325ac632422SStefano Zampini           }
73269566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
73279566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
7328b96c3477SStefano Zampini         }
7329c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
7330b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
7331c9db6a07SStefano Zampini           PetscInt i;
7332c9db6a07SStefano Zampini 
733348a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
73349566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
7335c9db6a07SStefano Zampini         }
7336b96c3477SStefano Zampini       }
733716909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
733816909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
733916909a7fSStefano Zampini       } else {
73409566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
734116909a7fSStefano Zampini       }
73421dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
734327b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
734472b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
73459566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
734672b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
734772b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
734872b8c272SStefano Zampini     }
73491dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
735027b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
73519566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
7352b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
7353906d46d4SStefano Zampini     } else {
73541dd7afcfSStefano Zampini       Mat benign_global = NULL;
735527b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
73561dd7afcfSStefano Zampini         Mat M;
73571dd7afcfSStefano Zampini 
73589e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
73599566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
73609566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
73619566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
73629e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
73639566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
73649566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
7365906d46d4SStefano Zampini         } else {
73669566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
73679566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
7368906d46d4SStefano Zampini         }
73699566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
73709566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
73719566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
73729566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
73731dd7afcfSStefano Zampini       }
73741dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
7375fb842aefSJose E. Roman         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &pcbddc->ChangeOfBasisMatrix));
73769566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
737727b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
73781dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
73791dd7afcfSStefano Zampini       }
73801dd7afcfSStefano Zampini     }
738116909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
738216909a7fSStefano Zampini       IS              is_global;
738316909a7fSStefano Zampini       const PetscInt *gidxs;
738416909a7fSStefano Zampini 
73859566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
73869566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
73879566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
73889566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
73899566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
739016909a7fSStefano Zampini     }
73911dd7afcfSStefano Zampini   }
739248a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
7393a717540cSStefano Zampini 
739472b8c272SStefano Zampini   if (!pcbddc->fake_change) {
73954f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
73964f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
73974f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
73984f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
7399019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
7400019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
7401019a44ceSStefano Zampini       pcbddc->local_primal_size++;
7402019a44ceSStefano Zampini     }
7403019a44ceSStefano Zampini 
7404019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
7405727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
7406727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
74079566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7408c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
74090e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
74109566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7411727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
7412727cdba6SStefano Zampini       }
74130e6343abSStefano Zampini     }
7414727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
7415462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
741672b8c272SStefano Zampini   }
74179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
7418727cdba6SStefano Zampini 
7419a717540cSStefano Zampini   /* flush dbg viewer */
74201baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7421a717540cSStefano Zampini 
7422e310c8b4SStefano Zampini   /* free workspace */
74239566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
74249566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
742508122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
74269566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
74279566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
742808122e43SStefano Zampini   } else {
7429d0609cedSBarry 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));
74309566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
74319566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
743208122e43SStefano Zampini   }
74333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7434674ae819SStefano Zampini }
7435674ae819SStefano Zampini 
7436d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
7437d71ae5a4SJacob Faibussowitsch {
743871582508SStefano Zampini   ISLocalToGlobalMapping map;
7439674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7440674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
744166da6bd7Sstefano_zampini   PetscInt               i, N;
744266da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
7443674ae819SStefano Zampini 
7444674ae819SStefano Zampini   PetscFunctionBegin;
74458af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
7446b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
74478e61c736SStefano Zampini     /* Reset previously computed graph */
74489566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
7449674ae819SStefano Zampini     /* Init local Graph struct */
74509566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
74519566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
74529566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
7453674ae819SStefano Zampini 
745448a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
7455575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
74569371c9d4SSatish 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,
74579371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
74589577ea80SStefano Zampini 
7459674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
746066da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
74614d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
74624d379d7bSStefano Zampini       PetscInt  nvtxs;
74639de2952eSStefano Zampini       PetscBool flg_row;
74649de2952eSStefano Zampini       Mat       A;
7465674ae819SStefano Zampini 
74669de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
74679de2952eSStefano Zampini       A = matis->A;
74689de2952eSStefano Zampini       for (PetscInt i = 0; i < pcbddc->local_adj_square; i++) {
74699de2952eSStefano Zampini         Mat AtA;
74709de2952eSStefano Zampini 
74719de2952eSStefano Zampini         PetscCall(MatProductCreate(A, A, NULL, &AtA));
74729de2952eSStefano Zampini         PetscCall(MatSetOptionsPrefix(AtA, "pc_bddc_graph_"));
74739de2952eSStefano Zampini         PetscCall(MatProductSetType(AtA, MATPRODUCT_AtB));
74749de2952eSStefano Zampini         PetscCall(MatProductSetFromOptions(AtA));
74759de2952eSStefano Zampini         PetscCall(MatProductSymbolic(AtA));
74769de2952eSStefano Zampini         PetscCall(MatProductClear(AtA));
74779de2952eSStefano Zampini         /* we only need the sparsity, cheat and tell PETSc the matrix has been assembled */
74789de2952eSStefano Zampini         AtA->assembled = PETSC_TRUE;
74799de2952eSStefano Zampini         PetscCall(MatDestroy(&A));
74809de2952eSStefano Zampini         A = AtA;
74819de2952eSStefano Zampini       }
74829de2952eSStefano Zampini       PetscCall(MatGetRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
74832fffb893SStefano Zampini       if (flg_row) {
74849566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
7485b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
74869de2952eSStefano Zampini         PetscCall(MatRestoreRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
748766da6bd7Sstefano_zampini         rcsr = PETSC_TRUE;
7488674ae819SStefano Zampini       }
74899de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
74909de2952eSStefano Zampini     }
74911baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7492674ae819SStefano Zampini 
7493ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
7494ab8c8b98SStefano Zampini       PetscReal   *lcoords;
7495ab8c8b98SStefano Zampini       PetscInt     n;
7496ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
7497835f2295SStefano Zampini       PetscMPIInt  cdimi;
7498ab8c8b98SStefano Zampini 
74994f819b78SStefano Zampini       /* TODO: support for blocked */
750063a3b9bcSJacob 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);
75019566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
75029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
7503835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(pcbddc->mat_graph->cdim, &cdimi));
7504835f2295SStefano Zampini       PetscCallMPI(MPI_Type_contiguous(cdimi, MPIU_REAL, &dimrealtype));
75059566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
75069566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
75079566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
75089566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
75099566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
7510ab8c8b98SStefano Zampini 
7511ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
7512ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
7513ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
7514ab8c8b98SStefano Zampini     }
75159371c9d4SSatish 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,
75169371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
7517625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
7518ab8c8b98SStefano Zampini 
75194f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
75204f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
752120c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
75224f1b2e48SStefano Zampini 
75239566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
75249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
752520c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
75264f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
75274f1b2e48SStefano Zampini         const PetscInt *idxs;
75284f1b2e48SStefano Zampini         PetscInt        nl, j;
75294f1b2e48SStefano Zampini 
75309566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
75319566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
753271582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
75339566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
75344f1b2e48SStefano Zampini       }
753520c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
753620c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
75374f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
75384f1b2e48SStefano Zampini     }
75399de2952eSStefano Zampini 
75409de2952eSStefano Zampini     /* Setup of Graph */
75419de2952eSStefano Zampini     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
75428af8fcf9SStefano Zampini   }
75434f1b2e48SStefano Zampini 
7544cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
7545674ae819SStefano Zampini     /* Graph's connected components analysis */
75469566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
754771582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
75484f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
75498af8fcf9SStefano Zampini   }
755066da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
75513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7552674ae819SStefano Zampini }
7553674ae819SStefano Zampini 
7554d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[])
7555d71ae5a4SJacob Faibussowitsch {
7556295df10fSStefano Zampini   PetscInt     i, j, n;
75579a7d3425SStefano Zampini   PetscScalar *alphas;
7558295df10fSStefano Zampini   PetscReal    norm, *onorms;
75599a7d3425SStefano Zampini 
75609a7d3425SStefano Zampini   PetscFunctionBegin;
7561295df10fSStefano Zampini   n = *nio;
75623ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
75639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
75649566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
756592cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
7566295df10fSStefano Zampini     onorms[0] = 0.0;
75679566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
7568295df10fSStefano Zampini   } else {
7569295df10fSStefano Zampini     onorms[0] = norm;
757092cccca0SStefano Zampini   }
7571295df10fSStefano Zampini 
75728c0031efSStefano Zampini   for (i = 1; i < n; i++) {
75739566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
75748c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
75759566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
75769566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
757792cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
7578295df10fSStefano Zampini       onorms[i] = 0.0;
75799566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
7580295df10fSStefano Zampini     } else {
7581295df10fSStefano Zampini       onorms[i] = norm;
758292cccca0SStefano Zampini     }
75839a7d3425SStefano Zampini   }
7584295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
7585295df10fSStefano Zampini   for (i = 0; i < n; i++) {
7586295df10fSStefano Zampini     if (onorms[i] == 0.0) {
7587295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
7588295df10fSStefano Zampini         if (onorms[j] != 0.0) {
75899566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
7590295df10fSStefano Zampini           onorms[j] = 0.0;
7591295df10fSStefano Zampini         }
7592295df10fSStefano Zampini       }
7593295df10fSStefano Zampini     }
7594295df10fSStefano Zampini   }
7595295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
75969566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
75973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75989a7d3425SStefano Zampini }
75999a7d3425SStefano Zampini 
7600ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void)
7601d71ae5a4SJacob Faibussowitsch {
7602e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
760357de7509SStefano Zampini   Mat                    A;
7604e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
7605e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
760652e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
760752e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
7608bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
760957de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
761027b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
761127b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
761227b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
761327b6a85dSStefano Zampini   MPI_Comm               subcomm;
7614a57a6d2fSStefano Zampini 
7615e7931f94SStefano Zampini   PetscFunctionBegin;
761657de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
76179566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
761828b400f6SJacob 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);
761957de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
762057de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
762163a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
762257de7509SStefano Zampini 
762357de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
76249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
76259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
76269566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
76279566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
7628bb360cb4SStefano Zampini   im_active = !!n;
7629462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
763057de7509SStefano Zampini   void_procs = size - active_procs;
763115229ffcSPierre Jolivet   /* get ranks of non-active processes in mat communicator */
763257de7509SStefano Zampini   if (void_procs) {
763357de7509SStefano Zampini     PetscInt ncand;
763457de7509SStefano Zampini 
763557de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
76369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
76379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
763857de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
7639ad540459SPierre Jolivet       if (!procs_candidates[i]) procs_candidates[ncand++] = i;
764057de7509SStefano Zampini     }
764157de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
764257de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
764357de7509SStefano Zampini   }
764457de7509SStefano Zampini 
7645bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
76469dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
76479566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
7648bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
764914f0bfb9SStefano Zampini     PetscInt issize, isidx, dest;
765014f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
765114f0bfb9SStefano Zampini     else dest = rank;
765257de7509SStefano Zampini     if (im_active) {
765357de7509SStefano Zampini       issize = 1;
765457de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
765514f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
765657de7509SStefano Zampini       } else {
765714f0bfb9SStefano Zampini         isidx = dest;
765857de7509SStefano Zampini       }
765957de7509SStefano Zampini     } else {
766057de7509SStefano Zampini       issize = 0;
766157de7509SStefano Zampini       isidx  = -1;
766257de7509SStefano Zampini     }
7663bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
76649566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
76659566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
76663ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
766757de7509SStefano Zampini   }
76689de2952eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_use_vwgt", &use_vwgt, NULL));
76699de2952eSStefano Zampini   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_threshold", &threshold, NULL));
767027b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7671e7931f94SStefano Zampini 
7672e7931f94SStefano Zampini   /* Get info on mapping */
76739566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
76749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7675e7931f94SStefano Zampini 
7676e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
76779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7678e7931f94SStefano Zampini   xadj[0] = 0;
7679e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
76809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
76819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
76829566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
768327b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
76849371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7685e7931f94SStefano Zampini 
768627b6a85dSStefano Zampini   xadj_count = 0;
76872b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
768827b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
768927b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7690d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7691d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7692d023bfaeSStefano Zampini         xadj_count++;
769327b6a85dSStefano Zampini         break;
769427b6a85dSStefano Zampini       }
7695e7931f94SStefano Zampini     }
7696e7931f94SStefano Zampini   }
7697d023bfaeSStefano Zampini   xadj[1] = xadj_count;
76989566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
76999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
77009566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7701e7931f94SStefano Zampini 
77029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7703e7931f94SStefano Zampini 
770427b6a85dSStefano Zampini   /* Restrict work on active processes only */
77059566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
770627b6a85dSStefano Zampini   if (void_procs) {
77079566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
77089566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
77099566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
771027b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
771127b6a85dSStefano Zampini   } else {
771227b6a85dSStefano Zampini     psubcomm = NULL;
771327b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
771427b6a85dSStefano Zampini   }
771527b6a85dSStefano Zampini 
771627b6a85dSStefano Zampini   v_wgt = NULL;
771727b6a85dSStefano Zampini   if (!color) {
77189566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
77199566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
77209566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7721c8587f34SStefano Zampini   } else {
772252e5ac9dSStefano Zampini     Mat             subdomain_adj;
772352e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
772452e5ac9dSStefano Zampini     MatPartitioning partitioner;
77256497c311SBarry Smith     PetscInt        rstart, rend;
77266497c311SBarry Smith     PetscMPIInt     irstart = 0, irend = 0;
772752e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
772857de7509SStefano Zampini     PetscMPIInt     size;
7729b0c7d250SStefano Zampini     PetscBool       aggregate;
7730b0c7d250SStefano Zampini 
77319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
773227b6a85dSStefano Zampini     if (void_procs) {
773327b6a85dSStefano Zampini       PetscInt prank = rank;
77349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
77359566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
773648a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
77379566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
773827b6a85dSStefano Zampini     } else {
773927b6a85dSStefano Zampini       oldranks = NULL;
774027b6a85dSStefano Zampini     }
7741b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
774227b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7743b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7744b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7745b0c7d250SStefano Zampini       PetscScalar *vals;
7746b0c7d250SStefano Zampini 
77479566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7748b0c7d250SStefano Zampini       lrows = 0;
7749b0c7d250SStefano Zampini       if (nrank < redprocs) {
7750b0c7d250SStefano Zampini         lrows = size / redprocs;
7751b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7752b0c7d250SStefano Zampini       }
77539566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
77549566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
7755835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(rstart, &irstart));
7756835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(rend, &irend));
77579566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
77589566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7759b0c7d250SStefano Zampini       row   = nrank;
7760b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7761b0c7d250SStefano Zampini       cols  = adjncy;
77629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7763b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
77649566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
77659566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
77669566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
77679566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
77689566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
77699566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
77709566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
777127b6a85dSStefano Zampini       if (use_vwgt) {
777227b6a85dSStefano Zampini         Vec                v;
777327b6a85dSStefano Zampini         const PetscScalar *array;
777427b6a85dSStefano Zampini         PetscInt           nl;
777527b6a85dSStefano Zampini 
77769566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
77779566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
77789566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
77799566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
77809566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
77819566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
77829566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
778322db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
77849566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
77859566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
778627b6a85dSStefano Zampini       }
7787b0c7d250SStefano Zampini     } else {
7788835f2295SStefano Zampini       PetscCall(MatCreateMPIAdj(subcomm, 1, size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
778927b6a85dSStefano Zampini       if (use_vwgt) {
77909566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7791bb360cb4SStefano Zampini         v_wgt[0] = n;
779227b6a85dSStefano Zampini       }
7793b0c7d250SStefano Zampini     }
77949566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7795e7931f94SStefano Zampini 
7796e7931f94SStefano Zampini     /* Partition */
77979566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7798ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
77999566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7800ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
78019566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7802ce64c636SStefano Zampini #else
78039566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7804ce64c636SStefano Zampini #endif
78059566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
78061baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
7807835f2295SStefano Zampini     *n_subdomains = PetscMin(size, *n_subdomains);
78089566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
78099566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
78109566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
78119566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7812e7931f94SStefano Zampini 
781352e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
78149566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
78159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
78169566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
781757de7509SStefano Zampini     if (!aggregate) {
781857de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
78196bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
782057de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
782127b6a85dSStefano Zampini       } else if (oldranks) {
7822b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
782327b6a85dSStefano Zampini       } else {
782427b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
782557de7509SStefano Zampini       }
782628143c3dSStefano Zampini     } else {
78277fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7828b0c7d250SStefano Zampini       PetscMPIInt  tag;
7829b0c7d250SStefano Zampini       MPI_Request *reqs;
7830b0c7d250SStefano Zampini 
78319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
78329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
78336497c311SBarry Smith       for (PetscMPIInt i = irstart; i < irend; i++) PetscCallMPI(MPIU_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
78346497c311SBarry Smith       PetscCallMPI(MPIU_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
78356497c311SBarry Smith       PetscCallMPI(MPI_Waitall(irend - irstart, reqs, MPI_STATUSES_IGNORE));
78369566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
783757de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
78386bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
78397fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
784027b6a85dSStefano Zampini       } else if (oldranks) {
78417fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
784227b6a85dSStefano Zampini       } else {
78437fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
784428143c3dSStefano Zampini       }
784557de7509SStefano Zampini     }
78469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7847e7931f94SStefano Zampini     /* clean up */
78489566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
78499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
78509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
78519566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
7852e7931f94SStefano Zampini   }
78539566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
78549566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
7855e7931f94SStefano Zampini 
7856e7931f94SStefano Zampini   /* assemble parallel IS for sends */
7857e7931f94SStefano Zampini   i = 1;
785827b6a85dSStefano Zampini   if (!color) i = 0;
78599566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
78603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7861e7931f94SStefano Zampini }
7862e7931f94SStefano Zampini 
78639371c9d4SSatish Balay typedef enum {
78649371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
78659371c9d4SSatish Balay   MATAIJ_PRIVATE,
78669371c9d4SSatish Balay   MATBAIJ_PRIVATE,
78679371c9d4SSatish Balay   MATSBAIJ_PRIVATE
78689371c9d4SSatish Balay } MatTypePrivate;
7869e7931f94SStefano Zampini 
7870ba38deedSJacob 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[])
7871d71ae5a4SJacob Faibussowitsch {
787270cf5478SStefano Zampini   Mat                    local_mat;
7873e7931f94SStefano Zampini   IS                     is_sends_internal;
78749d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
78751ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
78769d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
7877e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
7878e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
7879e7931f94SStefano Zampini   const PetscInt        *is_indices;
7880e7931f94SStefano Zampini   MatType                new_local_type;
7881e7931f94SStefano Zampini   /* buffers */
7882e7931f94SStefano Zampini   PetscInt          *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
788328143c3dSStefano Zampini   PetscInt          *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
78849d30be91SStefano Zampini   PetscInt          *recv_buffer_idxs_local;
78851683a169SBarry Smith   PetscScalar       *ptr_vals, *recv_buffer_vals;
78861683a169SBarry Smith   const PetscScalar *send_buffer_vals;
78871ae86dd6SStefano Zampini   PetscScalar       *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
7888e7931f94SStefano Zampini   /* MPI */
788928143c3dSStefano Zampini   MPI_Comm     comm, comm_n;
789028143c3dSStefano Zampini   PetscSubcomm subcomm;
7891e569e4e1SStefano Zampini   PetscMPIInt  n_sends, n_recvs, size;
789228143c3dSStefano Zampini   PetscMPIInt *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
789328143c3dSStefano Zampini   PetscMPIInt *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
789460b1fa21SPierre Jolivet   PetscMPIInt  len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
78951ae86dd6SStefano Zampini   MPI_Request *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
78961ae86dd6SStefano Zampini   MPI_Request *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
7897e7931f94SStefano Zampini 
7898e7931f94SStefano Zampini   PetscFunctionBegin;
789957de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
79009566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
79015f80ce2aSJacob 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);
790257de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
790357de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
790457de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
790557de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
790657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
79071ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
79081ae86dd6SStefano Zampini   if (nvecs) {
790908401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
79101ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
79111ae86dd6SStefano Zampini   }
791257de7509SStefano Zampini   /* further checks */
79139566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
79149566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
79159de2952eSStefano Zampini   /* XXX hack for multi_element */
79169de2952eSStefano Zampini   if (!isdense) PetscCall(MatConvert(local_mat, MATDENSE, MAT_INPLACE_MATRIX, &local_mat));
79179de2952eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
79185f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
79199de2952eSStefano Zampini 
79209566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
79215f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
792257de7509SStefano Zampini   if (reuse && *mat_n) {
792370cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
792457de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
79259566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
79265f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
79279566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
79289566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
792963a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
793063a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
793170cf5478SStefano Zampini   }
79329566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
7933064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
793457de7509SStefano Zampini 
7935e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
7936e7931f94SStefano Zampini   if (!is_sends) {
79375f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
79389566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
7939c8587f34SStefano Zampini   } else {
79409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
7941e7931f94SStefano Zampini     is_sends_internal = is_sends;
7942c8587f34SStefano Zampini   }
7943e7931f94SStefano Zampini 
7944e7931f94SStefano Zampini   /* get comm */
79459566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7946e7931f94SStefano Zampini 
7947e7931f94SStefano Zampini   /* compute number of sends */
79489566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
79499566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
7950e7931f94SStefano Zampini 
7951e7931f94SStefano Zampini   /* compute number of receives */
79529566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
79539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
79549566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
79559566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
7956e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
79579566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
79589566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
7959e7931f94SStefano Zampini 
796028143c3dSStefano Zampini   /* restrict comm if requested */
79610a545947SLisandro Dalcin   subcomm     = NULL;
796228143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
796328143c3dSStefano Zampini   if (restrict_comm) {
7964779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
7965779c1cceSStefano Zampini 
796628143c3dSStefano Zampini     color = 0;
796753a05cb3SStefano Zampini     if (restrict_full) {
79686aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
796953a05cb3SStefano Zampini     } else {
79706aad120cSJose 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 */
797153a05cb3SStefano Zampini     }
7972462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
7973e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
797428143c3dSStefano Zampini     /* check if reuse has been requested */
797557de7509SStefano Zampini     if (reuse) {
797628143c3dSStefano Zampini       if (*mat_n) {
797728143c3dSStefano Zampini         PetscMPIInt subcommsize2;
79789566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
79795f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
798028143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
798128143c3dSStefano Zampini       } else {
798228143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
798328143c3dSStefano Zampini       }
798428143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
7985779c1cceSStefano Zampini       PetscMPIInt rank;
7986779c1cceSStefano Zampini 
79879566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
79889566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
79899566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
79909566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
7991306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
799228143c3dSStefano Zampini     }
799328143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
799428143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
799528143c3dSStefano Zampini   } else {
799628143c3dSStefano Zampini     comm_n = comm;
799728143c3dSStefano Zampini   }
799828143c3dSStefano Zampini 
7999e7931f94SStefano Zampini   /* prepare send/receive buffers */
80009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
80019566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
80029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
80039566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
800448a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
8005e7931f94SStefano Zampini 
800628143c3dSStefano Zampini   /* Get data from local matrices */
8007e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
8008e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
8009e7931f94SStefano Zampini   /*
8010e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
8011e7931f94SStefano Zampini        send_buffer_idxs should contain:
8012e7931f94SStefano Zampini        - MatType_PRIVATE type
8013e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
8014e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
8015e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
8016e7931f94SStefano Zampini     */
8017e432b41dSStefano Zampini   {
8018e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
8019e432b41dSStefano Zampini 
80209566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
80219566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
80229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
80239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
8024e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
8025e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
80269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
80279566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
80289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
80299566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
8030e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
8031e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
8032e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
8033c8587f34SStefano Zampini     }
8034c8587f34SStefano Zampini   }
80359566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
803628143c3dSStefano Zampini   /* additional is (if any) */
803728143c3dSStefano Zampini   if (nis) {
803828143c3dSStefano Zampini     PetscMPIInt psum;
803928143c3dSStefano Zampini     PetscInt    j;
804028143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
804128143c3dSStefano Zampini       PetscInt plen;
80429566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
80439566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
80446aad120cSJose E. Roman       psum += len + 1; /* indices + length */
804528143c3dSStefano Zampini     }
80469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
804728143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
804828143c3dSStefano Zampini       PetscInt        plen;
804928143c3dSStefano Zampini       const PetscInt *is_array_idxs;
80509566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
805128143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
80529566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
80539566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
80549566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
80556aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
805628143c3dSStefano Zampini     }
8057ad540459SPierre Jolivet     for (i = 0; i < n_sends; i++) ilengths_idxs_is[is_indices[i]] = psum;
80589566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
805928143c3dSStefano Zampini   }
80609566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
806128143c3dSStefano Zampini 
8062e7931f94SStefano Zampini   buf_size_idxs    = 0;
8063e7931f94SStefano Zampini   buf_size_vals    = 0;
806428143c3dSStefano Zampini   buf_size_idxs_is = 0;
80651ae86dd6SStefano Zampini   buf_size_vecs    = 0;
8066e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8067835f2295SStefano Zampini     buf_size_idxs += olengths_idxs[i];
8068835f2295SStefano Zampini     buf_size_vals += olengths_vals[i];
8069835f2295SStefano Zampini     if (nis) buf_size_idxs_is += olengths_idxs_is[i];
8070835f2295SStefano Zampini     if (nvecs) buf_size_vecs += olengths_idxs[i];
8071e7931f94SStefano Zampini   }
80729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
80739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
80749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
80759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
8076e7931f94SStefano Zampini 
8077e7931f94SStefano Zampini   /* get new tags for clean communications */
80789566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
80799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
80809566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
80819566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
8082e7931f94SStefano Zampini 
8083e7931f94SStefano Zampini   /* allocate for requests */
80849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
80859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
80869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
80879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
80889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
80899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
80909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
80919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
8092e7931f94SStefano Zampini 
8093e7931f94SStefano Zampini   /* communications */
8094e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
8095e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
809628143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
80971ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
8098e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8099e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, onodes[i], tag_idxs, comm, &recv_req_idxs[i]));
8100e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, onodes[i], tag_vals, comm, &recv_req_vals[i]));
8101e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8102e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
810328143c3dSStefano Zampini     if (nis) {
8104e91c04dfSPierre Jolivet       PetscCallMPI(MPIU_Irecv(ptr_idxs_is, olengths_idxs_is[i], MPIU_INT, onodes_is[i], tag_idxs_is, comm, &recv_req_idxs_is[i]));
810528143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
810628143c3dSStefano Zampini     }
81071ae86dd6SStefano Zampini     if (nvecs) {
8108e91c04dfSPierre Jolivet       PetscCallMPI(MPIU_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, onodes[i], tag_vecs, comm, &recv_req_vecs[i]));
81091ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
81101ae86dd6SStefano Zampini     }
8111e7931f94SStefano Zampini   }
8112e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
811360b1fa21SPierre Jolivet     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
811460b1fa21SPierre Jolivet     PetscCallMPI(MPIU_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
811560b1fa21SPierre Jolivet     PetscCallMPI(MPIU_Isend(send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
811660b1fa21SPierre Jolivet     if (nis) PetscCallMPI(MPIU_Isend(send_buffer_idxs_is, ilengths_idxs_is[source_dest], MPIU_INT, source_dest, tag_idxs_is, comm, &send_req_idxs_is[i]));
81171ae86dd6SStefano Zampini     if (nvecs) {
81189566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
811960b1fa21SPierre Jolivet       PetscCallMPI(MPIU_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
81201ae86dd6SStefano Zampini     }
8121e7931f94SStefano Zampini   }
81229566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
81239566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
8124e7931f94SStefano Zampini 
8125e7931f94SStefano Zampini   /* assemble new l2g map */
81269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
8127e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
81289d30be91SStefano Zampini   new_local_rows = 0;
8129e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
81309d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8131e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8132e7931f94SStefano Zampini   }
81339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
8134e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
81359d30be91SStefano Zampini   new_local_rows = 0;
8136e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
81379566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
81389d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8139e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8140e7931f94SStefano Zampini   }
81419566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
81429566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
81439566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
8144e7931f94SStefano Zampini 
8145e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
8146e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
8147e7931f94SStefano 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) */
8148e7931f94SStefano Zampini   if (n_recvs) {
814928143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
8150e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
8151e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
8152e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
8153e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
8154e7931f94SStefano Zampini         break;
8155e7931f94SStefano Zampini       }
8156e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
8157e7931f94SStefano Zampini     }
8158e7931f94SStefano Zampini     switch (new_local_type_private) {
815928143c3dSStefano Zampini     case MATDENSE_PRIVATE:
8160e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8161e7931f94SStefano Zampini       bs             = 1;
8162e7931f94SStefano Zampini       break;
8163e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
8164e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8165e7931f94SStefano Zampini       bs             = 1;
8166e7931f94SStefano Zampini       break;
8167d71ae5a4SJacob Faibussowitsch     case MATBAIJ_PRIVATE:
8168d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQBAIJ;
8169d71ae5a4SJacob Faibussowitsch       break;
8170d71ae5a4SJacob Faibussowitsch     case MATSBAIJ_PRIVATE:
8171d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQSBAIJ;
8172d71ae5a4SJacob Faibussowitsch       break;
8173d71ae5a4SJacob Faibussowitsch     default:
8174d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
8175e7931f94SStefano Zampini     }
8176ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
8177ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
817828143c3dSStefano Zampini     bs             = 1;
8179e7931f94SStefano Zampini   }
8180e7931f94SStefano Zampini 
818170cf5478SStefano Zampini   /* create MATIS object if needed */
818257de7509SStefano Zampini   if (!reuse) {
81839566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
81849566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
818570cf5478SStefano Zampini   } else {
818670cf5478SStefano Zampini     /* it also destroys the local matrices */
818757de7509SStefano Zampini     if (*mat_n) {
81889566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
818957de7509SStefano Zampini     } else { /* this is a fake object */
81909566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
819157de7509SStefano Zampini     }
819270cf5478SStefano Zampini   }
81939566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
81949566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
81959d30be91SStefano Zampini 
81969566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
81979d30be91SStefano Zampini 
81989d30be91SStefano Zampini   /* Global to local map of received indices */
81999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
82009566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
82019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
82029d30be91SStefano Zampini 
82039d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
82049d30be91SStefano Zampini   buf_size_idxs = 0;
82059d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
82069d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
82079d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
8208835f2295SStefano Zampini     buf_size_idxs += olengths_idxs[i];
82099d30be91SStefano Zampini   }
82109566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
82119d30be91SStefano Zampini 
82129d30be91SStefano Zampini   /* set preallocation */
82139566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
82149d30be91SStefano Zampini   if (!newisdense) {
82150a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
82169d30be91SStefano Zampini 
82179d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
821848a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
82199d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
82209d30be91SStefano Zampini       PetscInt j;
82219d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
8222ad540459SPierre Jolivet         for (j = 0; j < *(ptr_idxs + 1); j++) new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1);
82239d30be91SStefano Zampini       } else {
82249d30be91SStefano Zampini         /* TODO */
82259d30be91SStefano Zampini       }
82269d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
82279d30be91SStefano Zampini     }
82289d30be91SStefano Zampini     if (new_local_nnz) {
82299d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
82309566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
82319d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
82329566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
82339d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
82349566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
82359d30be91SStefano Zampini     } else {
82369566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
82379d30be91SStefano Zampini     }
82389566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
82399d30be91SStefano Zampini   } else {
82409566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
82419d30be91SStefano Zampini   }
8242e7931f94SStefano Zampini 
8243e7931f94SStefano Zampini   /* set values */
8244e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
82459d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
8246e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8247e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
82489566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
82499566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
82509566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
82519566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
82529566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
825328143c3dSStefano Zampini     } else {
825428143c3dSStefano Zampini       /* TODO */
8255e7931f94SStefano Zampini     }
8256e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8257e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
8258e7931f94SStefano Zampini   }
82599566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
82609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
82619566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
82629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
82639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
82649566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
8265e7931f94SStefano Zampini 
8266dfd14d43SStefano Zampini #if 0
826728143c3dSStefano Zampini   if (!restrict_comm) { /* check */
8268e7931f94SStefano Zampini     Vec       lvec,rvec;
8269e7931f94SStefano Zampini     PetscReal infty_error;
8270e7931f94SStefano Zampini 
82719566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
82729566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
82739566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
82749566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
82759566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
82769566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
82779566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
82789566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
82799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
8280e7931f94SStefano Zampini   }
828128143c3dSStefano Zampini #endif
8282e7931f94SStefano Zampini 
828328143c3dSStefano Zampini   /* assemble new additional is (if any) */
828428143c3dSStefano Zampini   if (nis) {
828528143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
828628143c3dSStefano Zampini 
82879566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
82889566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
828928143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
829028143c3dSStefano Zampini     psum     = 0;
829128143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
829228143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
829328143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
829428143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
829528143c3dSStefano Zampini         psum += plen;
829628143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
829728143c3dSStefano Zampini       }
829828143c3dSStefano Zampini     }
82999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
83009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
83018e3a54c0SPierre Jolivet     for (i = 1; i < nis; i++) temp_idxs[i] = PetscSafePointerPlusOffset(temp_idxs[i - 1], count_is[i - 1]);
83029566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
830328143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
830428143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
830528143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
830628143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
83079566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
830828143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
830928143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
831028143c3dSStefano Zampini       }
831128143c3dSStefano Zampini     }
831228143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
83139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
83149566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
83159566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
831628143c3dSStefano Zampini     }
83179566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
83189566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
83199566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
832028143c3dSStefano Zampini   }
8321e7931f94SStefano Zampini   /* free workspace */
83229566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
83239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
83249566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
83259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
8326e7931f94SStefano Zampini   if (isdense) {
83279566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
83289566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
83299566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
8330e7931f94SStefano Zampini   } else {
83319566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
8332e7931f94SStefano Zampini   }
833328143c3dSStefano Zampini   if (nis) {
83349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
83359566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
833628143c3dSStefano Zampini   }
83371ae86dd6SStefano Zampini 
83381ae86dd6SStefano Zampini   if (nvecs) {
83399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
83409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
83419566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
83429566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
83439566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
83449566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
83459566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
83461ae86dd6SStefano Zampini     /* set values */
83471ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
83481ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
83499566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
83501ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
83511ae86dd6SStefano Zampini       PetscInt j;
8352ad540459SPierre Jolivet       for (j = 0; j < *(ptr_idxs + 1); j++) send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j);
83531ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
83541ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
83551ae86dd6SStefano Zampini     }
83569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
83579566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
83589566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
83591ae86dd6SStefano Zampini   }
83601ae86dd6SStefano Zampini 
83619566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
83629566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
83639566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
83649566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
83659566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
83669566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
83679566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
83689566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
83699566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
83709566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
83719566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
83729566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
83739566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
83749566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
83759566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
837628143c3dSStefano Zampini   if (nis) {
83779566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
83789566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
83799566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
838028143c3dSStefano Zampini   }
83819566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
83826aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
83839566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
838448a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
83851ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
83869566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
83871ae86dd6SStefano Zampini     }
838853a05cb3SStefano Zampini     *mat_n = NULL;
838928143c3dSStefano Zampini   }
83903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8391e7931f94SStefano Zampini }
8392a57a6d2fSStefano Zampini 
839312edc857SStefano Zampini /* temporary hack into ksp private data structure */
8394af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
839512edc857SStefano Zampini 
83969de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, Mat coarse_submat)
8397d71ae5a4SJacob Faibussowitsch {
8398c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
8399c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
84009de2952eSStefano Zampini   PCBDDCGraph            graph  = pcbddc->mat_graph;
84019de2952eSStefano Zampini   Mat                    coarse_mat, coarse_mat_is;
84021ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
84031e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
84049881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
840520a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
84064f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
84076e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
840830368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
84099de2952eSStefano Zampini   PetscInt               coarse_eqs_per_proc, coarsening_ratio;
8410f9eb5b7dSStefano Zampini   PC                     pc_temp;
8411c8587f34SStefano Zampini   PCType                 coarse_pc_type;
8412c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
8413f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
84149de2952eSStefano Zampini   PetscBool              coarse_reuse, multi_element = graph->multi_element;
84151e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
841668457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
841722bc73bbSStefano Zampini   PetscScalar           *array;
841857de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
841957de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
8420e569e4e1SStefano Zampini   PetscMPIInt            size;
8421fdc09c96SStefano Zampini 
8422c8587f34SStefano Zampini   PetscFunctionBegin;
84239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8424c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
842568457ee5SStefano 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 */
8426fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
84275a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
84287de4f681Sstefano_zampini 
84297de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
8430fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
84319566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
84329566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
8433f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
8434fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
843551bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
843651bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
84379566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
8438fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
8439fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
8440fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
8441f4ddd8eeSStefano Zampini       }
8442fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
8443fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
8444f4ddd8eeSStefano Zampini     }
844570cf5478SStefano Zampini     /* reset any subassembling information */
844648a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
84476e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
8448fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
8449f4ddd8eeSStefano Zampini   }
845057de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
84519566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
84529566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
845357de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
845418a45a71SStefano Zampini   } else {
845557de7509SStefano Zampini     coarse_mat       = NULL;
845657de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
84576e683305SStefano Zampini   }
8458e7931f94SStefano Zampini 
8459abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
84609566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
84619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
8462abbbba34SStefano Zampini 
8463abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
84649de2952eSStefano Zampini   PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &t_coarse_mat_is));
84659de2952eSStefano Zampini   PetscCall(MatSetType(t_coarse_mat_is, MATIS));
84669de2952eSStefano Zampini   PetscCall(MatSetSizes(t_coarse_mat_is, PETSC_DECIDE, PETSC_DECIDE, pcbddc->coarse_size, pcbddc->coarse_size));
84679de2952eSStefano Zampini   PetscCall(MatISSetAllowRepeated(t_coarse_mat_is, PETSC_TRUE));
84689de2952eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(t_coarse_mat_is, coarse_islg, coarse_islg));
84699de2952eSStefano Zampini   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat));
84709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
84719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
84729de2952eSStefano Zampini   PetscCall(MatViewFromOptions(t_coarse_mat_is, (PetscObject)pc, "-pc_bddc_coarse_mat_is_view"));
8473abbbba34SStefano Zampini 
847457de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
8475f4f49eeaSPierre Jolivet   im_active = !!pcis->n;
8476462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
847757de7509SStefano Zampini 
847814f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
847928d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
848057de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
84819566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
848257de7509SStefano Zampini   coarse_mat_is        = NULL;
848357de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
848457de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
8485e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
84869de2952eSStefano Zampini   if (coarse_eqs_per_proc < 0 || size == 1) coarse_eqs_per_proc = PetscMax(pcbddc->coarse_size, 1);
848757de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
8488e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
84899de2952eSStefano Zampini   coarsening_ratio = multi_element ? 1 : pcbddc->coarsening_ratio;
849057de7509SStefano Zampini   if (multilevel_requested) {
84919de2952eSStefano Zampini     ncoarse    = active_procs / coarsening_ratio;
849257de7509SStefano Zampini     restr      = PETSC_FALSE;
849357de7509SStefano Zampini     full_restr = PETSC_FALSE;
849457de7509SStefano Zampini   } else {
8495e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
849657de7509SStefano Zampini     restr      = PETSC_TRUE;
849757de7509SStefano Zampini     full_restr = PETSC_TRUE;
849857de7509SStefano Zampini   }
8499e569e4e1SStefano Zampini   if (!pcbddc->coarse_size || size == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
850057de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
850157de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
85029de2952eSStefano Zampini     if (coarsening_ratio > 1) {
8503bb360cb4SStefano Zampini       if (multilevel_requested) {
85049566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8505bb360cb4SStefano Zampini       } else {
85069566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8507bb360cb4SStefano Zampini       }
8508a198735bSStefano Zampini     } else {
85097de4f681Sstefano_zampini       PetscMPIInt rank;
851028d58a37SPierre Jolivet 
85119566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
8512835f2295SStefano Zampini       have_void = (active_procs == size) ? PETSC_FALSE : PETSC_TRUE;
85139566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
8514a198735bSStefano Zampini     }
851557de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
851657de7509SStefano Zampini     PetscInt psum;
851757de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
851857de7509SStefano Zampini     else psum = 0;
8519462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
8520075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
852157de7509SStefano Zampini   }
852257de7509SStefano Zampini   /* determine if we can go multilevel */
852357de7509SStefano Zampini   if (multilevel_requested) {
852457de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
852557de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
852657de7509SStefano Zampini   }
852757de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
852857de7509SStefano Zampini 
8529e4d548c7SStefano Zampini   /* dump subassembling pattern */
853048a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
85316e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
85321e0482f5SStefano Zampini   nedcfield = -1;
85334f819b78SStefano Zampini   corners   = NULL;
85348966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
85356e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
85366e683305SStefano Zampini     const PetscInt        *idxs;
85376e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
85386e683305SStefano Zampini 
85396e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
85409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
85416e683305SStefano Zampini     /* allocate space for temporary storage */
85429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
85439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
85446e683305SStefano Zampini     /* allocate for IS array */
85456e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
85461e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
85471e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
85481e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
85491e0482f5SStefano Zampini       } else {
85501e0482f5SStefano Zampini         nedcfield = 0;
855163a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
85521e0482f5SStefano Zampini         nisdofs = 1;
85531e0482f5SStefano Zampini       }
85541e0482f5SStefano Zampini     }
85556e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
855627b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
855730368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
85589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
85596e683305SStefano Zampini     /* dofs splitting */
85606e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
85619566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
85621e0482f5SStefano Zampini       if (nedcfield != i) {
85639566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
85649566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
85659566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
85669566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
85671e0482f5SStefano Zampini       } else {
85689566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
85699566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
85709566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
857163a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
85729566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
85731e0482f5SStefano Zampini       }
85749566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85759566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
85769566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
85776e683305SStefano Zampini     }
85786e683305SStefano Zampini     /* neumann boundaries */
85796e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
85809566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
85819566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
85829566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
85839566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
85849566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
85859566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85869566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
85879566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
85886e683305SStefano Zampini     }
85894f819b78SStefano Zampini     /* coordinates */
85904f819b78SStefano Zampini     if (pcbddc->corner_selected) {
85919566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
85929566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
85939566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
85949566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
859563a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
85969566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
85979566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
85989566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85999566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
86004f819b78SStefano Zampini     }
86019566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
86029566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
86039566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
86046e683305SStefano Zampini   } else {
86056e683305SStefano Zampini     nis     = 0;
86066e683305SStefano Zampini     nisdofs = 0;
86076e683305SStefano Zampini     nisneu  = 0;
860830368db7SStefano Zampini     nisvert = 0;
86096e683305SStefano Zampini     isarray = NULL;
86106e683305SStefano Zampini   }
86116e683305SStefano Zampini   /* destroy no longer needed map */
86129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
86136e683305SStefano Zampini 
861457de7509SStefano Zampini   /* subassemble */
861557de7509SStefano Zampini   if (multilevel_allowed) {
86161ae86dd6SStefano Zampini     Vec       vp[1];
86171ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
86189de2952eSStefano Zampini     PetscBool reuse;
86191ae86dd6SStefano Zampini 
86201ae86dd6SStefano Zampini     vp[0] = NULL;
86219de2952eSStefano Zampini     /* XXX HDIV also */
86221ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
86239566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
86249566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
86259566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
86261ae86dd6SStefano Zampini       nvecs = 1;
86271ae86dd6SStefano Zampini 
86281ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
8629a198735bSStefano Zampini         Mat      B, loc_divudotp;
86301ae86dd6SStefano Zampini         Vec      v, p;
86311ae86dd6SStefano Zampini         IS       dummy;
86321ae86dd6SStefano Zampini         PetscInt np;
86331ae86dd6SStefano Zampini 
86349566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
86359566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
86369566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
86379566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
86389566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
86399566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
86409566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
86419566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
86429566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
86439566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
86449566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
86459566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
86469566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
86479566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
86489566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
86499566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
865074e2c79eSStefano Zampini       }
86511ae86dd6SStefano Zampini     }
86529de2952eSStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
86539de2952eSStefano Zampini     else reuse = PETSC_FALSE;
86549de2952eSStefano Zampini     if (multi_element) {
86559de2952eSStefano Zampini       /* XXX divudotp */
86569de2952eSStefano Zampini       PetscCall(MatISSetAllowRepeated(t_coarse_mat_is, PETSC_FALSE));
86579de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
86589de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
86599de2952eSStefano Zampini     } else {
8660462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &reuse, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
86619de2952eSStefano Zampini       if (reuse) {
86629566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
866374e2c79eSStefano Zampini       } else {
86649566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
86651ae86dd6SStefano Zampini       }
86661ae86dd6SStefano Zampini       if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
86671683a169SBarry Smith         PetscScalar       *arraym;
86681683a169SBarry Smith         const PetscScalar *arrayv;
86691ae86dd6SStefano Zampini         PetscInt           nl;
86709566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(vp[0], &nl));
86719566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
86729566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
86739566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vp[0], &arrayv));
86749566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(arraym, arrayv, nl));
86759566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
86769566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
86779566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&vp[0]));
8678a198735bSStefano Zampini       } else {
86799566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
86801ae86dd6SStefano Zampini       }
86819de2952eSStefano Zampini     }
86821ae86dd6SStefano Zampini   } else {
86839de2952eSStefano Zampini     if (ncoarse != size) PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
86849de2952eSStefano Zampini     else {
86859de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
86869de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
86879de2952eSStefano Zampini     }
86886e683305SStefano Zampini   }
868957de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
869057de7509SStefano Zampini     if (!multilevel_allowed) {
86919566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
86926e683305SStefano Zampini     } else {
869357de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
869457de7509SStefano Zampini       if (coarse_mat_is) {
869528b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
86969566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
869757de7509SStefano Zampini         coarse_mat = coarse_mat_is;
869857de7509SStefano Zampini       }
8699779c1cceSStefano Zampini     }
8700779c1cceSStefano Zampini   }
87019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
87029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
87036e683305SStefano Zampini 
87046e683305SStefano Zampini   /* create local to global scatters for coarse problem */
870568457ee5SStefano Zampini   if (compute_vecs) {
87066e683305SStefano Zampini     PetscInt lrows;
87079566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
870857de7509SStefano Zampini     if (coarse_mat) {
87099566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
87106e683305SStefano Zampini     } else {
87116e683305SStefano Zampini       lrows = 0;
87126e683305SStefano Zampini     }
87139566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
87149566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
87159566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
87169566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
87179566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
87186e683305SStefano Zampini   }
87199566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8720c8587f34SStefano Zampini 
8721f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8722f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8723f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8724f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8725f9eb5b7dSStefano Zampini   } else {
8726f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8727f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8728c8587f34SStefano Zampini   }
8729c8587f34SStefano Zampini 
87306e683305SStefano Zampini   /* print some info if requested */
87316e683305SStefano Zampini   if (pcbddc->dbg_flag) {
87326e683305SStefano Zampini     if (!multilevel_allowed) {
87339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
87346e683305SStefano Zampini       if (multilevel_requested) {
87359de2952eSStefano Zampini         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, coarsening_ratio));
87366e683305SStefano Zampini       } else if (pcbddc->max_levels) {
873763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
87386e683305SStefano Zampini       }
87399566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
87406e683305SStefano Zampini     }
87416e683305SStefano Zampini   }
87426e683305SStefano Zampini 
87431e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
87441e0482f5SStefano Zampini   coarseG = NULL;
87451e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
87461e0482f5SStefano Zampini     MPI_Comm ccomm;
87471e0482f5SStefano Zampini     if (coarse_mat) {
87481e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
87491e0482f5SStefano Zampini     } else {
87501e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
87511e0482f5SStefano Zampini     }
87529566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
87531e0482f5SStefano Zampini   }
87541e0482f5SStefano Zampini 
8755f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
875657de7509SStefano Zampini   if (coarse_mat) {
875728d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
87586a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8759b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
87607274672aSStefano Zampini 
87616e683305SStefano Zampini     if (pcbddc->dbg_flag) {
876257de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
87639566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
87646e683305SStefano Zampini     }
8765f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8766312be037SStefano Zampini       char   prefix[256], str_level[16];
8767e604994aSStefano Zampini       size_t len;
87681e0482f5SStefano Zampini 
87699566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
87703821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->coarse_ksp, pc->kspnestlevel));
87719566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
87729566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
8773fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, 1));
87749566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
87759566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
87769566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
87779566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
87781e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
87799566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8780e604994aSStefano Zampini       /* prefix */
8781c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(prefix, "", sizeof(prefix)));
8782c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(str_level, "", sizeof(str_level)));
8783e604994aSStefano Zampini       if (!pcbddc->current_level) {
87849566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
87859566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8786c8587f34SStefano Zampini       } else {
87879566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8788312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8789312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8790a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
87919566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
8792835f2295SStefano Zampini         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%" PetscInt_FMT "_", pcbddc->current_level));
87939566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8794e604994aSStefano Zampini       }
87959566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
87963e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
87979566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
87989566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
87999566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8800f9eb5b7dSStefano Zampini       /* allow user customization */
88019566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8802e569e4e1SStefano Zampini       /* get some info after set from options */
88039566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
880428d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
880528d58a37SPierre Jolivet       force = PETSC_FALSE;
88069566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
88079566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
88089566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
880928d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8810e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
88119566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
88129566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
88139566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
88149566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
88154f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8816d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8817dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8818dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8819d0609cedSBarry Smith           PetscOptionsEnd();
88204f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
88214f819b78SStefano Zampini         }
8822e569e4e1SStefano Zampini       }
88233e3c6dadSStefano Zampini     }
88243e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
88259566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
88263e3c6dadSStefano Zampini     if (nisdofs) {
88279566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
882848a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
88293e3c6dadSStefano Zampini     }
88303e3c6dadSStefano Zampini     if (nisneu) {
88319566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
88329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8833312be037SStefano Zampini     }
883430368db7SStefano Zampini     if (nisvert) {
88359566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
88369566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
883730368db7SStefano Zampini     }
88381baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8839f9eb5b7dSStefano Zampini 
8840f9eb5b7dSStefano Zampini     /* get some info after set from options */
88419566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
88424f819b78SStefano Zampini 
8843b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
884448a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
884528d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
884628d58a37SPierre Jolivet     force = PETSC_FALSE;
88479566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
88489566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
884948a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
88509566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
88514f3a063dSStefano Zampini     if (isredundant) {
88524f3a063dSStefano Zampini       KSP inner_ksp;
88534f3a063dSStefano Zampini       PC  inner_pc;
88549326c5c6Sstefano_zampini 
88559566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
88569566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
88574f3a063dSStefano Zampini     }
8858f9eb5b7dSStefano Zampini 
885957de7509SStefano Zampini     /* parameters which miss an API */
88609566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
886157de7509SStefano Zampini     if (isbddc) {
8862720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
88637274672aSStefano Zampini 
8864720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
886557de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8866e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
886727b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
886827b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
8869a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
8870a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
8871a198735bSStefano Zampini         IS                     row, col;
8872a198735bSStefano Zampini         const PetscInt        *gidxs;
8873a198735bSStefano Zampini         PetscInt               n, st, M, N;
8874a198735bSStefano Zampini 
88759566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
88769566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
8877a198735bSStefano Zampini         st = st - n;
88789566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
88799566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
88809566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
88819566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
88829566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
88839566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
88849566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
88859566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
88869566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
88879566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
88889566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
88899566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
88909566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
88919566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
88929566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
88939566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
88949566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
88959566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
88969566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
88979566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
88989566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
88999566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
8900720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8901bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8902720d30f9SStefano Zampini       }
8903d4d8cf7bSStefano Zampini     }
89049881197aSStefano Zampini 
89053301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
89069566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
8907b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
8908b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
8909b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
8910b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
8911b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
8912b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
8913b94d7dedSBarry Smith 
891448a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
89156e683305SStefano Zampini     /* set operators */
89169566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
89179566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
89189566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
89191baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
89206e683305SStefano Zampini   }
89219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
89229566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
8923b1ecc7b1SStefano Zampini #if 0
8924b9b85e73SStefano Zampini   {
8925b9b85e73SStefano Zampini     PetscViewer viewer;
8926b9b85e73SStefano Zampini     char filename[256];
8927a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "coarse_mat_level%d.m",pcbddc->current_level));
89289566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
89299566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
89309566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
89319566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
89329566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
8933b9b85e73SStefano Zampini   }
8934b9b85e73SStefano Zampini #endif
8935f9eb5b7dSStefano Zampini 
89364f819b78SStefano Zampini   if (corners) {
89374f819b78SStefano Zampini     Vec             gv;
89384f819b78SStefano Zampini     IS              is;
89394f819b78SStefano Zampini     const PetscInt *idxs;
89404f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
89414f819b78SStefano Zampini     PetscScalar    *coords;
89424f819b78SStefano Zampini 
894328b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
89449566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
89459566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
89469566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
89479566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
89489566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
89499566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
89509566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
89519566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
89524f819b78SStefano Zampini 
89539566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
89549566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
89559566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
89569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
89574f819b78SStefano Zampini     for (i = 0; i < n; i++) {
8958ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d];
89594f819b78SStefano Zampini     }
89609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
89619566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
89624f819b78SStefano Zampini 
89639566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
89649566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
89659566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
89669566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
89679566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
89689566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
89699566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
89709566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
89714f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
89724f819b78SStefano Zampini       PC        coarse_pc;
89734f819b78SStefano Zampini       PetscBool isbddc;
89744f819b78SStefano Zampini 
89759566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
89769566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
89774f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
89784f819b78SStefano Zampini         PetscReal *realcoords;
89794f819b78SStefano Zampini 
89809566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
89814f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
89829566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
89834f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
89844f819b78SStefano Zampini #else
89854f819b78SStefano Zampini         realcoords = coords;
89864f819b78SStefano Zampini #endif
89879566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
89884f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
89899566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
89904f819b78SStefano Zampini #endif
89914f819b78SStefano Zampini       }
89924f819b78SStefano Zampini     }
89939566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
89949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
89954f819b78SStefano Zampini   }
89969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
89974f819b78SStefano Zampini 
899898a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
899998a51de6SStefano Zampini     Vec crhs, csol;
900004708bb6SStefano Zampini 
90019566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
90029566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
9003f4f49eeaSPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &pcbddc->coarse_ksp->vec_sol, NULL));
9004f4f49eeaSPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &pcbddc->coarse_ksp->vec_rhs));
9005b0f5fe93SStefano Zampini   }
90069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
9007b0f5fe93SStefano Zampini 
9008b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
9009b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
90109566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
901148a46eb9SPierre 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));
90129566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
90139566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
90149566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
90159566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
9016b0f5fe93SStefano Zampini     if (coarse_mat) {
9017b0f5fe93SStefano Zampini       Vec          nullv;
9018b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
9019b0f5fe93SStefano Zampini       PetscInt     nl;
9020b0f5fe93SStefano Zampini 
90219566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
90229566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
90239566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
90249566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
90259566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
90269566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
90279566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
90289566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
90299566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
90309566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
9031b0f5fe93SStefano Zampini     }
9032b0f5fe93SStefano Zampini   }
90339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
9034b0f5fe93SStefano Zampini 
90359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
9036b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
9037b0f5fe93SStefano Zampini     PetscBool ispreonly;
9038b0f5fe93SStefano Zampini 
9039b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
9040b0f5fe93SStefano Zampini       PetscBool isnull;
90417c625d9fSStefano Zampini 
90429566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
90431baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
9044bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
9045b0f5fe93SStefano Zampini     }
9046b0f5fe93SStefano Zampini     /* setup coarse ksp */
90479566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
9048cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
90499566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
90506e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
9051c8587f34SStefano Zampini       KSP         check_ksp;
90522b510759SStefano Zampini       KSPType     check_ksp_type;
9053c8587f34SStefano Zampini       PC          check_pc;
90546e683305SStefano Zampini       Vec         check_vec, coarse_vec;
90556a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
90562b510759SStefano Zampini       PetscInt    its;
90576e683305SStefano Zampini       PetscBool   compute_eigs;
90586e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
90596e683305SStefano Zampini       PetscInt    neigs;
90608e185a42SStefano Zampini       const char *prefix;
9061c8587f34SStefano Zampini 
90622b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
90639566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
90643821be0aSBarry Smith       PetscCall(KSPSetNestLevel(check_ksp, pc->kspnestlevel));
90659566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
90669566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
90679566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
9068fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_CURRENT, pcbddc->coarse_size));
9069e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
90709566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
90719566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
90722b510759SStefano Zampini       if (ispreonly) {
90732b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
90746e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
90752b510759SStefano Zampini       } else {
9076cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
90776e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
9078c8587f34SStefano Zampini       }
90799566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
90809566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
90819566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
90829566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
90839566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
90849566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
90859566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
90869566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
90879566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
90889566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
90899566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
9090c8587f34SStefano Zampini       /* create random vec */
90919566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
90929566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
90939566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
9094c8587f34SStefano Zampini       /* solve coarse problem */
90959566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
90969566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
9097cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
90986e683305SStefano Zampini       if (compute_eigs) {
90999566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
91009566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
91019566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
91021ae86dd6SStefano Zampini         if (neigs) {
91036e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
91046e683305SStefano Zampini           lambda_min = eigs_r[0];
91056e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
91062701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
91079566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
91089566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
9109cbcc2c2aSStefano Zampini             }
9110c8587f34SStefano Zampini           }
9111c8587f34SStefano Zampini         }
91121ae86dd6SStefano Zampini       }
9113cbcc2c2aSStefano Zampini 
9114c8587f34SStefano Zampini       /* check coarse problem residual error */
91156e683305SStefano Zampini       if (pcbddc->dbg_flag) {
91166e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
91179566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
91189566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
91199566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
91209566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
91219566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
91229566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
9123f4f49eeaSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pcbddc->coarse_ksp, dbg_viewer));
912457508eceSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)check_pc, dbg_viewer));
912563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
912663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
912748a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
91286e683305SStefano Zampini         if (compute_eigs) {
91296e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
9130b03ebc13SStefano Zampini           KSPConvergedReason reason;
91319566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
91329566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
91339566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
91349566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
913563a3b9bcSJacob 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));
913648a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
91376e683305SStefano Zampini         }
91389566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
91399566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
91406e683305SStefano Zampini       }
91419566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
91429566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
91439566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
91446e683305SStefano Zampini       if (compute_eigs) {
91459566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
91469566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
9147c8587f34SStefano Zampini       }
91486e683305SStefano Zampini     }
91496e683305SStefano Zampini   }
91509566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
9151cbcc2c2aSStefano Zampini   /* print additional info */
9152cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
91536e683305SStefano Zampini     /* waits until all processes reaches this point */
91549566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
915563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
91569566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9157cbcc2c2aSStefano Zampini   }
9158cbcc2c2aSStefano Zampini 
91592b510759SStefano Zampini   /* free memory */
91609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
91619566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
91623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9163c8587f34SStefano Zampini }
9164674ae819SStefano Zampini 
9165d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n)
9166d71ae5a4SJacob Faibussowitsch {
9167f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
9168f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
9169dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
9170dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
917173be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
9172dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
9173f34684f1SStefano Zampini 
9174f34684f1SStefano Zampini   PetscFunctionBegin;
9175f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
917608401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
9177f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
91789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
91799566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9180f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
91819566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
91829566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
91839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
91849566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
918563a3b9bcSJacob 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);
91869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
91879566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
91889566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
91899566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
91909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9191f34684f1SStefano Zampini 
9192f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
91939566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
91949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
91959de2952eSStefano Zampini     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT "\n", coarse_size));
91969566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9197f34684f1SStefano Zampini   }
91986080607fSStefano Zampini 
9199f34684f1SStefano Zampini   /* get back data */
9200f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
9201f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
92023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9203674ae819SStefano Zampini }
9204674ae819SStefano Zampini 
9205d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis)
9206d71ae5a4SJacob Faibussowitsch {
9207e456f2a8SStefano Zampini   IS           localis_t;
9208a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
9209e456f2a8SStefano Zampini   PetscScalar *vals;
9210e456f2a8SStefano Zampini 
9211e456f2a8SStefano Zampini   PetscFunctionBegin;
9212a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
92139566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
92149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
9215e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
92169566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
92179566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
92189566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
92191035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
92209566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
92219566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
92221035eff8SStefano Zampini   }
92239566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
92249566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
92259566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
92269566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
9227a7dc3881SStefano Zampini   /* now compute set in local ordering */
92289566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
92299566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
92309566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
92319566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
9232a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9233ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) lsize++;
9234e456f2a8SStefano Zampini   }
92359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
9236a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9237ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) idxs[lsize++] = i;
9238e456f2a8SStefano Zampini   }
92399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
92409566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
9241e456f2a8SStefano Zampini   *localis = localis_t;
92423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9243e456f2a8SStefano Zampini }
9244906d46d4SStefano Zampini 
9245d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr)
9246d71ae5a4SJacob Faibussowitsch {
92477c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
92487c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
92497c625d9fSStefano Zampini   PC_IS   *pcisf;
92507c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
92517c625d9fSStefano Zampini   PC       pcf;
92527c625d9fSStefano Zampini 
92537c625d9fSStefano Zampini   PetscFunctionBegin;
92547c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
92557c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
92567c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
92577c625d9fSStefano Zampini 
92587c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
925932fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
926032fe681dSStefano Zampini 
92617c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
92627c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
92637c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
92647c625d9fSStefano Zampini   pcisf->n          = pcis->n;
92657c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
92667c625d9fSStefano Zampini 
92677c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
926832fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
92697c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
927032fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
927132fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
927232fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
927332fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
927432fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
927532fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
92767c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
927732fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
927832fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
927932fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
92807c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
928132fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
928232fe681dSStefano Zampini 
928332fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
92847c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
92857c625d9fSStefano Zampini 
92867c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
92877c625d9fSStefano 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));
92887c625d9fSStefano 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));
92897c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
92907c625d9fSStefano Zampini 
929132fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
92927c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
929332fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
929432fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
929532fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
929632fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
92977c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
92983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92997c625d9fSStefano Zampini }
93007c625d9fSStefano Zampini 
9301d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
9302d71ae5a4SJacob Faibussowitsch {
9303a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
9304b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
9305b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
9306a64f4aa4SStefano Zampini   Mat             S_j;
9307b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
9308b96c3477SStefano Zampini   PetscBool       free_used_adj;
9309b96c3477SStefano Zampini 
9310b96c3477SStefano Zampini   PetscFunctionBegin;
93119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
9312b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
9313b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
931408122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
9315b96c3477SStefano Zampini     used_xadj   = NULL;
9316b96c3477SStefano Zampini     used_adjncy = NULL;
9317b96c3477SStefano Zampini   } else {
931808122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
931908122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
932008122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
932108122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
9322b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
9323b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
9324b96c3477SStefano Zampini     } else {
93252fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
9326b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
9327b96c3477SStefano Zampini       PetscInt        nvtxs;
9328b96c3477SStefano Zampini 
93299566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
93302fffb893SStefano Zampini       if (flg_row) {
93319566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
93329566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
93339566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
9334b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
93352fffb893SStefano Zampini       } else {
93362fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
93372fffb893SStefano Zampini         used_xadj                 = NULL;
93382fffb893SStefano Zampini         used_adjncy               = NULL;
93392fffb893SStefano Zampini       }
93409566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
9341b96c3477SStefano Zampini     }
9342b96c3477SStefano Zampini   }
9343d5574798SStefano Zampini 
9344d5574798SStefano Zampini   /* setup sub_schurs data */
93459566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
9346df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
9347df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
93489566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
93499566063dSJacob 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));
9350a64f4aa4SStefano Zampini   } else {
935172b8c272SStefano Zampini     Mat       change        = NULL;
93529d54b7f4SStefano Zampini     Vec       scaling       = NULL;
9353111315fdSstefano_zampini     IS        change_primal = NULL, iP;
9354111315fdSstefano_zampini     PetscInt  benign_n;
9355111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
93567ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
9357111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
9358a3df083aSStefano Zampini 
93595feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
93605feab87aSStefano Zampini       PetscInt n_vertices;
93615feab87aSStefano Zampini 
93629566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
93632034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
93645feab87aSStefano Zampini     }
9365a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
9366a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
9367ca92afb2SStefano Zampini     } else {
9368a3df083aSStefano Zampini       benign_n = 0;
9369ca92afb2SStefano Zampini     }
9370b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
9371b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
9372b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
937372b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
937422db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
9375462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
937622db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
9377b7ab4a40SStefano Zampini     }
93787c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
9379b7ab4a40SStefano Zampini     if (need_change) {
938028b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
938132fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
938288c03ad3SStefano Zampini     }
93839d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
9384111315fdSstefano_zampini 
93859566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
9386111315fdSstefano_zampini     if (iP) {
9387d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
93889566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
9389d0609cedSBarry Smith       PetscOptionsEnd();
9390111315fdSstefano_zampini     }
9391111315fdSstefano_zampini     if (discrete_harmonic) {
9392111315fdSstefano_zampini       Mat A;
93939566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
93949566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
93959566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
93969371c9d4SSatish 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,
93979371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
93989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
9399111315fdSstefano_zampini     } else {
94009371c9d4SSatish 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,
94019371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
9402111315fdSstefano_zampini     }
94039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
94049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
9405ca92afb2SStefano Zampini   }
94069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
9407b96c3477SStefano Zampini 
9408b96c3477SStefano Zampini   /* free adjacency */
94091baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
94109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
94113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9412b96c3477SStefano Zampini }
9413b96c3477SStefano Zampini 
9414d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCInitSubSchurs(PC pc)
9415d71ae5a4SJacob Faibussowitsch {
9416b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
9417b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
9418b96c3477SStefano Zampini   PCBDDCGraph graph;
9419b96c3477SStefano Zampini 
9420b96c3477SStefano Zampini   PetscFunctionBegin;
9421b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
942208122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
94233301b35fSStefano Zampini     IS       verticesIS, verticescomm;
94243301b35fSStefano Zampini     PetscInt vsize, *idxs;
9425b96c3477SStefano Zampini 
94269566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
94279566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
94289566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
94299566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
94309566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
94319566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
94329566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
94339566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
94349566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
94359566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
94369566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
9437b96c3477SStefano Zampini   } else {
9438b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
9439b96c3477SStefano Zampini   }
9440e4d548c7SStefano Zampini   /* print some info */
94415c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
9442e4d548c7SStefano Zampini     IS       vertices;
9443e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
94449566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
94459566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
94469566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
94479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
94489566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
944963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
945063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
945163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
94529566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
94539566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
94549566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
9455e4d548c7SStefano Zampini   }
9456b96c3477SStefano Zampini 
9457b96c3477SStefano Zampini   /* sub_schurs init */
945848a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
945932fe681dSStefano 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));
9460a64f4aa4SStefano Zampini 
9461b96c3477SStefano Zampini   /* free graph struct */
946248a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
94633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9464b96c3477SStefano Zampini }
9465fa34dd3eSStefano Zampini 
94669de2952eSStefano Zampini static PetscErrorCode PCBDDCViewGlobalIS(PC pc, IS is, PetscViewer viewer)
94679de2952eSStefano Zampini {
94689de2952eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
94699de2952eSStefano Zampini   PetscInt        n     = pc->pmat->rmap->n, ln, ni, st;
94709de2952eSStefano Zampini   const PetscInt *idxs;
94719de2952eSStefano Zampini   IS              gis;
94729de2952eSStefano Zampini 
94739de2952eSStefano Zampini   PetscFunctionBegin;
94749de2952eSStefano Zampini   if (!is) PetscFunctionReturn(PETSC_SUCCESS);
94759de2952eSStefano Zampini   PetscCall(MatGetOwnershipRange(pc->pmat, &st, NULL));
94769de2952eSStefano Zampini   PetscCall(MatGetLocalSize(matis->A, NULL, &ln));
94779de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_leafdata, ln));
94789de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_rootdata, n));
94799de2952eSStefano Zampini   PetscCall(ISGetLocalSize(is, &ni));
94809de2952eSStefano Zampini   PetscCall(ISGetIndices(is, &idxs));
94819de2952eSStefano Zampini   for (PetscInt i = 0; i < ni; i++) {
94829de2952eSStefano Zampini     if (idxs[i] < 0 || idxs[i] >= ln) continue;
94839de2952eSStefano Zampini     matis->sf_leafdata[idxs[i]] = 1;
94849de2952eSStefano Zampini   }
94859de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is, &idxs));
94869de2952eSStefano Zampini   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
94879de2952eSStefano Zampini   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
94889de2952eSStefano Zampini   ln = 0;
94899de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
94909de2952eSStefano Zampini     if (matis->sf_rootdata[i]) matis->sf_rootdata[ln++] = i + st;
94919de2952eSStefano Zampini   }
94929de2952eSStefano Zampini   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), ln, matis->sf_rootdata, PETSC_USE_POINTER, &gis));
94939de2952eSStefano Zampini   PetscCall(ISView(gis, viewer));
94949de2952eSStefano Zampini   PetscCall(ISDestroy(&gis));
94959de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
94969de2952eSStefano Zampini }
94979de2952eSStefano Zampini 
94989de2952eSStefano Zampini PetscErrorCode PCBDDCLoadOrViewCustomization(PC pc, PetscBool load, const char *outfile)
94999de2952eSStefano Zampini {
95009de2952eSStefano Zampini   PetscInt    header[11];
95019de2952eSStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
95029de2952eSStefano Zampini   PetscViewer viewer;
95039de2952eSStefano Zampini   MPI_Comm    comm = PetscObjectComm((PetscObject)pc);
95049de2952eSStefano Zampini 
95059de2952eSStefano Zampini   PetscFunctionBegin;
95069de2952eSStefano Zampini   PetscCall(PetscViewerBinaryOpen(comm, outfile ? outfile : "bddc_dump.dat", load ? FILE_MODE_READ : FILE_MODE_WRITE, &viewer));
95079de2952eSStefano Zampini   if (load) {
95089de2952eSStefano Zampini     IS  is;
95099de2952eSStefano Zampini     Mat A;
95109de2952eSStefano Zampini 
95119de2952eSStefano Zampini     PetscCall(PetscViewerBinaryRead(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), NULL, PETSC_INT));
95129de2952eSStefano Zampini     PetscCheck(header[0] == 0 || header[0] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95139de2952eSStefano Zampini     PetscCheck(header[1] == 0 || header[1] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95149de2952eSStefano Zampini     PetscCheck(header[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95159de2952eSStefano Zampini     PetscCheck(header[3] == 0 || header[3] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95169de2952eSStefano Zampini     PetscCheck(header[4] == 0 || header[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95179de2952eSStefano Zampini     PetscCheck(header[5] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95189de2952eSStefano Zampini     PetscCheck(header[7] == 0 || header[7] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95199de2952eSStefano Zampini     PetscCheck(header[8] == 0 || header[8] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95209de2952eSStefano Zampini     PetscCheck(header[9] == 0 || header[9] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95219de2952eSStefano Zampini     PetscCheck(header[10] == 0 || header[10] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
95229de2952eSStefano Zampini     if (header[0]) {
95239de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
95249de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
95259de2952eSStefano Zampini       PetscCall(PCBDDCSetDirichletBoundaries(pc, is));
95269de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
95279de2952eSStefano Zampini     }
95289de2952eSStefano Zampini     if (header[1]) {
95299de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
95309de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
95319de2952eSStefano Zampini       PetscCall(PCBDDCSetNeumannBoundaries(pc, is));
95329de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
95339de2952eSStefano Zampini     }
95349de2952eSStefano Zampini     if (header[2]) {
95359de2952eSStefano Zampini       IS *isarray;
95369de2952eSStefano Zampini 
95379de2952eSStefano Zampini       PetscCall(PetscMalloc1(header[2], &isarray));
95389de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) {
95399de2952eSStefano Zampini         PetscCall(ISCreate(comm, &isarray[i]));
95409de2952eSStefano Zampini         PetscCall(ISLoad(isarray[i], viewer));
95419de2952eSStefano Zampini       }
95429de2952eSStefano Zampini       PetscCall(PCBDDCSetDofsSplitting(pc, header[2], isarray));
95439de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) PetscCall(ISDestroy(&isarray[i]));
95449de2952eSStefano Zampini       PetscCall(PetscFree(isarray));
95459de2952eSStefano Zampini     }
95469de2952eSStefano Zampini     if (header[3]) {
95479de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
95489de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
95499de2952eSStefano Zampini       PetscCall(PCBDDCSetPrimalVerticesIS(pc, is));
95509de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
95519de2952eSStefano Zampini     }
95529de2952eSStefano Zampini     if (header[4]) {
95539de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
95549de2952eSStefano Zampini       PetscCall(MatSetType(A, MATAIJ));
95559de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
95569de2952eSStefano Zampini       PetscCall(PCBDDCSetDiscreteGradient(pc, A, header[5], header[6], (PetscBool)header[7], (PetscBool)header[8]));
95579de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
95589de2952eSStefano Zampini     }
95599de2952eSStefano Zampini     if (header[9]) {
95609de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
95619de2952eSStefano Zampini       PetscCall(MatSetType(A, MATIS));
95629de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
95639de2952eSStefano Zampini       PetscCall(PCBDDCSetDivergenceMat(pc, A, (PetscBool)header[10], NULL));
95649de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
95659de2952eSStefano Zampini     }
95669de2952eSStefano Zampini   } else {
95679de2952eSStefano Zampini     header[0]  = (PetscInt)!!pcbddc->DirichletBoundariesLocal;
95689de2952eSStefano Zampini     header[1]  = (PetscInt)!!pcbddc->NeumannBoundariesLocal;
95699de2952eSStefano Zampini     header[2]  = pcbddc->n_ISForDofsLocal;
95709de2952eSStefano Zampini     header[3]  = (PetscInt)!!pcbddc->user_primal_vertices_local;
95719de2952eSStefano Zampini     header[4]  = (PetscInt)!!pcbddc->discretegradient;
95729de2952eSStefano Zampini     header[5]  = pcbddc->nedorder;
95739de2952eSStefano Zampini     header[6]  = pcbddc->nedfield;
95749de2952eSStefano Zampini     header[7]  = (PetscInt)pcbddc->nedglobal;
95759de2952eSStefano Zampini     header[8]  = (PetscInt)pcbddc->conforming;
95769de2952eSStefano Zampini     header[9]  = (PetscInt)!!pcbddc->divudotp;
95779de2952eSStefano Zampini     header[10] = (PetscInt)pcbddc->divudotp_trans;
95789de2952eSStefano Zampini     if (header[4]) header[3] = 0;
95799de2952eSStefano Zampini 
95809de2952eSStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), PETSC_INT));
95819de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->DirichletBoundariesLocal, viewer));
95829de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->NeumannBoundariesLocal, viewer));
95839de2952eSStefano Zampini     for (PetscInt i = 0; i < header[2]; i++) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->ISForDofsLocal[i], viewer));
95849de2952eSStefano Zampini     if (header[3]) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->user_primal_vertices_local, viewer));
95859de2952eSStefano Zampini     if (header[4]) PetscCall(MatView(pcbddc->discretegradient, viewer));
95869de2952eSStefano Zampini     if (header[9]) PetscCall(MatView(pcbddc->divudotp, viewer));
95879de2952eSStefano Zampini   }
95889de2952eSStefano Zampini   PetscCall(PetscViewerDestroy(&viewer));
95899de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
95909de2952eSStefano Zampini }
95919de2952eSStefano Zampini 
95921e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
9593ba38deedSJacob Faibussowitsch static PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
9594d71ae5a4SJacob Faibussowitsch {
95951e0482f5SStefano Zampini   Mat         At;
95961e0482f5SStefano Zampini   IS          rows;
95971e0482f5SStefano Zampini   PetscInt    rst, ren;
95981e0482f5SStefano Zampini   PetscLayout rmap;
95991e0482f5SStefano Zampini 
96001e0482f5SStefano Zampini   PetscFunctionBegin;
96011e0482f5SStefano Zampini   rst = ren = 0;
96021e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
96039566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
96049566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
96059566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
96069566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
96079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
96081e0482f5SStefano Zampini   }
96099566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
96109566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
96119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
96121e0482f5SStefano Zampini 
96131e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
96141e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
96151e0482f5SStefano Zampini     IS          from, to;
96161e0482f5SStefano Zampini     Vec         gvec;
96171e0482f5SStefano Zampini     PetscInt    lsize;
96181e0482f5SStefano Zampini 
96199566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
96209566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
96219566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
962257508eceSPierre Jolivet     PetscCall(PetscLayoutDestroy(&(*B)->rmap));
96239566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
96241e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
96251e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
96269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
96279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
96289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
96299566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
96301e0482f5SStefano Zampini     b->A = a->A;
96311e0482f5SStefano Zampini     b->B = a->B;
96321e0482f5SStefano Zampini 
96331e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
96341e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
96350a545947SLisandro Dalcin     b->rowindices   = NULL;
96360a545947SLisandro Dalcin     b->rowvalues    = NULL;
96371e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
96381e0482f5SStefano Zampini 
96391e0482f5SStefano Zampini     (*B)->rmap         = rmap;
96401e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
96411e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
96421e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
96431e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
96441e0482f5SStefano Zampini 
96451e0482f5SStefano Zampini     if (a->colmap) {
96461e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
9647eec179cfSJacob Faibussowitsch       PetscCall(PetscHMapIDuplicate(a->colmap, &b->colmap));
96481e0482f5SStefano Zampini #else
96499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
96509566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
96511e0482f5SStefano Zampini #endif
96520a545947SLisandro Dalcin     } else b->colmap = NULL;
96531e0482f5SStefano Zampini     if (a->garray) {
96541e0482f5SStefano Zampini       PetscInt len;
96551e0482f5SStefano Zampini       len = a->B->cmap->n;
96569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
96579566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
96580a545947SLisandro Dalcin     } else b->garray = NULL;
96591e0482f5SStefano Zampini 
96609566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
96611e0482f5SStefano Zampini     b->lvec = a->lvec;
96621e0482f5SStefano Zampini 
96631e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
96649566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
96659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
96669566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
96679566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
96689566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
96699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
96709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
96719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
96721e0482f5SStefano Zampini   }
96739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
96743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96751e0482f5SStefano Zampini }
96769de2952eSStefano Zampini 
96779de2952eSStefano Zampini /* same as MatCreateSubMatrix(A, rows, NULL,...) but allows repeated rows */
96789de2952eSStefano Zampini static PetscErrorCode MatAIJExtractRows(Mat A, IS rows, Mat *sA)
96799de2952eSStefano Zampini {
96809de2952eSStefano Zampini   PetscBool isaij;
96819de2952eSStefano Zampini   MPI_Comm  comm;
96829de2952eSStefano Zampini 
96839de2952eSStefano Zampini   PetscFunctionBegin;
96849de2952eSStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
96859de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &isaij, MATSEQAIJ, MATMPIAIJ, ""));
96869de2952eSStefano Zampini   PetscCheck(isaij, comm, PETSC_ERR_SUP, "Not implemented");
96879de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isaij));
96889de2952eSStefano Zampini   if (isaij) { /* SeqAIJ supports repeated rows */
96899de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, sA));
96909de2952eSStefano Zampini   } else {
96919de2952eSStefano Zampini     Mat                A_loc;
96929de2952eSStefano Zampini     Mat_SeqAIJ        *da;
96939de2952eSStefano Zampini     PetscSF            sf;
96949de2952eSStefano Zampini     PetscInt           ni, *di, *dj, m = A->rmap->n, c, *ldata, *rdata;
96959de2952eSStefano Zampini     PetscScalar       *daa;
96969de2952eSStefano Zampini     const PetscInt    *idxs;
96979de2952eSStefano Zampini     const PetscSFNode *iremotes;
96989de2952eSStefano Zampini     PetscSFNode       *remotes;
96999de2952eSStefano Zampini 
97009de2952eSStefano Zampini     /* SF for incoming rows */
97019de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &sf));
97029de2952eSStefano Zampini     PetscCall(ISGetLocalSize(rows, &ni));
97039de2952eSStefano Zampini     PetscCall(ISGetIndices(rows, &idxs));
97049de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, ni, NULL, PETSC_USE_POINTER, idxs));
97059de2952eSStefano Zampini     PetscCall(ISRestoreIndices(rows, &idxs));
97069de2952eSStefano Zampini 
97079de2952eSStefano Zampini     PetscCall(MatMPIAIJGetLocalMat(A, MAT_INITIAL_MATRIX, &A_loc));
97089de2952eSStefano Zampini     da = (Mat_SeqAIJ *)A_loc->data;
97099de2952eSStefano Zampini     PetscCall(PetscMalloc2(2 * ni, &ldata, 2 * m, &rdata));
97109de2952eSStefano Zampini     for (PetscInt i = 0; i < m; i++) {
97119de2952eSStefano Zampini       rdata[2 * i + 0] = da->i[i + 1] - da->i[i];
97129de2952eSStefano Zampini       rdata[2 * i + 1] = da->i[i];
97139de2952eSStefano Zampini     }
97149de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
97159de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
97169de2952eSStefano Zampini     PetscCall(PetscMalloc1(ni + 1, &di));
97179de2952eSStefano Zampini     di[0] = 0;
97189de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) di[i + 1] = di[i] + ldata[2 * i + 0];
97199de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &dj));
97209de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &daa));
97219de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &remotes));
97229de2952eSStefano Zampini 
97239de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(sf, NULL, NULL, NULL, &iremotes));
97249de2952eSStefano Zampini 
97259de2952eSStefano Zampini     /* SF graph for nonzeros */
97269de2952eSStefano Zampini     c = 0;
97279de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) {
9728835f2295SStefano Zampini       const PetscInt rank  = iremotes[i].rank;
97299de2952eSStefano Zampini       const PetscInt rsize = ldata[2 * i];
97309de2952eSStefano Zampini       for (PetscInt j = 0; j < rsize; j++) {
97319de2952eSStefano Zampini         remotes[c].rank  = rank;
97329de2952eSStefano Zampini         remotes[c].index = ldata[2 * i + 1] + j;
97339de2952eSStefano Zampini         c++;
97349de2952eSStefano Zampini       }
97359de2952eSStefano Zampini     }
97369de2952eSStefano Zampini     PetscCheck(c == di[ni], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of local nonzeros %" PetscInt_FMT " != %" PetscInt_FMT, c, di[ni]);
97379de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(sf, da->i[m], di[ni], NULL, PETSC_USE_POINTER, remotes, PETSC_USE_POINTER));
97389de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
97399de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
97409de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
97419de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
97429de2952eSStefano Zampini 
97439de2952eSStefano Zampini     PetscCall(MatCreateMPIAIJWithArrays(comm, ni, A->cmap->n, PETSC_DECIDE, A->cmap->N, di, dj, daa, sA));
97449de2952eSStefano Zampini     PetscCall(MatDestroy(&A_loc));
97459de2952eSStefano Zampini     PetscCall(PetscSFDestroy(&sf));
97469de2952eSStefano Zampini     PetscCall(PetscFree(di));
97479de2952eSStefano Zampini     PetscCall(PetscFree(dj));
97489de2952eSStefano Zampini     PetscCall(PetscFree(daa));
97499de2952eSStefano Zampini     PetscCall(PetscFree(remotes));
97509de2952eSStefano Zampini     PetscCall(PetscFree2(ldata, rdata));
97519de2952eSStefano Zampini   }
97529de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
97539de2952eSStefano Zampini }
9754