xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision d7974de0bb28820a4deab863dae36e244f8c42e4)
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));
2085440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&lrc[0], &lrc[1], 1, MPI_C_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"); */
10595440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&eerr, &done, 1, MPI_C_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 
1329732a5147SStefano Zampini   /* Create change of basis matrix (no preallocation) */
13309566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
13319de2952eSStefano Zampini   PetscCall(MatSetLayouts(T, pc->mat->rmap, pc->mat->cmap));
13329566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
13339566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
13349566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
1335732a5147SStefano Zampini   PetscCall(MatSetOption(T, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
1336732a5147SStefano Zampini   //PetscCall(MatSeqAIJSetPreallocation(T, maxsize, NULL));
1337732a5147SStefano Zampini   //PetscCall(MatMPIAIJSetPreallocation(T, maxsize, NULL, maxsize, NULL));
1338732a5147SStefano Zampini   //PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
1339a13144ffSStefano Zampini 
1340a13144ffSStefano Zampini   /* Defaults to identity */
1341732a5147SStefano Zampini   {
1342732a5147SStefano Zampini     Vec                w;
1343732a5147SStefano Zampini     const PetscScalar *wa;
1344732a5147SStefano Zampini 
1345732a5147SStefano Zampini     PetscCall(MatCreateVecs(T, &w, NULL));
1346732a5147SStefano Zampini     PetscCall(VecSetLocalToGlobalMapping(w, al2g));
1347732a5147SStefano Zampini     PetscCall(VecSet(w, 1.0));
1348732a5147SStefano Zampini     for (i = 0; i < nee; i++) {
1349732a5147SStefano Zampini       const PetscInt *idxs;
1350732a5147SStefano Zampini       PetscInt        nl;
1351732a5147SStefano Zampini 
1352732a5147SStefano Zampini       PetscCall(ISGetLocalSize(eedges[i], &nl));
1353732a5147SStefano Zampini       PetscCall(ISGetIndices(eedges[i], &idxs));
1354732a5147SStefano Zampini       PetscCall(VecSetValuesLocal(w, nl, idxs, NULL, INSERT_VALUES));
1355732a5147SStefano Zampini       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1356732a5147SStefano Zampini     }
1357732a5147SStefano Zampini     PetscCall(VecAssemblyBegin(w));
1358732a5147SStefano Zampini     PetscCall(VecAssemblyEnd(w));
1359732a5147SStefano Zampini     PetscCall(VecGetArrayRead(w, &wa));
1360732a5147SStefano Zampini     for (i = T->rmap->rstart; i < T->rmap->rend; i++)
1361732a5147SStefano Zampini       if (PetscAbsScalar(wa[i - T->rmap->rstart])) PetscCall(MatSetValue(T, i, i, 1.0, INSERT_VALUES));
1362732a5147SStefano Zampini     PetscCall(VecRestoreArrayRead(w, &wa));
1363732a5147SStefano Zampini     PetscCall(VecDestroy(&w));
1364732a5147SStefano Zampini   }
1365a13144ffSStefano Zampini 
13661e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
13679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
13689566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
13691e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
13701e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
13711e0482f5SStefano Zampini     IS                     wis, gwis;
13721e0482f5SStefano Zampini     PetscInt               cnv, cne;
13731e0482f5SStefano Zampini 
13749566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
13751e0482f5SStefano Zampini     if (fl2g) {
13769566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
13771e0482f5SStefano Zampini     } else {
13789566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
13791e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
13801e0482f5SStefano Zampini     }
13819566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
13829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13839566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
13849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
13859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13871e0482f5SStefano Zampini 
13889566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
13899566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
13909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13919566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
13929566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
13939566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13951e0482f5SStefano Zampini 
13969566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
13979566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
13989566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
13999566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
14009566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
14019566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
14029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
14039566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
14041e0482f5SStefano Zampini   }
14051e0482f5SStefano Zampini 
1406a75bf7bfSStefano Zampini   MatNullSpace nnsp;
1407a75bf7bfSStefano Zampini   PetscBool    nnsp_has_const = PETSC_FALSE;
1408a75bf7bfSStefano Zampini   const Vec   *nnsp_vecs      = NULL;
1409a75bf7bfSStefano Zampini   PetscInt     nnsp_nvecs     = 0;
1410a75bf7bfSStefano Zampini   VecScatter   nnsp_vscat     = NULL;
1411a75bf7bfSStefano Zampini   PetscCall(MatGetNullSpace(pcbddc->discretegradient, &nnsp));
1412a75bf7bfSStefano Zampini   if (nnsp) PetscCall(MatNullSpaceGetVecs(nnsp, &nnsp_has_const, &nnsp_nvecs, &nnsp_vecs));
1413a75bf7bfSStefano Zampini   if (nnsp_has_const || nnsp_nvecs) { /* create scatter to import edge constraints */
1414a75bf7bfSStefano Zampini     IS                 allextcols, gallextcols, galleedges, is_E_to_zero;
1415a75bf7bfSStefano Zampini     Vec                E, V;
1416a75bf7bfSStefano Zampini     PetscInt          *eedgesidxs;
1417a75bf7bfSStefano Zampini     const PetscScalar *evals;
1418a75bf7bfSStefano Zampini 
1419a75bf7bfSStefano Zampini     PetscCall(MatCreateVecs(pc->pmat, &E, NULL));
1420a75bf7bfSStefano Zampini     PetscCall(MatCreateVecs(pcbddc->discretegradient, &V, NULL));
1421a75bf7bfSStefano Zampini     PetscCall(ISConcatenate(PETSC_COMM_SELF, nee, extcols, &allextcols));
1422a75bf7bfSStefano Zampini     cum = 0;
1423a75bf7bfSStefano Zampini     for (i = 0; i < nee; i++) {
1424a75bf7bfSStefano Zampini       PetscInt j;
1425a75bf7bfSStefano Zampini 
1426a75bf7bfSStefano Zampini       PetscCall(ISGetLocalSize(eedges[i], &j));
14278c5add6aSPierre Jolivet       PetscCheck(j, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Zero sized edge %" PetscInt_FMT, i);
1428a75bf7bfSStefano Zampini       cum += j - 1;
1429a75bf7bfSStefano Zampini     }
1430a75bf7bfSStefano Zampini     PetscCall(PetscMalloc1(PetscMax(cum, pc->pmat->rmap->n), &eedgesidxs));
1431a75bf7bfSStefano Zampini     cum = 0;
1432a75bf7bfSStefano Zampini     for (i = 0; i < nee; i++) {
1433a75bf7bfSStefano Zampini       const PetscInt *idxs;
1434a75bf7bfSStefano Zampini       PetscInt        j;
1435a75bf7bfSStefano Zampini 
1436a75bf7bfSStefano Zampini       PetscCall(ISGetLocalSize(eedges[i], &j));
1437a75bf7bfSStefano Zampini       PetscCall(ISGetIndices(eedges[i], &idxs));
1438a75bf7bfSStefano Zampini       PetscCall(PetscArraycpy(eedgesidxs + cum, idxs, j - 1)); /* last on the edge is primal */
1439a75bf7bfSStefano Zampini       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1440a75bf7bfSStefano Zampini       cum += j - 1;
1441a75bf7bfSStefano Zampini     }
1442a75bf7bfSStefano Zampini     PetscCall(ISLocalToGlobalMappingApply(al2g, cum, eedgesidxs, eedgesidxs));
1443a75bf7bfSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, eedgesidxs, PETSC_USE_POINTER, &galleedges));
1444a75bf7bfSStefano Zampini     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, allextcols, &gallextcols));
1445a75bf7bfSStefano Zampini     PetscCall(VecScatterCreate(V, gallextcols, E, galleedges, &nnsp_vscat));
1446a75bf7bfSStefano Zampini     PetscCall(ISDestroy(&allextcols));
1447a75bf7bfSStefano Zampini     PetscCall(ISDestroy(&gallextcols));
1448a75bf7bfSStefano Zampini     PetscCall(ISDestroy(&galleedges));
1449a75bf7bfSStefano Zampini 
1450a75bf7bfSStefano Zampini     /* identify dofs we must zero if importing user-defined near nullspace from pmat */
1451a75bf7bfSStefano Zampini     PetscCall(VecSet(E, 1.0));
1452a75bf7bfSStefano Zampini     PetscCall(VecSetValues(E, cum, eedgesidxs, NULL, INSERT_VALUES));
1453a75bf7bfSStefano Zampini     PetscCall(VecAssemblyBegin(E));
1454a75bf7bfSStefano Zampini     PetscCall(VecAssemblyEnd(E));
1455a75bf7bfSStefano Zampini     PetscCall(VecGetArrayRead(E, &evals));
1456a75bf7bfSStefano Zampini     for (i = 0, cum = 0; i < pc->pmat->rmap->n; i++)
1457a75bf7bfSStefano Zampini       if (evals[i] == 0.0) eedgesidxs[cum++] = i + pc->pmat->rmap->rstart;
1458a75bf7bfSStefano Zampini     PetscCall(VecRestoreArrayRead(E, &evals));
1459a75bf7bfSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, eedgesidxs, PETSC_COPY_VALUES, &is_E_to_zero));
1460a75bf7bfSStefano Zampini     PetscCall(PetscFree(eedgesidxs));
1461a75bf7bfSStefano Zampini 
1462a75bf7bfSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)nnsp_vscat, "__V_Vec", (PetscObject)V));
1463a75bf7bfSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)nnsp_vscat, "__E_Vec", (PetscObject)E));
1464a75bf7bfSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)nnsp_vscat, "__E_zero", (PetscObject)is_E_to_zero));
1465a75bf7bfSStefano Zampini     PetscCall(ISDestroy(&is_E_to_zero));
1466a75bf7bfSStefano Zampini     PetscCall(VecDestroy(&V));
1467a75bf7bfSStefano Zampini     PetscCall(VecDestroy(&E));
1468a75bf7bfSStefano Zampini   }
14691e0482f5SStefano Zampini #if defined(PRINT_GDET)
14701e0482f5SStefano Zampini   inc = 0;
14711e0482f5SStefano Zampini   lev = pcbddc->current_level;
14721e0482f5SStefano Zampini #endif
1473213b8bfaSStefano Zampini 
1474213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1475a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1476a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
14771e0482f5SStefano Zampini     IS          cornersis = NULL;
14781e0482f5SStefano Zampini     PetscScalar cvals[2];
1479a13144ffSStefano Zampini 
148048a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
14819566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1482a13144ffSStefano Zampini     if (Gins && GKins) {
14831683a169SBarry Smith       const PetscScalar *data;
1484a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1485a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1486a13144ffSStefano Zampini 
14879566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1488a13144ffSStefano Zampini       /* H1 */
14899566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
14909566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
14919566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
14929566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
14939566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
14949566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1495a13144ffSStefano Zampini       /* complement */
14969566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
149763a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
149863a3b9bcSJacob 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);
149963a3b9bcSJacob 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);
15009566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
15019566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
15029566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
15031e0482f5SStefano Zampini 
15041e0482f5SStefano Zampini       /* coarse discrete gradient */
15051e0482f5SStefano Zampini       if (pcbddc->nedcG) {
15061e0482f5SStefano Zampini         PetscInt cols[2];
15071e0482f5SStefano Zampini 
15081e0482f5SStefano Zampini         cols[0] = 2 * i;
15091e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
15109566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
15111e0482f5SStefano Zampini       }
15129566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1513a13144ffSStefano Zampini     }
15149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
15159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
15169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
15179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
15189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1519a13144ffSStefano Zampini   }
15200b61a303SStefano Zampini 
1521a75bf7bfSStefano Zampini   /* import edge constraints */
1522a75bf7bfSStefano Zampini   if (nnsp_vscat) {
1523a75bf7bfSStefano Zampini     Vec          V, E, *quadvecs;
1524a75bf7bfSStefano Zampini     PetscInt     nvecs, nvecs_orth;
1525a75bf7bfSStefano Zampini     MatNullSpace onnsp           = NULL;
1526a75bf7bfSStefano Zampini     PetscBool    onnsp_has_const = PETSC_FALSE;
1527a75bf7bfSStefano Zampini     const Vec   *onnsp_vecs      = NULL;
1528a75bf7bfSStefano Zampini     PetscInt     onnsp_nvecs     = 0, new_nnsp_nvecs, old_nnsp_nvecs;
1529a75bf7bfSStefano Zampini     IS           is_E_to_zero;
15300b61a303SStefano Zampini 
1531a75bf7bfSStefano Zampini     /* import nearnullspace from preconditioning matrix if user-defined */
1532a75bf7bfSStefano Zampini     PetscCall(MatGetNearNullSpace(pc->pmat, &onnsp));
1533a75bf7bfSStefano Zampini     if (onnsp) {
1534a75bf7bfSStefano Zampini       PetscBool isinternal;
15350b61a303SStefano Zampini 
1536a75bf7bfSStefano Zampini       PetscCall(PetscStrcmp("_internal_BDDC_nedelec_nnsp", ((PetscObject)onnsp)->name, &isinternal));
1537a75bf7bfSStefano Zampini       if (!isinternal) PetscCall(MatNullSpaceGetVecs(onnsp, &onnsp_has_const, &onnsp_nvecs, &onnsp_vecs));
15380b61a303SStefano Zampini     }
1539a75bf7bfSStefano Zampini     new_nnsp_nvecs = nnsp_nvecs + (nnsp_has_const ? 1 : 0);
1540a75bf7bfSStefano Zampini     old_nnsp_nvecs = onnsp_nvecs + (onnsp_has_const ? 1 : 0);
1541a75bf7bfSStefano Zampini     nvecs          = old_nnsp_nvecs + new_nnsp_nvecs;
1542a75bf7bfSStefano Zampini     PetscCall(PetscMalloc1(nvecs, &quadvecs));
1543a75bf7bfSStefano Zampini 
1544a75bf7bfSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)nnsp_vscat, "__V_Vec", (PetscObject *)&V));
1545a75bf7bfSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)nnsp_vscat, "__E_Vec", (PetscObject *)&E));
1546a75bf7bfSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)nnsp_vscat, "__E_zero", (PetscObject *)&is_E_to_zero));
1547a75bf7bfSStefano Zampini     for (i = 0; i < nvecs; i++) PetscCall(VecDuplicate(E, &quadvecs[i]));
1548a75bf7bfSStefano Zampini     cum = 0;
1549a75bf7bfSStefano Zampini     if (nnsp_has_const) {
1550a75bf7bfSStefano Zampini       PetscCall(VecSet(V, 1.0));
1551a75bf7bfSStefano Zampini       PetscCall(VecScatterBegin(nnsp_vscat, V, quadvecs[0], INSERT_VALUES, SCATTER_FORWARD));
1552a75bf7bfSStefano Zampini       PetscCall(VecScatterEnd(nnsp_vscat, V, quadvecs[0], INSERT_VALUES, SCATTER_FORWARD));
1553a75bf7bfSStefano Zampini       cum = 1;
1554a75bf7bfSStefano Zampini     }
1555a75bf7bfSStefano Zampini     for (i = 0; i < nnsp_nvecs; i++) {
1556a75bf7bfSStefano Zampini       PetscCall(VecScatterBegin(nnsp_vscat, nnsp_vecs[i], quadvecs[i + cum], INSERT_VALUES, SCATTER_FORWARD));
1557a75bf7bfSStefano Zampini       PetscCall(VecScatterEnd(nnsp_vscat, nnsp_vecs[i], quadvecs[i + cum], INSERT_VALUES, SCATTER_FORWARD));
1558a75bf7bfSStefano Zampini     }
1559a75bf7bfSStefano Zampini 
1560a75bf7bfSStefano Zampini     /* Now add old nnsp if present */
1561a75bf7bfSStefano Zampini     cum = 0;
1562a75bf7bfSStefano Zampini     if (onnsp_has_const) {
1563a75bf7bfSStefano Zampini       PetscCall(VecSet(quadvecs[new_nnsp_nvecs], 1.0));
1564a75bf7bfSStefano Zampini       PetscCall(VecISSet(quadvecs[new_nnsp_nvecs], is_E_to_zero, 0));
1565a75bf7bfSStefano Zampini       cum = 1;
1566a75bf7bfSStefano Zampini     }
1567a75bf7bfSStefano Zampini     for (i = 0; i < onnsp_nvecs; i++) {
1568a75bf7bfSStefano Zampini       PetscCall(VecCopy(onnsp_vecs[i], quadvecs[i + cum + new_nnsp_nvecs]));
1569a75bf7bfSStefano Zampini       PetscCall(VecISSet(quadvecs[i + cum + new_nnsp_nvecs], is_E_to_zero, 0));
1570a75bf7bfSStefano Zampini     }
1571a75bf7bfSStefano Zampini     nvecs_orth = nvecs;
1572a75bf7bfSStefano Zampini     PetscCall(PCBDDCOrthonormalizeVecs(&nvecs_orth, quadvecs));
1573a75bf7bfSStefano Zampini     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)pc), PETSC_FALSE, nvecs_orth, quadvecs, &nnsp));
1574a75bf7bfSStefano Zampini     for (i = 0; i < nvecs; i++) PetscCall(VecDestroy(&quadvecs[i]));
1575a75bf7bfSStefano Zampini     PetscCall(PetscFree(quadvecs));
1576a75bf7bfSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)nnsp, "_internal_BDDC_nedelec_nnsp"));
15770b61a303SStefano Zampini     PetscCall(MatSetNearNullSpace(pc->pmat, nnsp));
15780b61a303SStefano Zampini     PetscCall(MatNullSpaceDestroy(&nnsp));
15790b61a303SStefano Zampini   }
1580a75bf7bfSStefano Zampini   PetscCall(VecScatterDestroy(&nnsp_vscat));
1581a75bf7bfSStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
15829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1583732a5147SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1584a13144ffSStefano Zampini 
1585a13144ffSStefano Zampini   /* Start assembling */
15869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
15871baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1588a13144ffSStefano Zampini 
1589a13144ffSStefano Zampini   /* Free */
1590c2151214SStefano Zampini   if (fl2g) {
15919566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
159248a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
15939566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1594c2151214SStefano Zampini   }
1595eee23b56SStefano Zampini 
1596eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1597eee23b56SStefano Zampini   {
1598eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1599eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1600eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1601eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1602eee23b56SStefano Zampini 
1603eee23b56SStefano Zampini     /* find first primal edge */
1604eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
16059566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1606eee23b56SStefano Zampini     } else {
16071baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1608eee23b56SStefano Zampini       idxs = cedges;
1609eee23b56SStefano Zampini     }
1610eee23b56SStefano Zampini     cum = 0;
1611eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1612eee23b56SStefano Zampini 
1613eee23b56SStefano Zampini     /* adapt connected components */
16149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1615eee23b56SStefano Zampini     graph->cptr[0] = 0;
1616eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1617eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1618eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1619eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1620eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1621eee23b56SStefano Zampini         ncc++;
1622eee23b56SStefano Zampini         lc--;
1623eee23b56SStefano Zampini         cum++;
1624eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1625eee23b56SStefano Zampini       }
1626eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1627eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1628eee23b56SStefano Zampini       ncc++;
1629eee23b56SStefano Zampini     }
1630eee23b56SStefano Zampini     graph->ncc = ncc;
163148a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
16329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1633eee23b56SStefano Zampini   }
16349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
16359566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
16369566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
1637eee23b56SStefano Zampini 
16389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
16399566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
16409566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
16419566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
16429566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
16439566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
16449566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
16459566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1646a13144ffSStefano Zampini 
1647a13144ffSStefano Zampini   /* Complete assembling */
16489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
16499de2952eSStefano Zampini   PetscCall(MatViewFromOptions(T, (PetscObject)pc, "-pc_bddc_nedelec_change_view"));
16501e0482f5SStefano Zampini   if (pcbddc->nedcG) {
16519566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1652a4cdd7efSStefano Zampini     PetscCall(MatViewFromOptions(pcbddc->nedcG, (PetscObject)pc, "-pc_bddc_nedelec_coarse_change_view"));
16531e0482f5SStefano Zampini   }
1654a13144ffSStefano Zampini 
16550b61a303SStefano Zampini   PetscCall(ISDestroy(&elements_corners));
16560b61a303SStefano Zampini 
1657a13144ffSStefano Zampini   /* set change of basis */
16580b61a303SStefano Zampini   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, PETSC_FALSE));
16599566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
16603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1661a13144ffSStefano Zampini }
1662a13144ffSStefano Zampini 
1663d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1664d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1665d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
1666d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1667d71ae5a4SJacob Faibussowitsch {
1668d8203eabSStefano Zampini   PetscInt i;
1669d8203eabSStefano Zampini 
1670d8203eabSStefano Zampini   PetscFunctionBegin;
1671d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1672d8203eabSStefano Zampini     PetscInt first, last;
1673d8203eabSStefano Zampini 
16749566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
16757827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1676d8203eabSStefano Zampini     if (i >= first && i < last) {
1677d8203eabSStefano Zampini       PetscScalar *data;
16789566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1679d8203eabSStefano Zampini       if (!has_const) {
1680d8203eabSStefano Zampini         data[i - first] = 1.;
1681d8203eabSStefano Zampini       } else {
168286fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
168386fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1684d8203eabSStefano Zampini       }
16859566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1686d8203eabSStefano Zampini     }
16879566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1688d8203eabSStefano Zampini   }
16899566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1690d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1691d8203eabSStefano Zampini     PetscInt first, last;
16929566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
16939566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1694d8203eabSStefano Zampini     if (i >= first && i < last) {
1695d8203eabSStefano Zampini       PetscScalar *data;
16969566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1697d8203eabSStefano Zampini       if (!has_const) {
1698d8203eabSStefano Zampini         data[i - first] = 0.;
1699d8203eabSStefano Zampini       } else {
170086fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
170186fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1702d8203eabSStefano Zampini       }
17039566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1704d8203eabSStefano Zampini     }
17059566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
17069566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1707d8203eabSStefano Zampini   }
17083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1709d8203eabSStefano Zampini }
1710d8203eabSStefano Zampini 
1711d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1712d71ae5a4SJacob Faibussowitsch {
1713a198735bSStefano Zampini   Mat                    loc_divudotp;
17149de2952eSStefano Zampini   Vec                    p, v, quad_vec;
17158ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
17169de2952eSStefano Zampini   PetscScalar           *array;
1717669cc0f4SStefano Zampini 
1718669cc0f4SStefano Zampini   PetscFunctionBegin;
17199566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
17208ae0ca82SStefano Zampini   if (!transpose) {
17219566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
17228ae0ca82SStefano Zampini   } else {
17239566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
17248ae0ca82SStefano Zampini   }
17259de2952eSStefano Zampini   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, 1, &quad_vec, nnsp));
17269de2952eSStefano Zampini   PetscCall(VecLockReadPop(quad_vec));
17279de2952eSStefano Zampini   PetscCall(VecSetLocalToGlobalMapping(quad_vec, map));
1728d8203eabSStefano Zampini 
1729669cc0f4SStefano Zampini   /* compute local quad vec */
17309566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
17318ae0ca82SStefano Zampini   if (!transpose) {
17329566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
17338ae0ca82SStefano Zampini   } else {
17349566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
17358ae0ca82SStefano Zampini   }
17369de2952eSStefano Zampini   /* the assumption here is that the constant vector interpolates the constant on the L2 conforming space */
17379566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
17388ae0ca82SStefano Zampini   if (!transpose) {
17399566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
17408ae0ca82SStefano Zampini   } else {
17419566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
17428ae0ca82SStefano Zampini   }
17439de2952eSStefano Zampini   PetscCall(VecDestroy(&p));
1744fa23a32eSStefano Zampini   if (vl2l) {
1745187c917aSStefano Zampini     Mat        lA;
1746187c917aSStefano Zampini     VecScatter sc;
17479de2952eSStefano Zampini     Vec        vins;
1748187c917aSStefano Zampini 
17499566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
17509566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
17519566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
17529566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
17539566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
17549566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
17559566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&v));
17569de2952eSStefano Zampini     v = vins;
1757669cc0f4SStefano Zampini   }
17589de2952eSStefano Zampini 
17599de2952eSStefano Zampini   /* mask summation of interface values */
17609de2952eSStefano Zampini   PetscInt        n, *mmask, *mask, *idxs, nmr, nr;
17619de2952eSStefano Zampini   const PetscInt *degree;
17629de2952eSStefano Zampini   PetscSF         msf;
17639de2952eSStefano Zampini 
17649de2952eSStefano Zampini   PetscCall(VecGetLocalSize(v, &n));
17659de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nr, NULL, NULL, NULL));
17669de2952eSStefano Zampini   PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf));
17679de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
17689de2952eSStefano Zampini   PetscCall(PetscCalloc3(nmr, &mmask, n, &mask, n, &idxs));
17699de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &degree));
17709de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &degree));
17719de2952eSStefano Zampini   for (PetscInt i = 0, c = 0; i < nr; i++) {
17729de2952eSStefano Zampini     mmask[c] = 1;
17739de2952eSStefano Zampini     c += degree[i];
17749de2952eSStefano Zampini   }
17759de2952eSStefano Zampini   PetscCall(PetscSFScatterBegin(graph->interface_subset_sf, MPIU_INT, mmask, mask));
17769de2952eSStefano Zampini   PetscCall(PetscSFScatterEnd(graph->interface_subset_sf, MPIU_INT, mmask, mask));
17779de2952eSStefano Zampini   PetscCall(VecGetArray(v, &array));
17789de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
17799de2952eSStefano Zampini     array[i] *= mask[i];
17809de2952eSStefano Zampini     idxs[i] = i;
17819de2952eSStefano Zampini   }
17829de2952eSStefano Zampini   PetscCall(VecSetValuesLocal(quad_vec, n, idxs, array, ADD_VALUES));
17839de2952eSStefano Zampini   PetscCall(VecRestoreArray(v, &array));
17849de2952eSStefano Zampini   PetscCall(PetscFree3(mmask, mask, idxs));
17859de2952eSStefano Zampini   PetscCall(VecDestroy(&v));
17869de2952eSStefano Zampini   PetscCall(VecAssemblyBegin(quad_vec));
17879de2952eSStefano Zampini   PetscCall(VecAssemblyEnd(quad_vec));
17889de2952eSStefano Zampini   PetscCall(VecViewFromOptions(quad_vec, NULL, "-pc_bddc_quad_vec_view"));
17899de2952eSStefano Zampini   PetscCall(VecLockReadPush(quad_vec));
17909de2952eSStefano Zampini   PetscCall(VecDestroy(&quad_vec));
17913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1792669cc0f4SStefano Zampini }
1793669cc0f4SStefano Zampini 
1794d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1795d71ae5a4SJacob Faibussowitsch {
17967620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
17977620a527SStefano Zampini 
17987620a527SStefano Zampini   PetscFunctionBegin;
17997620a527SStefano Zampini   if (primalv) {
18007620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
18017620a527SStefano Zampini       IS list[2], newp;
18027620a527SStefano Zampini 
18037620a527SStefano Zampini       list[0] = primalv;
18047620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
18059566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
18069566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
18079566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
18087620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
18097620a527SStefano Zampini     } else {
18109566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
18117620a527SStefano Zampini     }
18127620a527SStefano Zampini   }
18133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18147620a527SStefano Zampini }
1815669cc0f4SStefano Zampini 
1816d71ae5a4SJacob Faibussowitsch static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1817d71ae5a4SJacob Faibussowitsch {
18181c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
18191c7a958bSStefano Zampini 
18201c7a958bSStefano Zampini   PetscFunctionBegin;
18211c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
18223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18231c7a958bSStefano Zampini }
1824674ae819SStefano Zampini 
1825d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1826d71ae5a4SJacob Faibussowitsch {
18271f4df5f7SStefano Zampini   Vec       local, global;
18281f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
18291f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
18305c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
18311f4df5f7SStefano Zampini 
18321f4df5f7SStefano Zampini   PetscFunctionBegin;
1833d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
18349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1835d0609cedSBarry Smith   PetscOptionsEnd();
18361f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
18379566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
18389566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
18399566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
18409566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
18416a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
184248a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
18436a8fc67bSStefano Zampini     goto boundary;
18446a8fc67bSStefano Zampini   }
18455c5e10d6SStefano Zampini 
18461f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
18471f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
18481f4df5f7SStefano Zampini       PetscInt i;
18490c85b387SStefano Zampini 
18509566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
18511f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
18520c85b387SStefano Zampini         PetscInt bs;
18530c85b387SStefano Zampini 
18549566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
18559566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
18569566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
18579566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
18581f4df5f7SStefano Zampini       }
18591f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
18601f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
18619566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
18621f4df5f7SStefano Zampini     }
18631f4df5f7SStefano Zampini   } else {
186421ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
186521ef3d20SStefano Zampini       DM dm;
186621ef3d20SStefano Zampini 
18679566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
186848a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
186921ef3d20SStefano Zampini       if (dm) {
187021ef3d20SStefano Zampini         IS      *fields;
187121ef3d20SStefano Zampini         PetscInt nf, i;
18720c85b387SStefano Zampini 
18739566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
18749566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
187521ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
18760c85b387SStefano Zampini           PetscInt bs;
18770c85b387SStefano Zampini 
18789566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
18799566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
18809566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
18819566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
188221ef3d20SStefano Zampini         }
18839566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
188421ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
188521ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
188621ef3d20SStefano Zampini         PetscContainer c;
188721ef3d20SStefano Zampini 
18889566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
188921ef3d20SStefano Zampini         if (c) {
189021ef3d20SStefano Zampini           MatISLocalFields lf;
18919566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
18929566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
189321ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
18941f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
18959566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
189621ef3d20SStefano Zampini           if (i > 1) {
1897986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
18989566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
189948a46eb9SPierre 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]));
19001f4df5f7SStefano Zampini           }
190121ef3d20SStefano Zampini         }
190221ef3d20SStefano Zampini       }
19037a0e7b2cSstefano_zampini     } else {
19047a0e7b2cSstefano_zampini       PetscInt i;
190548a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
19061f4df5f7SStefano Zampini     }
1907986cdee1SStefano Zampini   }
19081f4df5f7SStefano Zampini 
19095c5e10d6SStefano Zampini boundary:
19101f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
19119566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
19127a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
19139566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
19141f4df5f7SStefano Zampini   }
19151f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
19169566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
19177a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
19189566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
19191f4df5f7SStefano Zampini   }
192048a46eb9SPierre 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));
19219566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
19229566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
19239de2952eSStefano Zampini   /* detect local disconnected subdomains if requested or needed */
19249de2952eSStefano Zampini   if (pcbddc->detect_disconnected || matis->allow_repeated) {
19257620a527SStefano Zampini     IS        primalv = NULL;
19260b61a303SStefano Zampini     PetscInt  nel;
19278361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
19287a0e7b2cSstefano_zampini 
19290b61a303SStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
19309566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
19310b61a303SStefano Zampini     PetscCall(MatGetVariableBlockSizes(matis->A, &nel, NULL));
19320b61a303SStefano Zampini     if (matis->allow_repeated && nel) {
19330b61a303SStefano Zampini       const PetscInt *elsizes;
19340b61a303SStefano Zampini 
19350b61a303SStefano Zampini       pcbddc->n_local_subs = nel;
19360b61a303SStefano Zampini       PetscCall(MatGetVariableBlockSizes(matis->A, NULL, &elsizes));
19370b61a303SStefano Zampini       PetscCall(PetscMalloc1(nel, &pcbddc->local_subs));
19380b61a303SStefano Zampini       for (PetscInt i = 0, c = 0; i < nel; i++) {
19390b61a303SStefano Zampini         PetscCall(ISCreateStride(PETSC_COMM_SELF, elsizes[i], c, 1, &pcbddc->local_subs[i]));
19400b61a303SStefano Zampini         c += elsizes[i];
19410b61a303SStefano Zampini       }
19420b61a303SStefano Zampini     } else {
19439566063dSJacob Faibussowitsch       PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
19440b61a303SStefano Zampini     }
19459566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
19469566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
19477620a527SStefano Zampini   }
19487620a527SStefano Zampini   /* early stage corner detection */
19497620a527SStefano Zampini   {
19507620a527SStefano Zampini     DM dm;
19517620a527SStefano Zampini 
19529566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
195348a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
19547620a527SStefano Zampini     if (dm) {
19557620a527SStefano Zampini       PetscBool isda;
19567620a527SStefano Zampini 
19579566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
19587620a527SStefano Zampini       if (isda) {
19597620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
19607620a527SStefano Zampini         IS                     corners;
19617620a527SStefano Zampini         Mat                    lA;
19624f819b78SStefano Zampini         PetscBool              gl, lo;
19637620a527SStefano Zampini 
19644f819b78SStefano Zampini         {
19654f819b78SStefano Zampini           Vec                cvec;
19664f819b78SStefano Zampini           const PetscScalar *coords;
19674f819b78SStefano Zampini           PetscInt           dof, n, cdim;
19684f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
19694f819b78SStefano Zampini 
19709566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
19719566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
19729566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
19739566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
19744f819b78SStefano Zampini           n /= cdim;
19759566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
19769566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
19779566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
19784f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
19794f819b78SStefano Zampini           memc = PETSC_FALSE;
19804f819b78SStefano Zampini #endif
19814f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
19824f819b78SStefano Zampini           if (memc) {
19839566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
19844f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
19854f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
19864f819b78SStefano Zampini             PetscInt   i, b, d;
19874f819b78SStefano Zampini 
19884f819b78SStefano Zampini             for (i = 0; i < n; i++) {
19894f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
1990ad540459SPierre Jolivet                 for (d = 0; d < cdim; d++) bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]);
19914f819b78SStefano Zampini               }
19924f819b78SStefano Zampini             }
19934f819b78SStefano Zampini           }
19949566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
19954f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
19964f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
19974f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
19984f819b78SStefano Zampini         }
19999566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
20009566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
20019566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
20029566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
20034f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
20045440e5dcSBarry Smith         PetscCallMPI(MPIU_Allreduce(&lo, &gl, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
20054f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
20067620a527SStefano Zampini           const PetscInt *idx;
200772ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
20087620a527SStefano Zampini 
20099566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
20109566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
20119566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
20129566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
201372ed36d8SStefano Zampini           if (bs == dof) {
20149566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
20159566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
201672ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
201772ed36d8SStefano Zampini             PetscInt i, d;
201872ed36d8SStefano Zampini 
20199566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
20209371c9d4SSatish Balay             for (i = 0; i < n; i++)
20219371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
20229566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
202372ed36d8SStefano Zampini 
202472ed36d8SStefano Zampini             bs = 1;
202572ed36d8SStefano Zampini             n *= dof;
202672ed36d8SStefano Zampini           }
20279566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
20289566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
20299566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
20309566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
20319566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
20321c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
20334f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
20344f819b78SStefano Zampini         }
203548a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
20367620a527SStefano Zampini       }
20377620a527SStefano Zampini     }
20387620a527SStefano Zampini   }
20391c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
20401c7a958bSStefano Zampini     DM dm;
20411c7a958bSStefano Zampini 
20429566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
204348a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
20444f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
20451c7a958bSStefano Zampini       Vec          vcoords;
20461c7a958bSStefano Zampini       PetscSection section;
20471c7a958bSStefano Zampini       PetscReal   *coords;
20481c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
20491c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
205051ab8ad6SStefano Zampini       /* debug coordinates */
205151ab8ad6SStefano Zampini       PetscViewer       viewer;
205251ab8ad6SStefano Zampini       PetscBool         flg;
205351ab8ad6SStefano Zampini       PetscViewerFormat format;
205451ab8ad6SStefano Zampini       const char       *prefix;
20551c7a958bSStefano Zampini 
20569566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
20579566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
20589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
20599566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
20609566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
20619566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
20629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
20639566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
20641c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
20651c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
206651ab8ad6SStefano Zampini 
206751ab8ad6SStefano Zampini       /* debug coordinates */
206851ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
2069648c30bcSBarry Smith       PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
207051ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
20711c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
20721c7a958bSStefano Zampini         PetscInt           i;
20731c7a958bSStefano Zampini         const PetscScalar *v;
207451ab8ad6SStefano Zampini         char               name[16];
20751c7a958bSStefano Zampini 
20761c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
2077835f2295SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%" PetscInt_FMT, d));
207851ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
20799566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
208051ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
20819566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
20821c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
20839566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
20841c7a958bSStefano Zampini       }
20859566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
20869566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
20879566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
20889566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
20899566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
209051ab8ad6SStefano Zampini       if (flg) {
209151ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
2092648c30bcSBarry Smith         PetscCall(PetscViewerDestroy(&viewer));
209351ab8ad6SStefano Zampini       }
20941c7a958bSStefano Zampini     }
20951c7a958bSStefano Zampini   }
20963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20977a0e7b2cSstefano_zampini }
20987a0e7b2cSstefano_zampini 
2099d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
2100d71ae5a4SJacob Faibussowitsch {
2101f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
21027a0e7b2cSstefano_zampini   IS              nis;
21037a0e7b2cSstefano_zampini   const PetscInt *idxs;
21047a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
21057a0e7b2cSstefano_zampini 
21067a0e7b2cSstefano_zampini   PetscFunctionBegin;
210757508eceSPierre Jolivet   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
21087a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
21097a0e7b2cSstefano_zampini     /* init rootdata with true */
21101bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
21117a0e7b2cSstefano_zampini   } else {
21129566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
21137a0e7b2cSstefano_zampini   }
21149566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
21159566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
21169566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
21177a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
21189371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
21199566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
21209566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
21219566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
21229566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
21239566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
21247a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
21259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
21267a0e7b2cSstefano_zampini   } else {
21279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
21287a0e7b2cSstefano_zampini   }
21297a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
21309371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
2131f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)*is), nnd, nidxs, PETSC_OWN_POINTER, &nis));
21329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
21337a0e7b2cSstefano_zampini   *is = nis;
21343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21351f4df5f7SStefano Zampini }
21361f4df5f7SStefano Zampini 
2137d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z)
2138d71ae5a4SJacob Faibussowitsch {
2139f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2140f4f49eeaSPierre Jolivet   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
21413e589ea0SStefano Zampini 
21423e589ea0SStefano Zampini   PetscFunctionBegin;
21433ba16761SJacob Faibussowitsch   if (!pcbddc->benign_have_null) PetscFunctionReturn(PETSC_SUCCESS);
21443e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
21453e589ea0SStefano Zampini     Vec swap;
21463e589ea0SStefano Zampini 
21479566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
21483e589ea0SStefano Zampini     swap                = pcbddc->work_change;
21493e589ea0SStefano Zampini     pcbddc->work_change = r;
21503e589ea0SStefano Zampini     r                   = swap;
21513e589ea0SStefano Zampini   }
21529566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
21539566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
21549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
21559566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
21569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
21579566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
21589566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
21599566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
21609566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
21613e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
2162f913dca9SStefano Zampini     pcbddc->work_change = r;
21639566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
21649566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
21653e589ea0SStefano Zampini   }
21663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21673e589ea0SStefano Zampini }
21683e589ea0SStefano Zampini 
2169ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
2170d71ae5a4SJacob Faibussowitsch {
2171a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
2172a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
2173a3df083aSStefano Zampini 
2174a3df083aSStefano Zampini   PetscFunctionBegin;
21759566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
2176a3df083aSStefano Zampini   if (transpose) {
2177a3df083aSStefano Zampini     apply_right = ctx->apply_left;
2178a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
2179a3df083aSStefano Zampini   } else {
2180a3df083aSStefano Zampini     apply_right = ctx->apply_right;
2181a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
2182a3df083aSStefano Zampini   }
2183a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
2184a3df083aSStefano Zampini   if (apply_right) {
2185a3df083aSStefano Zampini     const PetscScalar *ax;
2186a3df083aSStefano Zampini     PetscInt           nl, i;
2187a3df083aSStefano Zampini 
21889566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
21899566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
21909566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
21919566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
2192a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2193a3df083aSStefano Zampini       PetscScalar     sum, val;
2194a3df083aSStefano Zampini       const PetscInt *idxs;
2195a3df083aSStefano Zampini       PetscInt        nz, j;
21969566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
21979566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2198a3df083aSStefano Zampini       sum = 0.;
2199a3df083aSStefano Zampini       if (ctx->apply_p0) {
2200a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
2201a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2202a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
2203a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
2204a3df083aSStefano Zampini         }
2205a3df083aSStefano Zampini       } else {
2206ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) sum += ctx->work[idxs[j]];
2207a3df083aSStefano Zampini       }
2208a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
22099566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2210a3df083aSStefano Zampini     }
22119566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
2212a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
2213a3df083aSStefano Zampini   }
2214a3df083aSStefano Zampini   if (transpose) {
22159566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
2216a3df083aSStefano Zampini   } else {
22179566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
2218a3df083aSStefano Zampini   }
22191baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
2220a3df083aSStefano Zampini   if (apply_left) {
2221a3df083aSStefano Zampini     PetscScalar *ay;
2222a3df083aSStefano Zampini     PetscInt     i;
2223a3df083aSStefano Zampini 
22249566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
2225a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2226a3df083aSStefano Zampini       PetscScalar     sum, val;
2227a3df083aSStefano Zampini       const PetscInt *idxs;
2228a3df083aSStefano Zampini       PetscInt        nz, j;
22299566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
22309566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2231a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
2232a3df083aSStefano Zampini       if (ctx->apply_p0) {
2233a3df083aSStefano Zampini         sum = 0.;
2234a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2235a3df083aSStefano Zampini           sum += ay[idxs[j]];
2236a3df083aSStefano Zampini           ay[idxs[j]] += val;
2237a3df083aSStefano Zampini         }
2238a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
2239a3df083aSStefano Zampini       } else {
2240ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) ay[idxs[j]] += val;
2241a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
2242a3df083aSStefano Zampini       }
22439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2244a3df083aSStefano Zampini     }
22459566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
2246a3df083aSStefano Zampini   }
22473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2248a3df083aSStefano Zampini }
2249a3df083aSStefano Zampini 
2250ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
2251d71ae5a4SJacob Faibussowitsch {
2252a3df083aSStefano Zampini   PetscFunctionBegin;
22539566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
22543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2255a3df083aSStefano Zampini }
2256a3df083aSStefano Zampini 
2257ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
2258d71ae5a4SJacob Faibussowitsch {
2259a3df083aSStefano Zampini   PetscFunctionBegin;
22609566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
22613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2262a3df083aSStefano Zampini }
2263a3df083aSStefano Zampini 
2264d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
2265d71ae5a4SJacob Faibussowitsch {
2266a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
2267a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
2268a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
2269a3df083aSStefano Zampini 
2270a3df083aSStefano Zampini   PetscFunctionBegin;
2271a3df083aSStefano Zampini   if (!restore) {
22721dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
2273a3df083aSStefano Zampini     PetscScalar       *work;
2274b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
2275a3df083aSStefano Zampini 
227628b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
22773ba16761SJacob Faibussowitsch     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(PETSC_SUCCESS);
22789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
22799566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
22809566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
22819566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
228257d50842SBarry Smith     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (PetscErrorCodeFn *)PCBDDCBenignMatMult_Private));
228357d50842SBarry Smith     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (PetscErrorCodeFn *)PCBDDCBenignMatMultTranspose_Private));
22849566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
22859566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
2286a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
2287a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
2288a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
2289a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
2290059032f7SStefano Zampini     if (reuse) {
2291a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
22921dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
2293059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
2294059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
2295059032f7SStefano Zampini       PetscInt               i;
2296059032f7SStefano Zampini 
22979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
22989566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
229948a46eb9SPierre 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]));
23009566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
23011dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
2302059032f7SStefano Zampini     }
2303a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
2304a3df083aSStefano Zampini     ctx->work = work;
23059566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
23069566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
23079566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
2308a3df083aSStefano Zampini     pcis->A_IB = A_IB;
2309a3df083aSStefano Zampini 
2310a3df083aSStefano Zampini     /* A_BI as A_IB^T */
23119566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
2312a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
2313a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
2314a3df083aSStefano Zampini   } else {
23153ba16761SJacob Faibussowitsch     if (!pcbddc->benign_original_mat) PetscFunctionReturn(PETSC_SUCCESS);
23169566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
23179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2318a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
23191dd7afcfSStefano Zampini     ctx->A     = NULL;
23209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
23211dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
23221dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
23231dd7afcfSStefano Zampini     if (ctx->free) {
2324059032f7SStefano Zampini       PetscInt i;
232548a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
23269566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2327059032f7SStefano Zampini     }
23289566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
23299566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2330a3df083aSStefano Zampini   }
23313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2332a3df083aSStefano Zampini }
2333a3df083aSStefano Zampini 
2334a3df083aSStefano Zampini /* used just in bddc debug mode */
2335ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2336d71ae5a4SJacob Faibussowitsch {
2337a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2338a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2339a3df083aSStefano Zampini   Mat      An;
2340a3df083aSStefano Zampini 
2341a3df083aSStefano Zampini   PetscFunctionBegin;
23429566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
23439566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2344a3df083aSStefano Zampini   if (is1) {
23459566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
23469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2347a3df083aSStefano Zampini   } else {
2348a3df083aSStefano Zampini     *B = An;
2349a3df083aSStefano Zampini   }
23503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2351a3df083aSStefano Zampini }
2352a3df083aSStefano Zampini 
23531cf9b237SStefano Zampini /* TODO: add reuse flag */
2354d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2355d71ae5a4SJacob Faibussowitsch {
23561cf9b237SStefano Zampini   Mat             Bt;
23571cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
23581cf9b237SStefano Zampini   const PetscInt *ii, *ij;
23591cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
23601cf9b237SStefano Zampini   PetscBool       flg_row;
23611cf9b237SStefano Zampini 
23621cf9b237SStefano Zampini   PetscFunctionBegin;
23639566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
23649566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
23659566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
23661cf9b237SStefano Zampini   nnz = n;
23671cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
23681cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
23691cf9b237SStefano Zampini   }
23709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
23719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
23729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
23731cf9b237SStefano Zampini   nnz    = 0;
23741cf9b237SStefano Zampini   bii[0] = 0;
23751cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
23761cf9b237SStefano Zampini     PetscInt j;
23771cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
23781cf9b237SStefano Zampini       PetscScalar entry = a[j];
23793272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
23801cf9b237SStefano Zampini         bij[nnz]   = ij[j];
23811cf9b237SStefano Zampini         bdata[nnz] = entry;
23821cf9b237SStefano Zampini         nnz++;
23831cf9b237SStefano Zampini       }
23841cf9b237SStefano Zampini     }
23851cf9b237SStefano Zampini     bii[i + 1] = nnz;
23861cf9b237SStefano Zampini   }
23879566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
23889566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
23899566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
23901cf9b237SStefano Zampini   {
2391f4f49eeaSPierre Jolivet     Mat_SeqAIJ *b = (Mat_SeqAIJ *)Bt->data;
23921cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
23931cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
23941cf9b237SStefano Zampini   }
239548a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
23961cf9b237SStefano Zampini   *B = Bt;
23973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23981cf9b237SStefano Zampini }
23991cf9b237SStefano Zampini 
2400d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv)
2401d71ae5a4SJacob Faibussowitsch {
2402c80a6c00SStefano Zampini   Mat                    B = NULL;
2403c80a6c00SStefano Zampini   DM                     dm;
24044f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
24054f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
24064f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2407c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
24084f1b2e48SStefano Zampini   PetscInt               i, n;
24094f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2410c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
24114f1b2e48SStefano Zampini 
24124f1b2e48SStefano Zampini   PetscFunctionBegin;
2413a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2414a2eca866SStefano Zampini   if (cc) *cc = NULL;
2415a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
24169566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
24179566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
241848a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
2419f9635d15SStefano Zampini   if (dm) PetscCall(PetscObjectTypeCompareAny((PetscObject)dm, &isplex, DMPLEX, DMP4EST, DMP8EST, ""));
24208361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
24218361f951SStefano Zampini 
2422c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2423c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2424c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2425c80a6c00SStefano Zampini     IS              cellNumbering;
2426c80a6c00SStefano Zampini     const PetscInt *cellNum;
2427c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2428c80a6c00SStefano Zampini     PetscSection    section;
2429c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2430c80a6c00SStefano Zampini     PetscSF         sfPoint;
2431c80a6c00SStefano Zampini 
2432f9635d15SStefano Zampini     PetscCall(DMConvert(dm, DMPLEX, &dm));
24339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
24349566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
24359566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2436c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
24379566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
24389566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
24399566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2440c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
24419566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
24429566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
24439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
24449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2445c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2446c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
24479371c9d4SSatish Balay       if (nroots > 0) {
24489371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
24499371c9d4SSatish Balay       }
2450c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
24519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2452c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2453c80a6c00SStefano Zampini         const PetscInt point = adj[a];
24545cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2455c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
24569566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
24579566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2458c80a6c00SStefano Zampini           *pBuf = point;
2459c80a6c00SStefano Zampini         }
2460c80a6c00SStefano Zampini       }
2461c80a6c00SStefano Zampini       n++;
2462c80a6c00SStefano Zampini     }
24639566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2464c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
24659566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
24679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2468c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
24699371c9d4SSatish Balay       if (nroots > 0) {
24709371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
24719371c9d4SSatish Balay       }
2472f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetOffset(section, p, &xadj[idx++]));
2473c80a6c00SStefano Zampini     }
2474c80a6c00SStefano Zampini     xadj[n] = size;
24759566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2476c80a6c00SStefano Zampini     /* Clean up */
24779566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
24789566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
24799566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2480c80a6c00SStefano Zampini     graph->xadj   = xadj;
2481c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2482c80a6c00SStefano Zampini   } else {
2483c80a6c00SStefano Zampini     Mat       A;
24848361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2485c80a6c00SStefano Zampini 
24869566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
248763c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
24889566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
24893ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
249063c961adSStefano Zampini     }
24919566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
24924f1b2e48SStefano Zampini     if (!isseqaij && filter) {
24931cf9b237SStefano Zampini       PetscBool isseqdense;
24941cf9b237SStefano Zampini 
24959566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
24961cf9b237SStefano Zampini       if (!isseqdense) {
24979566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
24981cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
24991cf9b237SStefano Zampini         PetscScalar *array;
25001cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
25011cf9b237SStefano Zampini 
25029566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
25039566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
25049566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
25051cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
25061cf9b237SStefano Zampini           PetscInt j;
25071cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
25081cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
25091cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
25101cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
25111cf9b237SStefano Zampini           }
25121cf9b237SStefano Zampini         }
25139566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
25149566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
25151cf9b237SStefano Zampini       }
25164f1b2e48SStefano Zampini     } else {
25179566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
25184f1b2e48SStefano Zampini       B = A;
25194f1b2e48SStefano Zampini     }
25209566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
25214f1b2e48SStefano Zampini 
25224f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
25234f1b2e48SStefano Zampini     if (filter) {
25244f1b2e48SStefano Zampini       PetscScalar *data;
25254f1b2e48SStefano Zampini       PetscInt     j, cum;
25264f1b2e48SStefano Zampini 
25279566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
25289566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
25294f1b2e48SStefano Zampini       cum = 0;
25304f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
25314f1b2e48SStefano Zampini         PetscInt t;
25324f1b2e48SStefano Zampini 
25334f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
2534ad540459SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) continue;
25354f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
25364f1b2e48SStefano Zampini         }
25374f1b2e48SStefano Zampini         t                = xadj_filtered[i];
25384f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
25394f1b2e48SStefano Zampini         cum += t;
25404f1b2e48SStefano Zampini       }
25419566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
25424f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
25434f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
25444f1b2e48SStefano Zampini     } else {
25454f1b2e48SStefano Zampini       graph->xadj   = xadj;
25464f1b2e48SStefano Zampini       graph->adjncy = adjncy;
25474f1b2e48SStefano Zampini     }
2548c80a6c00SStefano Zampini   }
2549c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
25509de2952eSStefano Zampini   graph->seq_graph = PETSC_TRUE; /* analyze local connected components (i.e. disconnected subdomains) irrespective of dofs count */
25519566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
25529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
25539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
25541690c2aeSBarry Smith   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_INT_MAX));
25559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
25569566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
25579566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2558c80a6c00SStefano Zampini 
25594f1b2e48SStefano Zampini   /* partial clean up */
25609566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2561c80a6c00SStefano Zampini   if (B) {
2562c80a6c00SStefano Zampini     PetscBool flg_row;
25639566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
25649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
25654f1b2e48SStefano Zampini   }
2566c80a6c00SStefano Zampini   if (isplex) {
25679566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
25689566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2569c80a6c00SStefano Zampini   }
25704f1b2e48SStefano Zampini 
25714f1b2e48SStefano Zampini   /* get back data */
2572c80a6c00SStefano Zampini   if (isplex) {
2573c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2574c80a6c00SStefano Zampini     if (cc || primalv) {
2575c80a6c00SStefano Zampini       Mat          A;
2576f9635d15SStefano Zampini       PetscBT      btv, btvt, btvc;
2577c80a6c00SStefano Zampini       PetscSection subSection;
2578c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2579f9635d15SStefano Zampini       PetscInt     dim, cStart, cEnd, fStart, fEnd, vStart, vEnd, pStart, pEnd;
2580c80a6c00SStefano Zampini 
2581f9635d15SStefano Zampini       PetscCall(DMGetDimension(dm, &dim));
25829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
2583f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2584f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2585f9635d15SStefano Zampini       PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2586f9635d15SStefano Zampini       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
25879566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
25889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
25899566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
25909566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2591f9635d15SStefano Zampini       PetscCall(PetscBTCreate(pEnd - pStart, &btvc));
2592f9635d15SStefano Zampini 
2593f9635d15SStefano Zampini       /* First see if we find corners for the subdomains, i.e. a vertex
2594f9635d15SStefano Zampini          shared by at least dim subdomain boundary faces. This does not
2595f9635d15SStefano Zampini          cover all the possible cases with simplices but it is enough
2596f9635d15SStefano Zampini          for tensor cells */
2597f9635d15SStefano Zampini       if (vStart != fStart && dim <= 3) {
2598f9635d15SStefano Zampini         for (PetscInt c = cStart; c < cEnd; c++) {
2599f9635d15SStefano Zampini           PetscInt        nf, cnt = 0, mcnt = dim, *cfaces;
2600f9635d15SStefano Zampini           const PetscInt *faces;
2601f9635d15SStefano Zampini 
2602f9635d15SStefano Zampini           PetscCall(DMPlexGetConeSize(dm, c, &nf));
2603f9635d15SStefano Zampini           PetscCall(DMGetWorkArray(dm, nf, MPIU_INT, &cfaces));
2604f9635d15SStefano Zampini           PetscCall(DMPlexGetCone(dm, c, &faces));
2605f9635d15SStefano Zampini           for (PetscInt f = 0; f < nf; f++) {
2606f9635d15SStefano Zampini             PetscInt nc, ff;
2607f9635d15SStefano Zampini 
2608f9635d15SStefano Zampini             PetscCall(DMPlexGetSupportSize(dm, faces[f], &nc));
2609f9635d15SStefano Zampini             PetscCall(DMPlexGetTreeParent(dm, faces[f], &ff, NULL));
2610f9635d15SStefano Zampini             if (nc == 1 && faces[f] == ff) cfaces[cnt++] = faces[f];
2611f9635d15SStefano Zampini           }
2612f9635d15SStefano Zampini           if (cnt >= mcnt) {
2613f9635d15SStefano Zampini             PetscInt size, *closure = NULL;
2614f9635d15SStefano Zampini 
2615f9635d15SStefano Zampini             PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2616f9635d15SStefano Zampini             for (PetscInt k = 0; k < 2 * size; k += 2) {
2617f9635d15SStefano Zampini               PetscInt v = closure[k];
2618f9635d15SStefano Zampini               if (v >= vStart && v < vEnd) {
2619f9635d15SStefano Zampini                 PetscInt vsize, *vclosure = NULL;
2620f9635d15SStefano Zampini 
2621f9635d15SStefano Zampini                 cnt = 0;
2622f9635d15SStefano Zampini                 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2623f9635d15SStefano Zampini                 for (PetscInt vk = 0; vk < 2 * vsize; vk += 2) {
2624f9635d15SStefano Zampini                   PetscInt f = vclosure[vk];
2625f9635d15SStefano Zampini                   if (f >= fStart && f < fEnd) {
2626f9635d15SStefano Zampini                     PetscInt  nc, ff;
2627f9635d15SStefano Zampini                     PetscBool valid = PETSC_FALSE;
2628f9635d15SStefano Zampini 
2629f9635d15SStefano Zampini                     for (PetscInt fk = 0; fk < nf; fk++)
2630f9635d15SStefano Zampini                       if (f == cfaces[fk]) valid = PETSC_TRUE;
2631f9635d15SStefano Zampini                     if (!valid) continue;
2632f9635d15SStefano Zampini                     PetscCall(DMPlexGetSupportSize(dm, f, &nc));
2633f9635d15SStefano Zampini                     PetscCall(DMPlexGetTreeParent(dm, f, &ff, NULL));
2634f9635d15SStefano Zampini                     if (nc == 1 && f == ff) cnt++;
2635f9635d15SStefano Zampini                   }
2636f9635d15SStefano Zampini                 }
2637f9635d15SStefano Zampini                 if (cnt >= mcnt) PetscCall(PetscBTSet(btvc, v - pStart));
2638f9635d15SStefano Zampini                 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2639f9635d15SStefano Zampini               }
2640f9635d15SStefano Zampini             }
2641f9635d15SStefano Zampini             PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2642f9635d15SStefano Zampini           }
2643f9635d15SStefano Zampini           PetscCall(DMRestoreWorkArray(dm, nf, MPIU_INT, &cfaces));
2644f9635d15SStefano Zampini         }
2645f9635d15SStefano Zampini       }
2646c80a6c00SStefano Zampini 
2647c80a6c00SStefano Zampini       cids[0] = 0;
2648c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2649c80a6c00SStefano Zampini         PetscInt j;
2650c80a6c00SStefano Zampini 
26519566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2652c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2653c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2654c80a6c00SStefano Zampini 
26559566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2656c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
265720c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2658c80a6c00SStefano Zampini 
26599566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
26609566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
26619566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2662c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2663c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2664f9635d15SStefano Zampini               if (PetscBTLookup(btvc, p - pStart)) pids[cump++] = off + s; /* subdomain corner */
2665f9635d15SStefano Zampini               else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2666e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2667c80a6c00SStefano Zampini             }
26689566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
266920c3699dSStefano Zampini             if (pp != p) {
26709566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
26719566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
26729566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
267320c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
267420c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2675f9635d15SStefano Zampini                 if (PetscBTLookup(btvc, pp - pStart)) pids[cump++] = off + s; /* subdomain corner */
2676f9635d15SStefano Zampini                 else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2677e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
267820c3699dSStefano Zampini               }
267920c3699dSStefano Zampini             }
2680c80a6c00SStefano Zampini           }
26819566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2682c80a6c00SStefano Zampini         }
2683c80a6c00SStefano Zampini         cids[i + 1] = cum;
2684c80a6c00SStefano Zampini         /* mark dofs as already assigned */
268548a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2686c80a6c00SStefano Zampini       }
2687c80a6c00SStefano Zampini       if (cc) {
26889566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
268948a46eb9SPierre 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]));
2690c80a6c00SStefano Zampini         *cc = cc_n;
2691c80a6c00SStefano Zampini       }
26921baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
26939566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
26949566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
26959566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2696f9635d15SStefano Zampini       PetscCall(PetscBTDestroy(&btvc));
2697f9635d15SStefano Zampini       PetscCall(DMDestroy(&dm));
2698c80a6c00SStefano Zampini     }
2699c80a6c00SStefano Zampini   } else {
27001cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
27011cf9b237SStefano Zampini     if (cc) {
27029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
270348a46eb9SPierre 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]));
27044f1b2e48SStefano Zampini       *cc = cc_n;
27051cf9b237SStefano Zampini     }
2706c80a6c00SStefano Zampini   }
27074f1b2e48SStefano Zampini   /* clean up graph */
27080a545947SLisandro Dalcin   graph->xadj   = NULL;
27090a545947SLisandro Dalcin   graph->adjncy = NULL;
27109566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
27113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27124f1b2e48SStefano Zampini }
27134f1b2e48SStefano Zampini 
2714d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2715d71ae5a4SJacob Faibussowitsch {
27165408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2717f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2718dee84bffSStefano Zampini   IS       dirIS  = NULL;
27194f1b2e48SStefano Zampini   PetscInt i;
27205408967cSStefano Zampini 
27215408967cSStefano Zampini   PetscFunctionBegin;
27229566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
27235408967cSStefano Zampini   if (zerodiag) {
27245408967cSStefano Zampini     Mat             A;
27255408967cSStefano Zampini     Vec             vec3_N;
27265408967cSStefano Zampini     PetscScalar    *vals;
27275408967cSStefano Zampini     const PetscInt *idxs;
2728d12d3064SStefano Zampini     PetscInt        nz, *count;
27295408967cSStefano Zampini 
27305408967cSStefano Zampini     /* p0 */
27319566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
27329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
27339566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
27349566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
27354f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
27369566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
27379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
27389566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
27395408967cSStefano Zampini     /* v_I */
27409566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
27415408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
27429566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
27439566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
27449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
27455408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
27469566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
27479566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
27485408967cSStefano Zampini     if (dirIS) {
27495408967cSStefano Zampini       PetscInt n;
27505408967cSStefano Zampini 
27519566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
27529566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
27535408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
27549566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
27559566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
27565408967cSStefano Zampini     }
27579566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
27589566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
27599566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
27609566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
27619566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
27629566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
27639566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
27647827d75bSBarry 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]));
27659566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
27669566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2767d12d3064SStefano Zampini 
2768d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
27699566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
27709566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2771d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
27729566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
27739566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
277463a3b9bcSJacob 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]);
27759566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
27769566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
27775408967cSStefano Zampini   }
27789566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
27795408967cSStefano Zampini 
27805408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
27819566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
27824f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
27839566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
27844f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
27859566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2786f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2787f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
278863a3b9bcSJacob 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));
2789f2a566d8SStefano Zampini   }
27903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27915408967cSStefano Zampini }
27925408967cSStefano Zampini 
2793d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal)
2794d71ae5a4SJacob Faibussowitsch {
2795339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2796f4f49eeaSPierre Jolivet   Mat_IS   *matis     = (Mat_IS *)pc->pmat->data;
27973b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
27983b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
27994edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
28004edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2801339f8db1SStefano Zampini 
2802339f8db1SStefano Zampini   PetscFunctionBegin;
28033b03f7bbSStefano Zampini   if (reuse) goto project_b0;
28049566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
28059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
280648a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
28079566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
28083b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
28093b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
28103b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
28113b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
28124f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
28134f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
28141ae86dd6SStefano Zampini      since the local Schur complements are already SPD
28154f1b2e48SStefano Zampini   */
281640fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
28177fbe2174Sstefano_zampini     IS        iP = NULL;
28183b03f7bbSStefano Zampini     PetscInt  p, *pp;
281947c5ace7SStefano Zampini     PetscBool flg, blocked = PETSC_FALSE;
28204f1b2e48SStefano Zampini 
28219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
28223b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2823d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
28249566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
282547c5ace7SStefano Zampini     PetscCall(PetscOptionsBool("-pc_bddc_pressure_blocked", "Use blocked pressure fields", NULL, blocked, &blocked, NULL));
2826d0609cedSBarry Smith     PetscOptionsEnd();
28273b03f7bbSStefano Zampini     if (!flg) {
28283b03f7bbSStefano Zampini       n     = 1;
28293b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
28303b03f7bbSStefano Zampini     }
28313b03f7bbSStefano Zampini 
28323b03f7bbSStefano Zampini     bsp = 0;
28333b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
283447c5ace7SStefano Zampini       PetscInt bs = 1;
28353b03f7bbSStefano Zampini 
283663a3b9bcSJacob 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]);
283747c5ace7SStefano Zampini       if (blocked) PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
28383b03f7bbSStefano Zampini       bsp += bs;
28393b03f7bbSStefano Zampini     }
28409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
28413b03f7bbSStefano Zampini     bsp = 0;
28423b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
28433b03f7bbSStefano Zampini       const PetscInt *idxs;
284447c5ace7SStefano Zampini       PetscInt        b, bs = 1, npl, *bidxs;
28453b03f7bbSStefano Zampini 
284647c5ace7SStefano Zampini       if (blocked) PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
28479566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
28489566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
28499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
28503b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
28513b03f7bbSStefano Zampini         PetscInt i;
28523b03f7bbSStefano Zampini 
28533b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
28549566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
28553b03f7bbSStefano Zampini         bsp++;
28563b03f7bbSStefano Zampini       }
28579566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
28589566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
28593b03f7bbSStefano Zampini     }
28609566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
28613b03f7bbSStefano Zampini 
28627fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
28639566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
28647fbe2174Sstefano_zampini     if (iP) {
28657fbe2174Sstefano_zampini       IS newpressures;
28667fbe2174Sstefano_zampini 
28679566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
28689566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
28697fbe2174Sstefano_zampini       pressures = newpressures;
28707fbe2174Sstefano_zampini     }
28719566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
287248a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
28739566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
287440fa8d13SStefano Zampini   }
28753b03f7bbSStefano Zampini 
287697d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
28779566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
287827b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
28799566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
28809566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
288148a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
28829566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
28834edc6404Sstefano_zampini   zerodiag_save = zerodiag;
28849566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
28854f1b2e48SStefano Zampini   if (!nz) {
28864f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
28874f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
28889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
288940fa8d13SStefano Zampini   }
28904f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
28913b03f7bbSStefano Zampini 
28924f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
28934f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
28943b03f7bbSStefano Zampini   benign_n        = 0;
28951f4df5f7SStefano Zampini   n_interior_dofs = 0;
28961f4df5f7SStefano Zampini   interior_dofs   = NULL;
28974edc6404Sstefano_zampini   nneu            = 0;
289848a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
28993369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
29004edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
29019de2952eSStefano Zampini     PetscInt               n, i;
29029de2952eSStefano Zampini     PetscInt              *count;
29039de2952eSStefano Zampini     ISLocalToGlobalMapping mapping;
29041f4df5f7SStefano Zampini 
29059de2952eSStefano Zampini     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &mapping, NULL));
29069de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(mapping, &n, &count, NULL));
29079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
29081f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
29099de2952eSStefano Zampini       if (count[i] < 2) interior_dofs[n_interior_dofs++] = i;
29109de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(mapping, &n, &count, NULL));
29111f4df5f7SStefano Zampini   }
29124f1b2e48SStefano Zampini   if (has_null_pressures) {
29134f1b2e48SStefano Zampini     IS             *subs;
29144edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
29151f4df5f7SStefano Zampini     const PetscInt *idxs;
29161f4df5f7SStefano Zampini     PetscScalar    *array;
29171f4df5f7SStefano Zampini     Vec            *work;
29184f1b2e48SStefano Zampini 
29194f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
29204f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
29211f4df5f7SStefano 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) */
29224edc6404Sstefano_zampini     if (checkb) {
29239566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
29249566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
29259566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
29261f4df5f7SStefano Zampini       /* work[0] = 1_p */
29279566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
29289566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
29291f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
29309566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
29311f4df5f7SStefano Zampini       /* work[0] = 1_v */
29329566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
29339566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
29341f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
29359566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
29369566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
29371f4df5f7SStefano Zampini     }
29383b03f7bbSStefano Zampini 
29393b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
29403b03f7bbSStefano Zampini       IS      *is;
29413b03f7bbSStefano Zampini       PetscInt b, totb;
29423b03f7bbSStefano Zampini 
29433b03f7bbSStefano Zampini       totb  = bsp;
29443b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
29453b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
29469566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
29473b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
29484f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
29494f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
29504f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
29514f1b2e48SStefano Zampini           PetscInt               nl;
29524f1b2e48SStefano Zampini 
29533b03f7bbSStefano Zampini           if (subs) {
29549566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
29553b03f7bbSStefano Zampini           } else {
29563b03f7bbSStefano Zampini             IS tis;
29573b03f7bbSStefano Zampini 
29589566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
29599566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
29609566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
29619566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
29623b03f7bbSStefano Zampini           }
29639566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
29649566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
29654f1b2e48SStefano Zampini           if (nl) {
29664f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
29674f1b2e48SStefano Zampini 
29684edc6404Sstefano_zampini             if (checkb) {
29699566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
29709566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
29719566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
29729566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
29731f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
29749566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
29759566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
29769566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
29779566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
29789566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
29799566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
29801f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
29811f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
29821f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
29831f4df5f7SStefano Zampini                   break;
29841f4df5f7SStefano Zampini                 }
29851f4df5f7SStefano Zampini               }
29869566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
29871f4df5f7SStefano Zampini             }
29886632bad2Sstefano_zampini             if (valid && nneu) {
29896632bad2Sstefano_zampini               const PetscInt *idxs;
29901f4df5f7SStefano Zampini               PetscInt        nzb;
29911f4df5f7SStefano Zampini 
29929566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
29939566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
29949566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
29951f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
29961f4df5f7SStefano Zampini             }
29971f4df5f7SStefano Zampini             if (valid && pressures) {
29983b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
29993b03f7bbSStefano Zampini               PetscInt i1, i2;
30003b03f7bbSStefano Zampini 
30019566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
30029566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
30039566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
30049566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
30053b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
30069566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
30079566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
30084f1b2e48SStefano Zampini             }
30094f1b2e48SStefano Zampini             if (valid) {
30109566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
30113b03f7bbSStefano Zampini               benign_n++;
30123b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
30134f1b2e48SStefano Zampini           }
30149566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
30159566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
30164f1b2e48SStefano Zampini         }
30173b03f7bbSStefano Zampini       }
30184f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
30194f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
30201f4df5f7SStefano Zampini 
30216632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
302248a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
30234edc6404Sstefano_zampini       if (valid && checkb) {
30249566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
30259566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
30269566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
30271f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
30281f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
30291f4df5f7SStefano Zampini             valid = PETSC_FALSE;
30301f4df5f7SStefano Zampini             break;
30311f4df5f7SStefano Zampini           }
30321f4df5f7SStefano Zampini         }
30339566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
30341f4df5f7SStefano Zampini       }
30354f1b2e48SStefano Zampini       if (valid) {
30363b03f7bbSStefano Zampini         benign_n = 1;
30379566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
30389566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
30394f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
30404f1b2e48SStefano Zampini       }
30414f1b2e48SStefano Zampini     }
304248a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
30431f4df5f7SStefano Zampini   }
30449566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
30454f1b2e48SStefano Zampini 
30463b03f7bbSStefano Zampini   if (!benign_n) {
3047b9b0e38cSStefano Zampini     PetscInt n;
3048b9b0e38cSStefano Zampini 
30499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
30504f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
30519566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
305276a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
3053b9b0e38cSStefano Zampini   }
30544f1b2e48SStefano Zampini 
30554f1b2e48SStefano Zampini   /* final check for null pressures */
305648a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
30574f1b2e48SStefano Zampini 
30584f1b2e48SStefano Zampini   if (recompute_zerodiag) {
30599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
30603b03f7bbSStefano Zampini     if (benign_n == 1) {
30619566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
30624f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
30634f1b2e48SStefano Zampini     } else {
30644f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
30654f1b2e48SStefano Zampini 
30664f1b2e48SStefano Zampini       nzn = 0;
30673b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
30684f1b2e48SStefano Zampini         PetscInt ns;
30699566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
30704f1b2e48SStefano Zampini         nzn += ns;
30714f1b2e48SStefano Zampini       }
30729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
30734f1b2e48SStefano Zampini       nzn = 0;
30743b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
30754f1b2e48SStefano Zampini         PetscInt ns, *idxs;
30769566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
30779566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
30789566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
30799566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
30804f1b2e48SStefano Zampini         nzn += ns;
30814f1b2e48SStefano Zampini       }
30829566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
30839566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
30844f1b2e48SStefano Zampini     }
30854f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
30864f1b2e48SStefano Zampini   }
30874f1b2e48SStefano Zampini 
30883b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
30895440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
30903b03f7bbSStefano Zampini 
3091669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
3092a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
3093a198735bSStefano Zampini     Mat                    A, loc_divudotp;
3094a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
3095a198735bSStefano Zampini     IS                     row, col, isused = NULL;
3096a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
3097a198735bSStefano Zampini 
30981f4df5f7SStefano Zampini     if (pressures) {
30991f4df5f7SStefano Zampini       isused = pressures;
31001f4df5f7SStefano Zampini     } else {
31014edc6404Sstefano_zampini       isused = zerodiag_save;
31021f4df5f7SStefano Zampini     }
31039566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
31049566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
31059566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
31067827d75bSBarry 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");
3107a198735bSStefano Zampini     n_isused = 0;
310848a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
31099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
3110a198735bSStefano Zampini     st = st - n_isused;
31111ae86dd6SStefano Zampini     if (n) {
3112a198735bSStefano Zampini       const PetscInt *gidxs;
3113a198735bSStefano Zampini 
31149566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
31159566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
3116a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
31179566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
31189566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
31199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
31201ae86dd6SStefano Zampini     } else {
31219566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
31229566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
31239566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
3124a198735bSStefano Zampini     }
31259566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
31269566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
31279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
31289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
31299566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
31309566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
31319566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
31329566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
31339566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
31349566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
31359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
31369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
31379566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
31389566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
31399566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
31409566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
31411ae86dd6SStefano Zampini   }
31429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
31439566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
31443b03f7bbSStefano Zampini   if (bzerodiag) {
31453b03f7bbSStefano Zampini     PetscInt i;
3146b3afcdbeSStefano Zampini 
314748a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
31489566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
31493b03f7bbSStefano Zampini   }
31503b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
31513b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
31523b03f7bbSStefano Zampini 
31533b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
31543b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
31555440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
31563b03f7bbSStefano Zampini 
31573b03f7bbSStefano Zampini project_b0:
31589566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
3159b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
31603b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
31614f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
31624f1b2e48SStefano Zampini 
3163339f8db1SStefano Zampini     /* local change of basis for pressures */
31649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
31659566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
31669566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
31679566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
31689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
3169aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
31704f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
3171aa0d93e9SStefano Zampini       const PetscInt *idxs;
31724f1b2e48SStefano Zampini       PetscInt        nzs, j;
31734f1b2e48SStefano Zampini 
31749566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
31759566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
31764f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
31774f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
31789566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
31794f1b2e48SStefano Zampini     }
31809566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
31819566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
31829566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
3183aa0d93e9SStefano Zampini     /* set identity by default */
318448a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
31859566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
31869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
3187339f8db1SStefano Zampini     /* set change on pressures */
31884f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
31894f1b2e48SStefano Zampini       PetscScalar    *array;
3190aa0d93e9SStefano Zampini       const PetscInt *idxs;
31914f1b2e48SStefano Zampini       PetscInt        nzs;
31924f1b2e48SStefano Zampini 
31939566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
31949566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
31954f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
3196339f8db1SStefano Zampini         PetscScalar vals[2];
3197339f8db1SStefano Zampini         PetscInt    cols[2];
3198339f8db1SStefano Zampini 
3199339f8db1SStefano Zampini         cols[0] = idxs[i];
32004f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
3201339f8db1SStefano Zampini         vals[0] = 1.;
3202b0f5fe93SStefano Zampini         vals[1] = 1.;
32039566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
3204339f8db1SStefano Zampini       }
32059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
32064f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
32074f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
32089566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
32094f1b2e48SStefano Zampini       /* store local idxs for p0 */
32104f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
32119566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
32129566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
32134f1b2e48SStefano Zampini     }
32149566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
32159566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
32163b03f7bbSStefano Zampini 
3217a3df083aSStefano Zampini     /* project if needed */
3218a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
32191dd7afcfSStefano Zampini       Mat M;
32201dd7afcfSStefano Zampini 
32219566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
32229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
32239566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
32249566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
3225a3df083aSStefano Zampini     }
32264f1b2e48SStefano Zampini     /* store global idxs for p0 */
32279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
3228339f8db1SStefano Zampini   }
3229339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
32303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3231339f8db1SStefano Zampini }
3232339f8db1SStefano Zampini 
3233d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
3234d71ae5a4SJacob Faibussowitsch {
3235efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
3236de9d7bd0SStefano Zampini   PetscScalar *array;
3237efc2fbd9SStefano Zampini 
3238efc2fbd9SStefano Zampini   PetscFunctionBegin;
3239efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
32409566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
32419566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
3242efc2fbd9SStefano Zampini   }
3243de9d7bd0SStefano Zampini   if (get) {
32449566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
32459566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
32469566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
32479566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
3248de9d7bd0SStefano Zampini   } else {
32499566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
32509566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
32519566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
32529566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
3253efc2fbd9SStefano Zampini   }
32543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3255efc2fbd9SStefano Zampini }
3256efc2fbd9SStefano Zampini 
3257d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
3258d71ae5a4SJacob Faibussowitsch {
3259c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3260c263805aSStefano Zampini 
3261c263805aSStefano Zampini   PetscFunctionBegin;
3262c263805aSStefano Zampini   /* TODO: add error checking
3263c263805aSStefano Zampini     - avoid nested pop (or push) calls.
3264c263805aSStefano Zampini     - cannot push before pop.
32651c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
3266c263805aSStefano Zampini   */
32673ba16761SJacob Faibussowitsch   if (!pcbddc->benign_n) PetscFunctionReturn(PETSC_SUCCESS);
3268c263805aSStefano Zampini   if (pop) {
3269a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
32704f1b2e48SStefano Zampini       IS       is_p0;
32714f1b2e48SStefano Zampini       MatReuse reuse;
3272c263805aSStefano Zampini 
3273c263805aSStefano Zampini       /* extract B_0 */
32744f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
3275ad540459SPierre Jolivet       if (pcbddc->benign_B0) reuse = MAT_REUSE_MATRIX;
32769566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
32779566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
3278c263805aSStefano Zampini       /* remove rows and cols from local problem */
32799566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
32809566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
32819566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
32829566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
3283a3df083aSStefano Zampini     } else {
3284a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
3285a3df083aSStefano Zampini       PetscScalar *vals;
3286a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
3287a3df083aSStefano Zampini 
32889566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
32899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
3290a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
32910b5adadeSStefano Zampini         PetscInt *nnz;
32929566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
32939566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
32949566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
32959566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
3296331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
32979566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
3298331e053bSStefano Zampini           nnz[i] = n - nnz[i];
3299331e053bSStefano Zampini         }
33009566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
33019566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
33029566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
3303331e053bSStefano Zampini       }
3304a3df083aSStefano Zampini 
3305a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
3306a3df083aSStefano Zampini         PetscScalar *array;
3307a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
3308a3df083aSStefano Zampini 
33099566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
33109566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
33119566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3312a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
33139566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
33149566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
33159566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
33169566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
33179566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
33189566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
3319a3df083aSStefano Zampini         cum = 0;
3320a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
332122db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
3322a3df083aSStefano Zampini             vals[cum]     = array[j];
3323a3df083aSStefano Zampini             idxs_ins[cum] = j;
3324a3df083aSStefano Zampini             cum++;
3325a3df083aSStefano Zampini           }
3326a3df083aSStefano Zampini         }
33279566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
33289566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
33299566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3330a3df083aSStefano Zampini       }
33319566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
33329566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
33339566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
3334a3df083aSStefano Zampini     }
3335c263805aSStefano Zampini   } else { /* push */
33364f1b2e48SStefano Zampini 
33370fdf79fbSJacob Faibussowitsch     PetscCheck(pcbddc->benign_change_explicit, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
33380fdf79fbSJacob Faibussowitsch     for (PetscInt i = 0; i < pcbddc->benign_n; i++) {
33394f1b2e48SStefano Zampini       PetscScalar *B0_vals;
33404f1b2e48SStefano Zampini       PetscInt    *B0_cols, B0_ncol;
33414f1b2e48SStefano Zampini 
33429566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
33439566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
33449566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
33459566063dSJacob Faibussowitsch       PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
33469566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
33474f1b2e48SStefano Zampini     }
33489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
33499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
3350c263805aSStefano Zampini   }
33513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3352c263805aSStefano Zampini }
3353c263805aSStefano Zampini 
3354d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
3355d71ae5a4SJacob Faibussowitsch {
3356b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
335708122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
335897b17b2cSPierre Jolivet   PetscBLASInt    B_neigs, B_ierr, B_lwork;
335908122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
336008122e43SStefano Zampini   PetscScalar    *work, lwork;
336108122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
336208122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
3363bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
33641b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
336532fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
336608122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
336708122e43SStefano Zampini   PetscReal *rwork;
336808122e43SStefano Zampini #endif
3369b1b3d7a2SStefano Zampini 
3370b1b3d7a2SStefano Zampini   PetscFunctionBegin;
33713ba16761SJacob Faibussowitsch   if (!pcbddc->adaptive_selection) PetscFunctionReturn(PETSC_SUCCESS);
337228b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
337332fe681dSStefano 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");
33749371c9d4SSatish 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,
33759371c9d4SSatish Balay              sub_schurs->is_posdef);
33769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
337706a4e24aSStefano Zampini 
3378fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
337932fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
33809566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
33819566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
33829566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
33839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
3384fd14bc51SStefano Zampini   }
3385fd14bc51SStefano Zampini 
338648a46eb9SPierre 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));
3387e496cd5dSStefano Zampini 
338808122e43SStefano Zampini   /* max size of subsets */
338908122e43SStefano Zampini   mss = 0;
339008122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
339108122e43SStefano Zampini     PetscInt subset_size;
3392862806e4SStefano Zampini 
33939566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
339408122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
339508122e43SStefano Zampini   }
339608122e43SStefano Zampini 
339708122e43SStefano Zampini   /* min/max and threshold */
339808122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3399f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
340008122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3401f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3402bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3403f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3404f6f667cfSStefano Zampini   }
340508122e43SStefano Zampini 
340608122e43SStefano Zampini   /* allocate lapack workspace */
340708122e43SStefano Zampini   cum = cum2 = 0;
340808122e43SStefano Zampini   maxneigs   = 0;
340908122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
341008122e43SStefano Zampini     PetscInt n, subset_size;
3411f6f667cfSStefano Zampini 
34129566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
341308122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
34149162d606SStefano Zampini     cum += subset_size;
34159162d606SStefano Zampini     cum2 += subset_size * n;
341608122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
341708122e43SStefano Zampini   }
34187ebab0bbSStefano Zampini   lwork = 0;
341908122e43SStefano Zampini   if (mss) {
34207ebab0bbSStefano Zampini     PetscScalar  sdummy  = 0.;
342108122e43SStefano Zampini     PetscBLASInt B_itype = 1;
34226497c311SBarry Smith     PetscBLASInt B_N, idummy = 0;
34237ebab0bbSStefano Zampini     PetscReal    rdummy = 0., zero = 0.0;
34244c6709b3SStefano Zampini     PetscReal    eps = 0.0; /* dlamch? */
342508122e43SStefano Zampini 
34260fdf79fbSJacob Faibussowitsch     PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
34276497c311SBarry Smith     PetscCall(PetscBLASIntCast(mss, &B_N));
342808122e43SStefano Zampini     B_lwork = -1;
34297ebab0bbSStefano Zampini     /* some implementations may complain about NULL pointers, even if we are querying */
34307ebab0bbSStefano Zampini     S       = &sdummy;
34317ebab0bbSStefano Zampini     St      = &sdummy;
34327ebab0bbSStefano Zampini     eigs    = &rdummy;
34337ebab0bbSStefano Zampini     eigv    = &sdummy;
34347ebab0bbSStefano Zampini     B_iwork = &idummy;
34357ebab0bbSStefano Zampini     B_ifail = &idummy;
3436d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
34377ebab0bbSStefano Zampini     rwork = &rdummy;
3438d1710679SStefano Zampini #endif
34398bec7fa6SStefano Zampini     thresh = 1.0;
34409566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
344108122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
344297b17b2cSPierre Jolivet     PetscCallBLAS("LAPACKsygvx", LAPACKsygvx_(&B_itype, "V", "V", "L", &B_N, St, &B_N, S, &B_N, &zero, &thresh, B_iwork, B_iwork, &eps, &B_neigs, eigs, eigv, &B_N, &lwork, &B_lwork, rwork, B_iwork, B_ifail, &B_ierr));
344308122e43SStefano Zampini #else
344497b17b2cSPierre Jolivet     PetscCallBLAS("LAPACKsygvx", LAPACKsygvx_(&B_itype, "V", "V", "L", &B_N, St, &B_N, S, &B_N, &zero, &thresh, B_iwork, B_iwork, &eps, &B_neigs, eigs, eigv, &B_N, &lwork, &B_lwork, B_iwork, B_ifail, &B_ierr));
344508122e43SStefano Zampini #endif
3446835f2295SStefano Zampini     PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %" PetscBLASInt_FMT, B_ierr);
34479566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
344808122e43SStefano Zampini   }
344908122e43SStefano Zampini 
345008122e43SStefano Zampini   nv = 0;
3451d62866d3SStefano 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) */
34529566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
345308122e43SStefano Zampini   }
34549566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
345548a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
34569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
345708122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
34589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
345908122e43SStefano Zampini #endif
34609371c9d4SSatish 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,
34619371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
34629566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
346308122e43SStefano Zampini 
346408122e43SStefano Zampini   maxneigs = 0;
346572b8c272SStefano Zampini   cum = cumarray                           = 0;
34669162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
34679162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3468d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
346908122e43SStefano Zampini     const PetscInt *idxs;
347008122e43SStefano Zampini 
34719566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
347208122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
347308122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
347408122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
347508122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
34769162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
34779162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
347808122e43SStefano Zampini     }
34799566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
348008122e43SStefano Zampini   }
348108122e43SStefano Zampini 
348208122e43SStefano Zampini   if (mss) { /* multilevel */
348332fe681dSStefano Zampini     if (sub_schurs->gdsw) {
348432fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
348532fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
348632fe681dSStefano Zampini     } else {
34879566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
34889566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
348908122e43SStefano Zampini     }
349032fe681dSStefano Zampini   }
349108122e43SStefano Zampini 
3492bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3493bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
349432fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
349508122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
349608122e43SStefano Zampini     const PetscInt *idxs;
34979d54b7f4SStefano Zampini     PetscReal       upper, lower;
3498862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
349908122e43SStefano Zampini     PetscBLASInt    B_N;
3500aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3501bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
350208122e43SStefano Zampini 
350332fe681dSStefano Zampini     if (upart) {
35049d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3505bd2a564bSStefano Zampini       lower = uthresh;
35069d54b7f4SStefano Zampini     } else {
350732fe681dSStefano Zampini       if (sub_schurs->gdsw) {
350832fe681dSStefano Zampini         upper = uthresh;
350932fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
351032fe681dSStefano Zampini       } else {
351128b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3512bd2a564bSStefano Zampini         upper = 1. / uthresh;
35139d54b7f4SStefano Zampini         lower = 0.;
35149d54b7f4SStefano Zampini       }
351532fe681dSStefano Zampini     }
35169566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
35179566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
35189566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3519bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3520bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3521bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3522bd2a564bSStefano Zampini       Mat T;
3523bd2a564bSStefano Zampini 
3524bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3525bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
35269566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
35279566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
35289566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
35299566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
35309566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
35319566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3532bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3533bd2a564bSStefano Zampini             PetscInt        nz, k;
3534bd2a564bSStefano Zampini             const PetscInt *idxs;
3535bd2a564bSStefano Zampini 
35369566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
35379566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3538bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3539bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3540bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3541bd2a564bSStefano Zampini             }
35429566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3543bd2a564bSStefano Zampini           }
3544bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3545bd2a564bSStefano Zampini           break;
3546bd2a564bSStefano Zampini         }
3547bd2a564bSStefano Zampini       }
3548bd2a564bSStefano Zampini     }
3549bd2a564bSStefano Zampini 
3550f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3551bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3552aff50787SStefano Zampini         PetscInt j, k;
3553580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
35549566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
35559566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
355608122e43SStefano Zampini         }
355708122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3558aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3559aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3560aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3561aff50787SStefano Zampini           }
356208122e43SStefano Zampini         }
356308122e43SStefano Zampini       } else {
35649566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35659566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
356608122e43SStefano Zampini       }
35678bec7fa6SStefano Zampini     } else {
3568f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3569f6f667cfSStefano Zampini       St = Starray + cumarray;
35708bec7fa6SStefano Zampini     }
3571aff50787SStefano Zampini     /* see if we can save some work */
357248a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3573aff50787SStefano Zampini 
3574b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3575aff50787SStefano Zampini       B_neigs = 0;
3576aff50787SStefano Zampini     } else {
357797b17b2cSPierre Jolivet       PetscBLASInt B_itype = 1, B_IL = 1, B_IU = 0;
35784c6709b3SStefano Zampini       PetscReal    eps = -1.0; /* dlamch? */
35799552c7c7SStefano Zampini       PetscInt     nmin_s;
3580bd2a564bSStefano Zampini       PetscBool    compute_range;
3581bd2a564bSStefano Zampini 
35820fdf79fbSJacob Faibussowitsch       PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
35839036ceccSStefano Zampini       B_neigs       = 0;
3584bd2a564bSStefano Zampini       compute_range = (PetscBool)!same_data;
3585bd2a564bSStefano Zampini       if (nmin >= subset_size) compute_range = PETSC_FALSE;
358608122e43SStefano Zampini 
3587fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
3588a4cdd7efSStefano Zampini         PetscInt nc = 0, c = pcbddc->mat_graph->nodes[idxs[0]].count, w = pcbddc->mat_graph->nodes[idxs[0]].which_dof;
3589d16cbb6bSStefano Zampini 
359048a46eb9SPierre Jolivet         if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
35919de2952eSStefano Zampini         PetscCall(
35929de2952eSStefano 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));
3593b7ab4a40SStefano Zampini       }
3594b7ab4a40SStefano Zampini 
35959566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3596b7ab4a40SStefano Zampini       if (compute_range) {
3597d16cbb6bSStefano Zampini         /* ask for eigenvalues larger than thresh */
3598bd2a564bSStefano Zampini         if (sub_schurs->is_posdef) {
359908122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3600792fecdfSBarry 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));
360108122e43SStefano Zampini #else
3602792fecdfSBarry 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));
360308122e43SStefano Zampini #endif
36049566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3605bd2a564bSStefano Zampini         } else { /* no theory so far, but it works nicely */
36069036ceccSStefano Zampini           PetscInt  recipe = 0, recipe_m = 1;
3607bd2a564bSStefano Zampini           PetscReal bb[2];
3608bd2a564bSStefano Zampini 
36099566063dSJacob Faibussowitsch           PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3610bd2a564bSStefano Zampini           switch (recipe) {
3611bd2a564bSStefano Zampini           case 0:
36129371c9d4SSatish Balay             if (scal) {
36139371c9d4SSatish Balay               bb[0] = PETSC_MIN_REAL;
36149371c9d4SSatish Balay               bb[1] = lthresh;
36159371c9d4SSatish Balay             } else {
36169371c9d4SSatish Balay               bb[0] = uthresh;
36179371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
36189371c9d4SSatish Balay             }
3619bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3620792fecdfSBarry 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));
3621bd2a564bSStefano Zampini #else
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_neigs, eigs, eigv, &B_N, work, &B_lwork, B_iwork, B_ifail, &B_ierr));
3623bd2a564bSStefano Zampini #endif
36249566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3625bd2a564bSStefano Zampini             break;
3626d71ae5a4SJacob Faibussowitsch           case 1:
3627d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3628d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh * lthresh;
3629bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3630792fecdfSBarry 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));
3631bd2a564bSStefano Zampini #else
3632792fecdfSBarry 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));
3633bd2a564bSStefano Zampini #endif
36349566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3635bd2a564bSStefano Zampini             if (!scal) {
36369036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
3637bd2a564bSStefano Zampini 
36389371c9d4SSatish Balay               bb[0] = PetscMax(lthresh * lthresh, uthresh);
36399371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
36409566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
36419566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3642bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3643792fecdfSBarry 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));
3644bd2a564bSStefano Zampini #else
3645792fecdfSBarry 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));
3646bd2a564bSStefano Zampini #endif
36479566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3648bd2a564bSStefano Zampini               B_neigs += B_neigs2;
3649bd2a564bSStefano Zampini             }
3650bd2a564bSStefano Zampini             break;
36519036ceccSStefano Zampini           case 2:
36529036ceccSStefano Zampini             if (scal) {
36539036ceccSStefano Zampini               bb[0] = PETSC_MIN_REAL;
36549036ceccSStefano Zampini               bb[1] = 0;
36559036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3656792fecdfSBarry 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));
36579036ceccSStefano Zampini #else
3658792fecdfSBarry 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));
36599036ceccSStefano Zampini #endif
36609566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
36619036ceccSStefano Zampini             } else {
36629036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
366313bcc0bdSJacob Faibussowitsch               PetscBool    do_copy  = PETSC_FALSE;
36649036ceccSStefano Zampini 
36659036ceccSStefano Zampini               lthresh = PetscMax(lthresh, 0.0);
36669036ceccSStefano Zampini               if (lthresh > 0.0) {
36679036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
36689036ceccSStefano Zampini                 bb[1] = lthresh * lthresh;
36699036ceccSStefano Zampini 
367013bcc0bdSJacob Faibussowitsch                 do_copy = PETSC_TRUE;
36719036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3672792fecdfSBarry 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));
36739036ceccSStefano Zampini #else
3674792fecdfSBarry 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));
36759036ceccSStefano Zampini #endif
36769566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
36779036ceccSStefano Zampini               }
36789036ceccSStefano Zampini               bb[0] = PetscMax(lthresh * lthresh, uthresh);
36799036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
368013bcc0bdSJacob Faibussowitsch               if (do_copy) {
36819566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
36829566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
36839036ceccSStefano Zampini               }
36849036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3685792fecdfSBarry 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));
36869036ceccSStefano Zampini #else
3687792fecdfSBarry 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));
36889036ceccSStefano Zampini #endif
36899566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
36909036ceccSStefano Zampini               B_neigs += B_neigs2;
36919036ceccSStefano Zampini             }
36929036ceccSStefano Zampini             break;
36939036ceccSStefano Zampini           case 3:
36949036ceccSStefano Zampini             if (scal) {
36959566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
36969036ceccSStefano Zampini             } else {
36979566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
36989036ceccSStefano Zampini             }
36999036ceccSStefano Zampini             if (!scal) {
37009036ceccSStefano Zampini               bb[0] = uthresh;
37019036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
37029036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3703792fecdfSBarry 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));
37049036ceccSStefano Zampini #else
3705792fecdfSBarry 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));
37069036ceccSStefano Zampini #endif
37079566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
37089036ceccSStefano Zampini             }
37099036ceccSStefano Zampini             if (recipe_m > 0 && B_N - B_neigs > 0) {
37109036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
37119036ceccSStefano Zampini 
37129566063dSJacob Faibussowitsch               PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
37139566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
37149566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
37159036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3716792fecdfSBarry 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));
37179036ceccSStefano Zampini #else
3718792fecdfSBarry 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));
37199036ceccSStefano Zampini #endif
37209566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
37219036ceccSStefano Zampini               B_neigs += B_neigs2;
37229036ceccSStefano Zampini             }
37239036ceccSStefano Zampini             break;
3724d71ae5a4SJacob Faibussowitsch           case 4:
3725d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3726d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh;
372748cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3728792fecdfSBarry 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));
372948cebe81SStefano Zampini #else
3730792fecdfSBarry 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));
373148cebe81SStefano Zampini #endif
37329566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
373348cebe81SStefano Zampini             {
373448cebe81SStefano Zampini               PetscBLASInt B_neigs2 = 0;
373548cebe81SStefano Zampini 
37369371c9d4SSatish Balay               bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
37379371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
37389566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
37399566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
374048cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3741792fecdfSBarry 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));
374248cebe81SStefano Zampini #else
3743792fecdfSBarry 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));
374448cebe81SStefano Zampini #endif
37459566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
374648cebe81SStefano Zampini               B_neigs += B_neigs2;
374748cebe81SStefano Zampini             }
374848cebe81SStefano Zampini             break;
374980db8efeSStefano Zampini           case 5: /* same as before: first compute all eigenvalues, then filter */
375080db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3751792fecdfSBarry 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));
375280db8efeSStefano Zampini #else
3753792fecdfSBarry 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));
375480db8efeSStefano Zampini #endif
37559566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
375680db8efeSStefano Zampini             {
375780db8efeSStefano Zampini               PetscInt e, k, ne;
375880db8efeSStefano Zampini               for (e = 0, ne = 0; e < B_neigs; e++) {
375980db8efeSStefano Zampini                 if (eigs[e] < lthresh || eigs[e] > uthresh) {
376080db8efeSStefano Zampini                   for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
376180db8efeSStefano Zampini                   eigs[ne] = eigs[e];
376280db8efeSStefano Zampini                   ne++;
376380db8efeSStefano Zampini                 }
376480db8efeSStefano Zampini               }
37659566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(eigv, S, B_N * ne));
37666497c311SBarry Smith               PetscCall(PetscBLASIntCast(ne, &B_neigs));
376780db8efeSStefano Zampini             }
376880db8efeSStefano Zampini             break;
3769d71ae5a4SJacob Faibussowitsch           default:
3770d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3771bd2a564bSStefano Zampini           }
3772bd2a564bSStefano Zampini         }
3773bd2a564bSStefano Zampini       } else if (!same_data) { /* this is just to see all the eigenvalues */
37746497c311SBarry Smith         PetscCall(PetscBLASIntCast(PetscMax(1, PetscMin(B_N, nmax)), &B_IU));
3775d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3776792fecdfSBarry 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));
3777d16cbb6bSStefano Zampini #else
3778792fecdfSBarry 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));
3779d16cbb6bSStefano Zampini #endif
37809566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3781b03ebc13SStefano Zampini       } else { /* same_data is true, so just get the adaptive functional requested by the user */
3782b7ab4a40SStefano Zampini         PetscInt k;
378328b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
37849566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
37859566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3786b7ab4a40SStefano Zampini         nmin = nmax;
37879566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3788b7ab4a40SStefano Zampini         for (k = 0; k < nmax; k++) {
3789b7ab4a40SStefano Zampini           eigs[k]                     = 1. / PETSC_SMALL;
3790b7ab4a40SStefano Zampini           eigv[k * (subset_size + 1)] = 1.0;
3791b7ab4a40SStefano Zampini         }
3792d16cbb6bSStefano Zampini       }
37939566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
379408122e43SStefano Zampini       if (B_ierr) {
379563a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
379663a3b9bcSJacob 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);
379763a3b9bcSJacob 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);
379808122e43SStefano Zampini       }
379908122e43SStefano Zampini 
380008122e43SStefano Zampini       if (B_neigs > nmax) {
380148a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
380232fe681dSStefano Zampini         if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
38036497c311SBarry Smith         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
380408122e43SStefano Zampini       }
380508122e43SStefano Zampini 
38069552c7c7SStefano Zampini       nmin_s = PetscMin(nmin, B_N);
38079552c7c7SStefano Zampini       if (B_neigs < nmin_s) {
38089036ceccSStefano Zampini         PetscBLASInt B_neigs2 = 0;
380908122e43SStefano Zampini 
381032fe681dSStefano Zampini         if (upart) {
3811bd2a564bSStefano Zampini           if (scal) {
38126497c311SBarry Smith             PetscCall(PetscBLASIntCast(nmin_s, &B_IU));
3813bd2a564bSStefano Zampini             B_IL = B_neigs + 1;
3814bd2a564bSStefano Zampini           } else {
38156497c311SBarry Smith             PetscCall(PetscBLASIntCast(B_N - nmin_s + 1, &B_IL));
38169d54b7f4SStefano Zampini             B_IU = B_N - B_neigs;
3817bd2a564bSStefano Zampini           }
38189d54b7f4SStefano Zampini         } else {
38199d54b7f4SStefano Zampini           B_IL = B_neigs + 1;
38206497c311SBarry Smith           PetscCall(PetscBLASIntCast(nmin_s, &B_IU));
38219d54b7f4SStefano Zampini         }
3822fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
382363a3b9bcSJacob 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));
3824fd14bc51SStefano Zampini         }
3825bd2a564bSStefano Zampini         if (sub_schurs->is_symmetric) {
38261ae86dd6SStefano Zampini           PetscInt j, k;
382708122e43SStefano Zampini           for (j = 0; j < subset_size; j++) {
38281ae86dd6SStefano Zampini             for (k = j; k < subset_size; k++) {
38291ae86dd6SStefano Zampini               S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
38301ae86dd6SStefano Zampini               St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
383108122e43SStefano Zampini             }
383208122e43SStefano Zampini           }
383308122e43SStefano Zampini         } else {
38349566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
38359566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
383608122e43SStefano Zampini         }
38379566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
383808122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3839792fecdfSBarry 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));
384008122e43SStefano Zampini #else
3841792fecdfSBarry 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));
384208122e43SStefano Zampini #endif
38439566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
38449566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
384508122e43SStefano Zampini         B_neigs += B_neigs2;
384608122e43SStefano Zampini       }
384708122e43SStefano Zampini       if (B_ierr) {
384863a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
384963a3b9bcSJacob 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);
385063a3b9bcSJacob 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);
385108122e43SStefano Zampini       }
3852fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
385363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
385408122e43SStefano Zampini         for (j = 0; j < B_neigs; j++) {
385532fe681dSStefano Zampini           if (!sub_schurs->gdsw) {
385608122e43SStefano Zampini             if (eigs[j] == 0.0) {
38579566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
385808122e43SStefano Zampini             } else {
385932fe681dSStefano Zampini               if (upart) {
386063a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
38619d54b7f4SStefano Zampini               } else {
3862835f2295SStefano Zampini                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1 / eigs[j + eigs_start])));
38639d54b7f4SStefano Zampini               }
3864fd14bc51SStefano Zampini             }
386532fe681dSStefano Zampini           } else {
386632fe681dSStefano Zampini             double pg = (double)eigs[j + eigs_start];
386732fe681dSStefano Zampini             if (pg < 2 * PETSC_SMALL) pg = 0.0;
386832fe681dSStefano Zampini             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
386932fe681dSStefano Zampini           }
387008122e43SStefano Zampini         }
387108122e43SStefano Zampini       }
3872aff50787SStefano Zampini     }
38736c3e6151SStefano Zampini     /* change the basis back to the original one */
38746c3e6151SStefano Zampini     if (sub_schurs->change) {
387572b8c272SStefano Zampini       Mat change, phi, phit;
38766c3e6151SStefano Zampini 
387703dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
38786c3e6151SStefano Zampini         PetscInt ii;
38796c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
388063a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
38816c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3882684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3883684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3884684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
388563a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3886684229deSStefano Zampini #else
388763a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3888684229deSStefano Zampini #endif
38896c3e6151SStefano Zampini           }
38906c3e6151SStefano Zampini         }
38916c3e6151SStefano Zampini       }
38929566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
38939566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
3894fb842aefSJose E. Roman       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &phi));
38959566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
38969566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
38979566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
38986c3e6151SStefano Zampini     }
38998bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
39008bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
39019162d606SStefano Zampini     if (B_neigs) {
39029566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3903fd14bc51SStefano Zampini 
3904fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
39059552c7c7SStefano Zampini         PetscInt ii;
39069552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
390763a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
39089552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3909ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3910ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3911ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
391263a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3913ac47001eSStefano Zampini #else
391463a3b9bcSJacob 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]])));
3915ac47001eSStefano Zampini #endif
39169552c7c7SStefano Zampini           }
39179552c7c7SStefano Zampini         }
3918fd14bc51SStefano Zampini       }
39199566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
39209162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
39219162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
39229162d606SStefano Zampini       cum++;
392308122e43SStefano Zampini     }
39249566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
392508122e43SStefano Zampini     /* shift for next computation */
392608122e43SStefano Zampini     cumarray += subset_size * subset_size;
392708122e43SStefano Zampini   }
39281baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
392908122e43SStefano Zampini 
393008122e43SStefano Zampini   if (mss) {
393132fe681dSStefano Zampini     if (sub_schurs->gdsw) {
393232fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
393332fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
393432fe681dSStefano Zampini     } else {
39359566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
39369566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3937f6f667cfSStefano Zampini       /* destroy matrices (junk) */
39389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
39399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
394008122e43SStefano Zampini     }
394132fe681dSStefano Zampini   }
39421baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
39439566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
394408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
39459566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
394608122e43SStefano Zampini #endif
394708122e43SStefano Zampini   if (pcbddc->dbg_flag) {
39481b968477SStefano Zampini     PetscInt maxneigs_r;
3949462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
395063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
395108122e43SStefano Zampini   }
39529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
39533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
395408122e43SStefano Zampini }
3955b1b3d7a2SStefano Zampini 
3956d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3957d71ae5a4SJacob Faibussowitsch {
39589de2952eSStefano Zampini   Mat coarse_submat;
3959c8587f34SStefano Zampini 
3960c8587f34SStefano Zampini   PetscFunctionBegin;
3961f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
39625e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
39639566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3964c8587f34SStefano Zampini 
3965684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
39660fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
39679566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3968c8587f34SStefano Zampini 
39698629588bSStefano Zampini   /*
39708629588bSStefano Zampini      Setup local correction and local part of coarse basis.
39718629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
39728629588bSStefano Zampini   */
39739de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat));
39748629588bSStefano Zampini 
39758629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
39769de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat));
39779de2952eSStefano Zampini   PetscCall(MatDestroy(&coarse_submat));
39783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3979c8587f34SStefano Zampini }
3980c8587f34SStefano Zampini 
3981d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetCustomization(PC pc)
3982d71ae5a4SJacob Faibussowitsch {
3983674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3984674ae819SStefano Zampini 
3985674ae819SStefano Zampini   PetscFunctionBegin;
39869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
39879566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
39889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
39899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
39909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
39919566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
39929566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
39939566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
39949566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
39959566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
39963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3997674ae819SStefano Zampini }
3998674ae819SStefano Zampini 
3999d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetTopography(PC pc)
4000d71ae5a4SJacob Faibussowitsch {
4001674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
40024f1b2e48SStefano Zampini   PetscInt i;
4003674ae819SStefano Zampini 
4004674ae819SStefano Zampini   PetscFunctionBegin;
40059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
40069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
40079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
40089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
40099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
40109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
40119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
40129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
40139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
40149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
40159566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
401648a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
4017e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
40189566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
40199566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
4020c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
40218af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
40221c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
40233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4024674ae819SStefano Zampini }
4025674ae819SStefano Zampini 
4026d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetSolvers(PC pc)
4027d71ae5a4SJacob Faibussowitsch {
4028674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
4029674ae819SStefano Zampini 
4030674ae819SStefano Zampini   PetscFunctionBegin;
40319566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
40329566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
40339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
40349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
40359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
40369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
40379566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
40389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
40399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
40409566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
40419566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
40429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
40439566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
40449566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
40459566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
40469566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
40479566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
40489566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
40499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
40509566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
40519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
40529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
40539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
40549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
40559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
40569566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
40579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
40589566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
4059ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
4060ca92afb2SStefano Zampini     PetscInt i;
406148a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
40629566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
4063ca92afb2SStefano Zampini   }
40649566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
40653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4066674ae819SStefano Zampini }
4067674ae819SStefano Zampini 
4068d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
4069d71ae5a4SJacob Faibussowitsch {
40706bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
40716bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
40726bfb1811SStefano Zampini   VecType  impVecType;
40734f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
40746bfb1811SStefano Zampini 
40756bfb1811SStefano Zampini   PetscFunctionBegin;
40764f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
4077b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
40789566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
4079e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
4080e7b262bdSStefano Zampini   /* R nodes */
4081e7b262bdSStefano Zampini   old_size = -1;
408248a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
4083e7b262bdSStefano Zampini   if (n_R != old_size) {
40849566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
40859566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
40869566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
40879566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
40889566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
40899566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
4090e7b262bdSStefano Zampini   }
4091e7b262bdSStefano Zampini   /* local primal dofs */
4092e7b262bdSStefano Zampini   old_size = -1;
409348a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
4094e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
40959566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
40969566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
40979566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
40989566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
4099e7b262bdSStefano Zampini   }
4100e7b262bdSStefano Zampini   /* local explicit constraints */
4101e7b262bdSStefano Zampini   old_size = -1;
410248a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
4103e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
41049566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
41059566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
41069566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
41079566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
410883b7ccabSStefano Zampini   }
41093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41106bfb1811SStefano Zampini }
41116bfb1811SStefano Zampini 
41129de2952eSStefano Zampini static PetscErrorCode MatSetValuesSubMat(Mat A, Mat S, PetscInt nr, const PetscInt rows[], PetscInt nc, const PetscInt cols[], InsertMode imode)
4113d71ae5a4SJacob Faibussowitsch {
41149de2952eSStefano Zampini   PetscBool          flg;
41159de2952eSStefano Zampini   const PetscScalar *a;
41169de2952eSStefano Zampini 
41179de2952eSStefano Zampini   PetscFunctionBegin;
41189de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQDENSE, &flg));
41199de2952eSStefano Zampini   if (flg) {
41209de2952eSStefano Zampini     PetscCall(MatDenseGetArrayRead(S, &a));
41219de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_FALSE));
41229de2952eSStefano Zampini     PetscCall(MatSetValues(A, nr, rows, nc, cols, a, imode));
41239de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_TRUE));
41249de2952eSStefano Zampini     PetscCall(MatDenseRestoreArrayRead(S, &a));
41259de2952eSStefano Zampini   } else {
41269de2952eSStefano Zampini     const PetscInt *ii, *jj;
41279de2952eSStefano Zampini     PetscInt        n;
41289de2952eSStefano Zampini     PetscInt        buf[8192], *bufc = NULL;
41299de2952eSStefano Zampini     PetscBool       freeb = PETSC_FALSE;
41309de2952eSStefano Zampini     Mat             Sm    = S;
41319de2952eSStefano Zampini 
41329de2952eSStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQAIJ, &flg));
41339de2952eSStefano Zampini     if (!flg) PetscCall(MatConvert(S, MATSEQAIJ, MAT_INITIAL_MATRIX, &Sm));
41349de2952eSStefano Zampini     else PetscCall(PetscObjectReference((PetscObject)S));
41359de2952eSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(Sm, &a));
41369de2952eSStefano Zampini     PetscCall(MatGetRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
41379de2952eSStefano Zampini     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot get IJ structure");
41389de2952eSStefano Zampini     if (nc <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
41399de2952eSStefano Zampini       bufc = buf;
41409de2952eSStefano Zampini     } else {
41419de2952eSStefano Zampini       PetscCall(PetscMalloc1(nc, &bufc));
41429de2952eSStefano Zampini       freeb = PETSC_TRUE;
41439de2952eSStefano Zampini     }
41449de2952eSStefano Zampini 
41459de2952eSStefano Zampini     for (PetscInt i = 0; i < n; i++) {
41469de2952eSStefano Zampini       const PetscInt nci = ii[i + 1] - ii[i];
41479de2952eSStefano Zampini 
41489de2952eSStefano Zampini       for (PetscInt j = 0; j < nci; j++) bufc[j] = cols[jj[ii[i] + j]];
41499de2952eSStefano Zampini       PetscCall(MatSetValues(A, 1, rows + i, nci, bufc, a + ii[i], imode));
41509de2952eSStefano Zampini     }
41519de2952eSStefano Zampini     PetscCall(MatRestoreRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
41529de2952eSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(Sm, &a));
41539de2952eSStefano Zampini     PetscCall(MatDestroy(&Sm));
41549de2952eSStefano Zampini     if (freeb) PetscCall(PetscFree(bufc));
41559de2952eSStefano Zampini   }
41569de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY));
41579de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY));
41589de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
41599de2952eSStefano Zampini }
41609de2952eSStefano Zampini 
41619de2952eSStefano Zampini static PetscErrorCode MatCreateSeqAIJFromDenseExpand(Mat D, PetscInt n, const PetscInt j[], Mat *mat)
41629de2952eSStefano Zampini {
41639de2952eSStefano Zampini   Mat_SeqAIJ        *aij;
41649de2952eSStefano Zampini   PetscInt          *ii, *jj;
41659de2952eSStefano Zampini   PetscScalar       *aa;
41669de2952eSStefano Zampini   PetscInt           nnz = 0, m, nc;
41679de2952eSStefano Zampini   const PetscScalar *a;
41689de2952eSStefano Zampini   const PetscScalar  zero = 0.0;
41699de2952eSStefano Zampini 
41709de2952eSStefano Zampini   PetscFunctionBegin;
41719de2952eSStefano Zampini   PetscCall(MatGetLocalSize(D, &m, &nc));
41729de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(D, &a));
41739de2952eSStefano Zampini   PetscCall(PetscMalloc1(m + 1, &ii));
41749de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &jj));
41759de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &aa));
41769de2952eSStefano Zampini   ii[0] = 0;
41779de2952eSStefano Zampini   for (PetscInt k = 0; k < m; k++) {
41789de2952eSStefano Zampini     for (PetscInt s = 0; s < nc; s++) {
41799de2952eSStefano Zampini       const PetscInt    c = s + k * nc;
41809de2952eSStefano Zampini       const PetscScalar v = a[k + s * m];
41819de2952eSStefano Zampini 
41829de2952eSStefano Zampini       if (PetscUnlikely(j[c] < 0 || v == zero)) continue;
41839de2952eSStefano Zampini       jj[nnz] = j[c];
41849de2952eSStefano Zampini       aa[nnz] = a[k + s * m];
41859de2952eSStefano Zampini       nnz++;
41869de2952eSStefano Zampini     }
41879de2952eSStefano Zampini     ii[k + 1] = nnz;
41889de2952eSStefano Zampini   }
41899de2952eSStefano Zampini 
41909de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)D), m, n, ii, jj, aa, mat));
41919de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(D, &a));
41929de2952eSStefano Zampini 
41939de2952eSStefano Zampini   aij          = (Mat_SeqAIJ *)(*mat)->data;
41949de2952eSStefano Zampini   aij->free_a  = PETSC_TRUE;
41959de2952eSStefano Zampini   aij->free_ij = PETSC_TRUE;
41969de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
41979de2952eSStefano Zampini }
41989de2952eSStefano Zampini 
41999de2952eSStefano Zampini /* adapted from MatInvertVariableBlockDiagonal_SeqAIJ */
42009de2952eSStefano Zampini static PetscErrorCode MatSeqAIJInvertVariableBlockDiagonalMat(Mat A, PetscInt nblocks, const PetscInt *bsizes, Mat *B)
42019de2952eSStefano Zampini {
42029de2952eSStefano Zampini   PetscInt        n = A->rmap->n, ncnt = 0, ncnt2 = 0, bsizemax = 0, *v_pivots = NULL;
42039de2952eSStefano Zampini   const PetscBool allowzeropivot    = PETSC_FALSE;
42049de2952eSStefano Zampini   PetscBool       zeropivotdetected = PETSC_FALSE;
42059de2952eSStefano Zampini   const PetscReal shift             = 0.0;
42069de2952eSStefano Zampini   PetscInt        ipvt[5], *ii, *jj, *indi, *indj;
42079de2952eSStefano Zampini   PetscScalar     work[25], *v_work = NULL, *aa, *diag;
42089de2952eSStefano Zampini   PetscLogDouble  flops = 0.0;
42099de2952eSStefano Zampini 
42109de2952eSStefano Zampini   PetscFunctionBegin;
42119de2952eSStefano Zampini   PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Not for rectangular matrices");
42129de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
42139de2952eSStefano Zampini     ncnt += bsizes[i];
42149de2952eSStefano Zampini     ncnt2 += PetscSqr(bsizes[i]);
42159de2952eSStefano Zampini   }
42169de2952eSStefano 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);
42179de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]);
42189de2952eSStefano Zampini   if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots));
42199de2952eSStefano Zampini 
42209de2952eSStefano Zampini   PetscCall(PetscMalloc1(n + 1, &ii));
42219de2952eSStefano Zampini   PetscCall(PetscMalloc1(ncnt2, &jj));
42229de2952eSStefano Zampini   PetscCall(PetscCalloc1(ncnt2, &aa));
42239de2952eSStefano Zampini 
42249de2952eSStefano Zampini   ncnt  = 0;
42259de2952eSStefano Zampini   ii[0] = 0;
42269de2952eSStefano Zampini   indi  = ii;
42279de2952eSStefano Zampini   indj  = jj;
42289de2952eSStefano Zampini   diag  = aa;
42299de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
42309de2952eSStefano Zampini     const PetscInt bs = bsizes[i];
42319de2952eSStefano Zampini 
42329de2952eSStefano Zampini     for (PetscInt k = 0; k < bs; k++) {
42339de2952eSStefano Zampini       indi[k + 1] = indi[k] + bs;
42349de2952eSStefano Zampini       for (PetscInt j = 0; j < bs; j++) indj[k * bs + j] = ncnt + j;
42359de2952eSStefano Zampini     }
42369de2952eSStefano Zampini     PetscCall(MatGetValues(A, bs, indj, bs, indj, diag));
42379de2952eSStefano Zampini     switch (bs) {
42389de2952eSStefano Zampini     case 1:
42399de2952eSStefano Zampini       *diag = 1.0 / (*diag);
42409de2952eSStefano Zampini       break;
42419de2952eSStefano Zampini     case 2:
42429de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
42439de2952eSStefano Zampini       break;
42449de2952eSStefano Zampini     case 3:
42459de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
42469de2952eSStefano Zampini       break;
42479de2952eSStefano Zampini     case 4:
42489de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
42499de2952eSStefano Zampini       break;
42509de2952eSStefano Zampini     case 5:
42519de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
42529de2952eSStefano Zampini       break;
42539de2952eSStefano Zampini     case 6:
42549de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
42559de2952eSStefano Zampini       break;
42569de2952eSStefano Zampini     case 7:
42579de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
42589de2952eSStefano Zampini       break;
42599de2952eSStefano Zampini     default:
42609de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
42619de2952eSStefano Zampini     }
42629de2952eSStefano Zampini     ncnt += bs;
42639de2952eSStefano Zampini     flops += 2.0 * PetscPowInt(bs, 3) / 3.0;
42649de2952eSStefano Zampini     diag += bs * bs;
42659de2952eSStefano Zampini     indj += bs * bs;
42669de2952eSStefano Zampini     indi += bs;
42679de2952eSStefano Zampini   }
42689de2952eSStefano Zampini   PetscCall(PetscLogFlops(flops));
42699de2952eSStefano Zampini   PetscCall(PetscFree2(v_work, v_pivots));
42709de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, n, ii, jj, aa, B));
42719de2952eSStefano Zampini   {
42729de2952eSStefano Zampini     Mat_SeqAIJ *aij = (Mat_SeqAIJ *)(*B)->data;
42739de2952eSStefano Zampini     aij->free_a     = PETSC_TRUE;
42749de2952eSStefano Zampini     aij->free_ij    = PETSC_TRUE;
42759de2952eSStefano Zampini   }
42769de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
42779de2952eSStefano Zampini }
42789de2952eSStefano Zampini 
42799de2952eSStefano Zampini static PetscErrorCode MatDenseScatter(Mat A, PetscSF sf, Mat B)
42809de2952eSStefano Zampini {
42819de2952eSStefano Zampini   const PetscScalar *rarr;
42829de2952eSStefano Zampini   PetscScalar       *larr;
42839de2952eSStefano Zampini   PetscSF            vsf;
42849de2952eSStefano Zampini   PetscInt           n, rld, lld;
42859de2952eSStefano Zampini 
42869de2952eSStefano Zampini   PetscFunctionBegin;
42879de2952eSStefano Zampini   PetscCall(MatGetSize(A, NULL, &n));
42889de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(A, &rld));
42899de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(B, &lld));
42909de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(A, &rarr));
42919de2952eSStefano Zampini   PetscCall(MatDenseGetArrayWrite(B, &larr));
42929de2952eSStefano Zampini   PetscCall(PetscSFCreateStridedSF(sf, n, rld, lld, &vsf));
42939de2952eSStefano Zampini   PetscCall(PetscSFBcastBegin(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
42949de2952eSStefano Zampini   PetscCall(PetscSFBcastEnd(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
42959de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(A, &rarr));
42969de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayWrite(B, &larr));
42979de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&vsf));
42989de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
42999de2952eSStefano Zampini }
43009de2952eSStefano Zampini 
43019de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCorrection(PC pc, Mat *coarse_submat)
43029de2952eSStefano Zampini {
430388ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
430488ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
43059de2952eSStefano Zampini   PCBDDCGraph     graph      = pcbddc->mat_graph;
4306d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
430725084f0cSStefano Zampini   /* submatrices of local problem */
43089de2952eSStefano Zampini   Mat A_RV = NULL, A_VR, A_VV, local_auxmat2_R = NULL;
430906656605SStefano Zampini   /* submatrices of local coarse problem */
43109de2952eSStefano Zampini   Mat S_CV = NULL, S_VC = NULL, S_CC = NULL;
431125084f0cSStefano Zampini   /* working matrices */
431206656605SStefano Zampini   Mat C_CR;
43139de2952eSStefano Zampini 
431425084f0cSStefano Zampini   /* additional working stuff */
431506656605SStefano Zampini   PC              pc_R;
43169de2952eSStefano Zampini   IS              is_R, is_V, is_C;
43179de2952eSStefano Zampini   const PetscInt *idx_V, *idx_C;
4318c58f9fdbSStefano Zampini   Mat             F, Brhs = NULL;
43195cbda25cSStefano Zampini   Vec             dummy_vec;
4320*d7974de0SStefano Zampini   PetscBool       isPreonly, isLU, isCHOL, need_benign_correction, sparserhs;
432106656605SStefano Zampini   PetscInt       *idx_V_B;
43229de2952eSStefano Zampini   PetscInt        lda_rhs, n_vertices, n_constraints, *p0_lidx_I;
43239de2952eSStefano Zampini   PetscInt        n_eff_vertices, n_eff_constraints;
432406656605SStefano Zampini   PetscInt        i, n_R, n_D, n_B;
432506656605SStefano Zampini   PetscScalar     one = 1.0, m_one = -1.0;
432688ebb749SStefano Zampini 
43279de2952eSStefano Zampini   /* Multi-element support */
43289de2952eSStefano Zampini   PetscBool multi_element = graph->multi_element;
43299de2952eSStefano Zampini   PetscInt *V_to_eff_V = NULL, *C_to_eff_C = NULL;
43309de2952eSStefano Zampini   PetscInt *B_eff_V_J = NULL, *R_eff_V_J = NULL, *B_eff_C_J = NULL, *R_eff_C_J = NULL;
43319de2952eSStefano Zampini   IS        is_C_perm = NULL;
43329de2952eSStefano Zampini   PetscInt  n_C_bss = 0, *C_bss = NULL;
43339de2952eSStefano Zampini   Mat       coarse_phi_multi;
43349de2952eSStefano Zampini 
433588ebb749SStefano Zampini   PetscFunctionBegin;
43367827d75bSBarry 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");
43379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
4338ffd830a3SStefano Zampini 
4339ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
4340b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
43414f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
4342b371cd4fSStefano Zampini   n_B           = pcis->n_B;
4343b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
434488ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
434588ebb749SStefano Zampini 
434688ebb749SStefano Zampini   /* vertices in boundary numbering */
43479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
43489566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
434963a3b9bcSJacob 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);
435088ebb749SStefano Zampini 
43519de2952eSStefano Zampini   /* these two cases still need to be optimized */
43529de2952eSStefano Zampini   if (pcbddc->benign_saddle_point || !pcbddc->symmetric_primal) multi_element = PETSC_FALSE;
43539de2952eSStefano Zampini 
435406656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
43559de2952eSStefano Zampini   if (multi_element) {
43569de2952eSStefano Zampini     PetscCheck(!pcbddc->benign_n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
43579de2952eSStefano Zampini 
43589de2952eSStefano Zampini     PetscCall(MatCreate(PETSC_COMM_SELF, coarse_submat));
43599de2952eSStefano Zampini     PetscCall(MatSetSizes(*coarse_submat, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size));
43609de2952eSStefano Zampini     PetscCall(MatSetType(*coarse_submat, MATSEQAIJ));
43619de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
43629de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
43639de2952eSStefano Zampini 
43649de2952eSStefano Zampini     /* group vertices and constraints by subdomain id */
43659de2952eSStefano Zampini     const PetscInt *vidxs = pcbddc->primal_indices_local_idxs;
43669de2952eSStefano Zampini     const PetscInt *cidxs = pcbddc->primal_indices_local_idxs + n_vertices;
43679de2952eSStefano Zampini     PetscInt       *count_eff, *V_eff_to_V, *C_eff_to_C, *nnz;
43689de2952eSStefano Zampini     PetscInt        n_el = PetscMax(graph->n_local_subs, 1);
43699de2952eSStefano Zampini 
43709de2952eSStefano Zampini     PetscCall(PetscCalloc1(2 * n_el, &count_eff));
43719de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices, &V_to_eff_V));
43729de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &C_to_eff_C));
43739de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
43749de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
43759de2952eSStefano Zampini 
43769de2952eSStefano Zampini       V_to_eff_V[i] = count_eff[s];
43779de2952eSStefano Zampini       count_eff[s] += 1;
43789de2952eSStefano Zampini     }
43799de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
43809de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub + 1;
43819de2952eSStefano Zampini 
43829de2952eSStefano Zampini       C_to_eff_C[i] = count_eff[s];
43839de2952eSStefano Zampini       count_eff[s] += 1;
43849de2952eSStefano Zampini     }
43859de2952eSStefano Zampini 
43869de2952eSStefano Zampini     /* preallocation */
43879de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices + n_constraints, &nnz));
43889de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
43899de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
43909de2952eSStefano Zampini 
43919de2952eSStefano Zampini       nnz[i] = count_eff[s] + count_eff[s + 1];
43929de2952eSStefano Zampini     }
43939de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
43949de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub;
43959de2952eSStefano Zampini 
43969de2952eSStefano Zampini       nnz[i + n_vertices] = count_eff[s] + count_eff[s + 1];
43979de2952eSStefano Zampini     }
43989de2952eSStefano Zampini     PetscCall(MatSeqAIJSetPreallocation(*coarse_submat, 0, nnz));
43999de2952eSStefano Zampini     PetscCall(PetscFree(nnz));
44009de2952eSStefano Zampini 
44019de2952eSStefano Zampini     n_eff_vertices    = 0;
44029de2952eSStefano Zampini     n_eff_constraints = 0;
44039de2952eSStefano Zampini     for (PetscInt i = 0; i < n_el; i++) {
44049de2952eSStefano Zampini       n_eff_vertices       = PetscMax(n_eff_vertices, count_eff[2 * i]);
44059de2952eSStefano Zampini       n_eff_constraints    = PetscMax(n_eff_constraints, count_eff[2 * i + 1]);
44069de2952eSStefano Zampini       count_eff[2 * i]     = 0;
44079de2952eSStefano Zampini       count_eff[2 * i + 1] = 0;
44089de2952eSStefano Zampini     }
44099de2952eSStefano Zampini 
44109de2952eSStefano Zampini     const PetscInt *idx;
44119de2952eSStefano Zampini     PetscCall(PetscMalloc2(n_el * n_eff_vertices, &V_eff_to_V, n_el * n_eff_constraints, &C_eff_to_C));
44129de2952eSStefano Zampini 
44139de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
44149de2952eSStefano Zampini       const PetscInt e = graph->nodes[vidxs[i]].local_sub;
44159de2952eSStefano Zampini       const PetscInt s = 2 * e;
44169de2952eSStefano Zampini 
44179de2952eSStefano Zampini       V_eff_to_V[e * n_eff_vertices + count_eff[s]] = i;
44189de2952eSStefano Zampini       count_eff[s] += 1;
44199de2952eSStefano Zampini     }
44209de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
44219de2952eSStefano Zampini       const PetscInt e = graph->nodes[cidxs[i]].local_sub;
44229de2952eSStefano Zampini       const PetscInt s = 2 * e + 1;
44239de2952eSStefano Zampini 
44249de2952eSStefano Zampini       C_eff_to_C[e * n_eff_constraints + count_eff[s]] = i;
44259de2952eSStefano Zampini       count_eff[s] += 1;
44269de2952eSStefano Zampini     }
44279de2952eSStefano Zampini 
44289de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_vertices, &R_eff_V_J));
44299de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_constraints, &R_eff_C_J));
44309de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_vertices, &B_eff_V_J));
44319de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_constraints, &B_eff_C_J));
44329de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_vertices; i++) R_eff_V_J[i] = -1;
44339de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_constraints; i++) R_eff_C_J[i] = -1;
44349de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_vertices; i++) B_eff_V_J[i] = -1;
44359de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_constraints; i++) B_eff_C_J[i] = -1;
44369de2952eSStefano Zampini 
44379de2952eSStefano Zampini     PetscCall(ISGetIndices(pcbddc->is_R_local, &idx));
44389de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R; i++) {
44399de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
44409de2952eSStefano Zampini       const PetscInt s = 2 * e;
44419de2952eSStefano Zampini       PetscInt       j;
44429de2952eSStefano Zampini 
44439de2952eSStefano 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];
44449de2952eSStefano 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];
44459de2952eSStefano Zampini     }
44469de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idx));
44479de2952eSStefano Zampini     PetscCall(ISGetIndices(pcis->is_B_local, &idx));
44489de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B; i++) {
44499de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
44509de2952eSStefano Zampini       const PetscInt s = 2 * e;
44519de2952eSStefano Zampini       PetscInt       j;
44529de2952eSStefano Zampini 
44539de2952eSStefano 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];
44549de2952eSStefano 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];
44559de2952eSStefano Zampini     }
44569de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcis->is_B_local, &idx));
44579de2952eSStefano Zampini 
44589de2952eSStefano Zampini     /* permutation and blocksizes for block invert of S_CC */
44599de2952eSStefano Zampini     PetscInt *idxp;
44609de2952eSStefano Zampini 
44619de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &idxp));
44629de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_el, &C_bss));
44639de2952eSStefano Zampini     n_C_bss = 0;
44649de2952eSStefano Zampini     for (PetscInt e = 0, cnt = 0; e < n_el; e++) {
44659de2952eSStefano Zampini       const PetscInt nc = count_eff[2 * e + 1];
44669de2952eSStefano Zampini 
44679de2952eSStefano Zampini       if (nc) C_bss[n_C_bss++] = nc;
4468ac530a7eSPierre Jolivet       for (PetscInt c = 0; c < nc; c++) idxp[cnt + c] = C_eff_to_C[e * n_eff_constraints + c];
44699de2952eSStefano Zampini       cnt += nc;
44709de2952eSStefano Zampini     }
44719de2952eSStefano Zampini 
44729de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_constraints, idxp, PETSC_OWN_POINTER, &is_C_perm));
44739de2952eSStefano Zampini 
44749de2952eSStefano Zampini     PetscCall(PetscFree2(V_eff_to_V, C_eff_to_C));
44759de2952eSStefano Zampini     PetscCall(PetscFree(count_eff));
44769de2952eSStefano Zampini   } else {
44779de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, NULL, coarse_submat));
44789de2952eSStefano Zampini     n_eff_constraints = n_constraints;
44799de2952eSStefano Zampini     n_eff_vertices    = n_vertices;
44809de2952eSStefano Zampini   }
448106656605SStefano Zampini 
448206656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
44839566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
44849566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
4485*d7974de0SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->ksp_R, KSPPREONLY, &isPreonly));
44869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
44879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
4488ffd830a3SStefano Zampini   lda_rhs                = n_R;
4489a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
4490*d7974de0SStefano Zampini   F                      = NULL;
4491*d7974de0SStefano Zampini   if (isPreonly && (isLU || isCHOL)) {
44929566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
4493b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
4494df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4495d62866d3SStefano Zampini     MatFactorType      type;
4496d62866d3SStefano Zampini 
4497df4d28bfSStefano Zampini     F = reuse_solver->F;
44989566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
4499d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
45007ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
45019566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
450222db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
4503*d7974de0SStefano Zampini   }
450406656605SStefano Zampini 
4505c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
4506c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
45079de2952eSStefano Zampini   if (F && !multi_element) {
4508ea799195SBarry Smith     MatSolverType solver;
4509c58f9fdbSStefano Zampini 
45109566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
45119566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
4512c58f9fdbSStefano Zampini   }
4513c58f9fdbSStefano Zampini 
45145cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
45155cbda25cSStefano Zampini   dummy_vec = NULL;
45165cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
45179566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
45189566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
45199566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
45205cbda25cSStefano Zampini   }
45215cbda25cSStefano Zampini 
45229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
45239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
45247ebab0bbSStefano Zampini 
45259de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &is_R));
45269de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_vertices, 0, 1, &is_V));
45279de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_C));
45289de2952eSStefano Zampini   PetscCall(ISGetIndices(is_V, &idx_V));
45299de2952eSStefano Zampini   PetscCall(ISGetIndices(is_C, &idx_C));
45309de2952eSStefano Zampini 
453188ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
453288ebb749SStefano Zampini   if (n_constraints) {
45339de2952eSStefano Zampini     Mat C_B;
453406656605SStefano Zampini 
453525084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
45369de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
45379de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
453888ebb749SStefano Zampini 
453980677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
454080677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
4541c58f9fdbSStefano Zampini     if (!sparserhs) {
45429de2952eSStefano Zampini       PetscScalar *marr;
45439de2952eSStefano Zampini 
45449de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &Brhs));
45459de2952eSStefano Zampini       PetscCall(MatDenseGetArrayWrite(Brhs, &marr));
454688ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
454706656605SStefano Zampini         const PetscScalar *row_cmat_values;
454806656605SStefano Zampini         const PetscInt    *row_cmat_indices;
45499de2952eSStefano Zampini         PetscInt           size_of_constraint, j, col = C_to_eff_C ? C_to_eff_C[i] : i;
455088ebb749SStefano Zampini 
45519566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
45529de2952eSStefano Zampini         for (j = 0; j < size_of_constraint; j++) marr[row_cmat_indices[j] + col * lda_rhs] = -row_cmat_values[j];
45539566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
455406656605SStefano Zampini       }
45559de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayWrite(Brhs, &marr));
4556c58f9fdbSStefano Zampini     } else {
4557c58f9fdbSStefano Zampini       Mat tC_CR;
4558c58f9fdbSStefano Zampini 
45599566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
4560c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
4561c58f9fdbSStefano Zampini         PetscScalar *aa;
4562c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
4563c58f9fdbSStefano Zampini         PetscBool    done;
4564c58f9fdbSStefano Zampini 
45659566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
456628b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
45679566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
45689566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
45699566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
457028b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4571c58f9fdbSStefano Zampini       } else {
45729566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
4573c58f9fdbSStefano Zampini         tC_CR = C_CR;
4574c58f9fdbSStefano Zampini       }
45759566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
45769566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
4577c58f9fdbSStefano Zampini     }
45789de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &local_auxmat2_R));
457906656605SStefano Zampini     if (F) {
4580a3df083aSStefano Zampini       if (need_benign_correction) {
4581df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4582a3df083aSStefano Zampini 
458372b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
45849566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
4585a3df083aSStefano Zampini       }
45869566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
4587a3df083aSStefano Zampini       if (need_benign_correction) {
4588a3df083aSStefano Zampini         PetscScalar       *marr;
4589df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4590a3df083aSStefano Zampini 
45919de2952eSStefano Zampini         /* XXX multi_element? */
45929566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
45935cbda25cSStefano Zampini         if (lda_rhs != n_R) {
45949de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
45959566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
45969566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
45979566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
45985cbda25cSStefano Zampini           }
45995cbda25cSStefano Zampini         } else {
46009de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
46019566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
46029566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
46039566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
4604a3df083aSStefano Zampini           }
46055cbda25cSStefano Zampini         }
46069566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
4607a3df083aSStefano Zampini       }
460806656605SStefano Zampini     } else {
46099de2952eSStefano Zampini       const PetscScalar *barr;
461080677318SStefano Zampini       PetscScalar       *marr;
461180677318SStefano Zampini 
46129de2952eSStefano Zampini       PetscCall(MatDenseGetArrayRead(Brhs, &barr));
46139566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
46149de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
46159de2952eSStefano Zampini         PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
46169566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
46179566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
46189566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
46199566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
46209566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
462106656605SStefano Zampini       }
46229de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
46239566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
462406656605SStefano Zampini     }
46251baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
46269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
46279de2952eSStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
462880677318SStefano Zampini     if (!pcbddc->switch_static) {
46299de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_constraints, NULL, &pcbddc->local_auxmat2));
46309de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
4631ab2d12f3SJunchao Zhang         Vec r, b;
46329566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
46339566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
46349566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
46359566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
46369566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
46379566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
463880677318SStefano Zampini       }
46399de2952eSStefano Zampini       if (multi_element) {
46409de2952eSStefano Zampini         Mat T;
4641ffd830a3SStefano Zampini 
46429de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
46439de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
46449de2952eSStefano Zampini         local_auxmat2_R = T;
46459de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(pcbddc->local_auxmat2, n_constraints, B_eff_C_J, &T));
46469de2952eSStefano Zampini         PetscCall(MatDestroy(&pcbddc->local_auxmat2));
46479de2952eSStefano Zampini         pcbddc->local_auxmat2 = T;
46489de2952eSStefano Zampini       }
4649fb842aefSJose E. Roman       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_CC));
46509de2952eSStefano Zampini     } else {
46519de2952eSStefano Zampini       if (multi_element) {
46529de2952eSStefano Zampini         Mat T;
46539de2952eSStefano Zampini 
46549de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
46559de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
46569de2952eSStefano Zampini         local_auxmat2_R = T;
46579de2952eSStefano Zampini       }
46589de2952eSStefano Zampini       if (lda_rhs != n_R) {
46599de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(local_auxmat2_R, is_R, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
4660ffd830a3SStefano Zampini       } else {
46619566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
466280677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
4663ffd830a3SStefano Zampini       }
4664fb842aefSJose E. Roman       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_CC));
466580677318SStefano Zampini     }
46669de2952eSStefano Zampini     PetscCall(MatScale(S_CC, m_one));
46679de2952eSStefano Zampini     if (multi_element) {
46689de2952eSStefano Zampini       Mat T, T2;
46699de2952eSStefano Zampini       IS  isp, ispi;
46709de2952eSStefano Zampini 
46719de2952eSStefano Zampini       isp = is_C_perm;
46729de2952eSStefano Zampini 
46739de2952eSStefano Zampini       PetscCall(ISInvertPermutation(isp, PETSC_DECIDE, &ispi));
46749de2952eSStefano Zampini       PetscCall(MatPermute(S_CC, isp, isp, &T));
46759de2952eSStefano Zampini       PetscCall(MatSeqAIJInvertVariableBlockDiagonalMat(T, n_C_bss, C_bss, &T2));
46769de2952eSStefano Zampini       PetscCall(MatDestroy(&T));
46779de2952eSStefano Zampini       PetscCall(MatDestroy(&S_CC));
46789de2952eSStefano Zampini       PetscCall(MatPermute(T2, ispi, ispi, &S_CC));
46799de2952eSStefano Zampini       PetscCall(MatDestroy(&T2));
46809de2952eSStefano Zampini       PetscCall(ISDestroy(&ispi));
468180677318SStefano Zampini     } else {
46829de2952eSStefano Zampini       if (isCHOL) {
46839de2952eSStefano Zampini         PetscCall(MatCholeskyFactor(S_CC, NULL, NULL));
46849de2952eSStefano Zampini       } else {
46859de2952eSStefano Zampini         PetscCall(MatLUFactor(S_CC, NULL, NULL, NULL));
468680677318SStefano Zampini       }
46879de2952eSStefano Zampini       PetscCall(MatSeqDenseInvertFactors_Private(S_CC));
46889de2952eSStefano Zampini     }
468980677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
4690fb842aefSJose E. Roman     PetscCall(MatMatMult(S_CC, C_B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &pcbddc->local_auxmat1));
46919566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
46929de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, S_CC, n_constraints, idx_C, n_constraints, idx_C, INSERT_VALUES));
4693f4ddd8eeSStefano Zampini   }
4694fc227af8SStefano Zampini 
4695fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
469688ebb749SStefano Zampini   if (n_vertices) {
46977ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
46987ebab0bbSStefano Zampini     PetscBool oldpin;
46997ebab0bbSStefano Zampini #endif
470006656605SStefano Zampini     IS is_aux;
47013a50541eSStefano Zampini 
4702b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
47036816873aSStefano Zampini       IS tis;
47046816873aSStefano Zampini 
47059566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
47069566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
47079566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
47089566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
47096816873aSStefano Zampini     } else {
47109566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
47116816873aSStefano Zampini     }
47127ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4713b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
47147ebab0bbSStefano Zampini #endif
47159566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
47169566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
47179566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
47189de2952eSStefano Zampini     /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
47199566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
47209566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
47217ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
47229566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
47237ebab0bbSStefano Zampini #endif
47249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
472588ebb749SStefano Zampini   }
47269de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C_perm));
47279de2952eSStefano Zampini   PetscCall(PetscFree(C_bss));
472888ebb749SStefano Zampini 
47294f1b2e48SStefano Zampini   p0_lidx_I = NULL;
47304f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4731d12edf2fSStefano Zampini     const PetscInt *idxs;
4732d12edf2fSStefano Zampini 
47339566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
47349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
473548a46eb9SPierre 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]));
47369566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4737d12edf2fSStefano Zampini   }
4738d16cbb6bSStefano Zampini 
47399de2952eSStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
47409de2952eSStefano Zampini 
47419de2952eSStefano Zampini   /* Matrices of coarse basis functions (local) */
47429de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
47439de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
47449de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
47459de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
47469de2952eSStefano Zampini   if (!multi_element) {
47479de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_B));
47489de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_D));
47499de2952eSStefano Zampini     coarse_phi_multi = NULL;
47509de2952eSStefano Zampini   } else { /* Create temporary NEST matrix to hold coarse basis functions blocks */
47519de2952eSStefano Zampini     IS is_rows[2] = {pcbddc->is_R_local, NULL};
47529de2952eSStefano Zampini     IS is_cols[2] = {is_V, is_C};
47539de2952eSStefano Zampini 
47549de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_vertices, pcbddc->local_primal_ref_node, PETSC_USE_POINTER, &is_rows[1]));
47559de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, 2, is_rows, 2, is_cols, NULL, &coarse_phi_multi));
47569de2952eSStefano Zampini     PetscCall(ISDestroy(&is_rows[1]));
47579de2952eSStefano Zampini   }
47589de2952eSStefano Zampini 
475906656605SStefano Zampini   /* vertices */
476006656605SStefano Zampini   if (n_vertices) {
4761c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
47629de2952eSStefano Zampini     Mat       A_RRmA_RV  = NULL;
476316f15bc4SStefano Zampini 
47649de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, A_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
47659de2952eSStefano Zampini     PetscCall(MatDestroy(&A_VV));
476604708bb6SStefano Zampini 
476716f15bc4SStefano Zampini     if (n_R) {
47689de2952eSStefano Zampini       Mat A_RV_bcorr = NULL, S_VV;
476906656605SStefano Zampini 
47709566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
477114393ed6SStefano Zampini       if (need_benign_correction) {
477214393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
477314393ed6SStefano Zampini         IS                     is_p0;
477414393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
477514393ed6SStefano Zampini 
47769566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
47779566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
47789566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
477963a3b9bcSJacob 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);
47809566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
47819566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
47829566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
47839566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
478414393ed6SStefano Zampini       }
478514393ed6SStefano Zampini 
47869de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &A_RRmA_RV));
4787c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
47889de2952eSStefano Zampini         if (lda_rhs == n_R && !multi_element) {
47899566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4790ffd830a3SStefano Zampini         } else {
47919de2952eSStefano Zampini           Mat             T;
4792ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4793ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4794ca92afb2SStefano Zampini           PetscInt        n;
4795ca92afb2SStefano Zampini           PetscBool       flg_row;
4796ffd830a3SStefano Zampini 
47979de2952eSStefano Zampini           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &T));
47989de2952eSStefano Zampini           PetscCall(MatDenseGetArrayWrite(T, &array));
47999566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
48009566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
48019566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4802ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4803ca92afb2SStefano Zampini             PetscInt j;
48049de2952eSStefano 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];
4805ffd830a3SStefano Zampini           }
48069566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
48079de2952eSStefano Zampini           PetscCall(MatDenseRestoreArrayWrite(T, &array));
48089566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
48099de2952eSStefano Zampini           A_RV = T;
4810ffd830a3SStefano Zampini         }
4811a3df083aSStefano Zampini         if (need_benign_correction) {
4812df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4813a3df083aSStefano Zampini           PetscScalar       *marr;
4814a3df083aSStefano Zampini 
48159de2952eSStefano Zampini           /* XXX multi_element */
48169566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
481714393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
481814393ed6SStefano Zampini 
481914393ed6SStefano Zampini                  | 0 0  0 | (V)
482014393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
482114393ed6SStefano Zampini                  | 0 0 -1 | (p0)
482214393ed6SStefano Zampini 
482314393ed6SStefano Zampini           */
4824df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
482514393ed6SStefano Zampini             const PetscScalar *vals;
482614393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
482714393ed6SStefano Zampini             PetscInt           n, j, nz;
482814393ed6SStefano Zampini 
48299566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
48309566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
48319566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
483214393ed6SStefano Zampini             for (j = 0; j < n; j++) {
483314393ed6SStefano Zampini               PetscScalar val = vals[j];
483414393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
483514393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
483614393ed6SStefano Zampini             }
48379566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
48389566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
483914393ed6SStefano Zampini           }
48409566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
484172b8c272SStefano Zampini         }
48429566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4843c58f9fdbSStefano Zampini         Brhs = A_RV;
4844c58f9fdbSStefano Zampini       } else {
4845c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4846c58f9fdbSStefano Zampini 
4847c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4848fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
48499566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4850c58f9fdbSStefano Zampini         } else {
4851c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
48529566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
48539566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4854c58f9fdbSStefano Zampini           A_RVT = A_VR;
4855c58f9fdbSStefano Zampini         }
4856c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4857c58f9fdbSStefano Zampini           PetscScalar *aa;
4858c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4859c58f9fdbSStefano Zampini           PetscBool    done;
4860c58f9fdbSStefano Zampini 
48619566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
486228b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
48639566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
48649566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
48659566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
486628b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4867c58f9fdbSStefano Zampini         } else {
48689566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4869c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4870c58f9fdbSStefano Zampini         }
48719566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
48729566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
48739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4874c58f9fdbSStefano Zampini       }
487572b8c272SStefano Zampini       if (F) {
487614393ed6SStefano Zampini         /* need to correct the rhs */
487772b8c272SStefano Zampini         if (need_benign_correction) {
487872b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
487972b8c272SStefano Zampini           PetscScalar       *marr;
488072b8c272SStefano Zampini 
48819566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
48825cbda25cSStefano Zampini           if (lda_rhs != n_R) {
48839de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
48849566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
48859566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
48869566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
48875cbda25cSStefano Zampini             }
48885cbda25cSStefano Zampini           } else {
48899de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
48909566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
48919566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
48929566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4893a3df083aSStefano Zampini             }
48945cbda25cSStefano Zampini           }
48959566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4896a3df083aSStefano Zampini         }
48979566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
48981baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
489914393ed6SStefano Zampini         /* need to correct the solution */
4900a3df083aSStefano Zampini         if (need_benign_correction) {
4901df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4902a3df083aSStefano Zampini           PetscScalar       *marr;
4903a3df083aSStefano Zampini 
49049566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
49055cbda25cSStefano Zampini           if (lda_rhs != n_R) {
49069de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
49079566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
49089566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
49099566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
49105cbda25cSStefano Zampini             }
49115cbda25cSStefano Zampini           } else {
49129de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
49139566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
49149566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
49159566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4916a3df083aSStefano Zampini             }
49175cbda25cSStefano Zampini           }
49189566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4919a3df083aSStefano Zampini         }
492006656605SStefano Zampini       } else {
49219de2952eSStefano Zampini         const PetscScalar *barr;
49229de2952eSStefano Zampini         PetscScalar       *marr;
49239de2952eSStefano Zampini 
49249de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(Brhs, &barr));
49259de2952eSStefano Zampini         PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
49269de2952eSStefano Zampini         for (i = 0; i < n_eff_vertices; i++) {
49279de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
49289de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
49299566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
49309566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
49319566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
49329566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
493306656605SStefano Zampini         }
49349de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
49359de2952eSStefano Zampini         PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
493606656605SStefano Zampini       }
49379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
49389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4939ffd830a3SStefano Zampini       /* S_VV and S_CV */
494006656605SStefano Zampini       if (n_constraints) {
494106656605SStefano Zampini         Mat B;
494280677318SStefano Zampini 
49439de2952eSStefano Zampini         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_vertices, NULL, &B));
49449de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, B));
49459de2952eSStefano Zampini 
49469de2952eSStefano Zampini         /* S_CV = pcbddc->local_auxmat1 * B */
49479de2952eSStefano Zampini         if (multi_element) {
49489de2952eSStefano Zampini           Mat T;
49499de2952eSStefano Zampini 
49509de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(B, n_vertices, B_eff_V_J, &T));
49519de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
49529de2952eSStefano Zampini           B = T;
495380677318SStefano Zampini         }
49549de2952eSStefano Zampini         PetscCall(MatProductCreate(pcbddc->local_auxmat1, B, NULL, &S_CV));
49559566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
49569566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
49579566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
49589566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
49599566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
49609566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
49619de2952eSStefano Zampini 
49629de2952eSStefano Zampini         /* B = local_auxmat2_R * S_CV */
49639de2952eSStefano Zampini         PetscCall(MatProductCreate(local_auxmat2_R, S_CV, NULL, &B));
49649566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
49659566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
49669566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
49679566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
49684222ddf1SHong Zhang 
49699566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
49709de2952eSStefano Zampini         PetscCall(MatSetValuesSubMat(*coarse_submat, S_CV, n_constraints, idx_C, n_vertices, idx_V, INSERT_VALUES));
497114393ed6SStefano Zampini 
49729de2952eSStefano Zampini         if (multi_element) {
49739de2952eSStefano Zampini           Mat T;
49749de2952eSStefano Zampini 
49759de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
49769de2952eSStefano Zampini           PetscCall(MatDestroy(&A_RRmA_RV));
49779de2952eSStefano Zampini           A_RRmA_RV = T;
49789de2952eSStefano Zampini         }
49799de2952eSStefano Zampini         PetscCall(MatAXPY(A_RRmA_RV, 1.0, B, UNKNOWN_NONZERO_PATTERN)); /* XXX ? */
49809de2952eSStefano Zampini         PetscCall(MatDestroy(&B));
49819de2952eSStefano Zampini       } else if (multi_element) {
49829de2952eSStefano Zampini         Mat T;
49839de2952eSStefano Zampini 
49849de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
49859de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
49869de2952eSStefano Zampini         A_RRmA_RV = T;
49879de2952eSStefano Zampini       }
49889de2952eSStefano Zampini 
49899de2952eSStefano Zampini       if (lda_rhs != n_R) {
49909de2952eSStefano Zampini         Mat T;
49919de2952eSStefano Zampini 
49929de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(A_RRmA_RV, is_R, NULL, MAT_INITIAL_MATRIX, &T));
49939de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
49949de2952eSStefano Zampini         A_RRmA_RV = T;
49959de2952eSStefano Zampini       }
49969de2952eSStefano Zampini 
49979de2952eSStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
49989de2952eSStefano Zampini       if (need_benign_correction) { /* XXX SPARSE */
49999de2952eSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
50009de2952eSStefano Zampini         PetscScalar       *sums;
50019de2952eSStefano Zampini         const PetscScalar *marr;
50029de2952eSStefano Zampini 
50039de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(A_RRmA_RV, &marr));
50049566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
5005df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
500614393ed6SStefano Zampini           const PetscScalar *vals;
500714393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
500814393ed6SStefano Zampini           PetscInt           n, j, nz;
500914393ed6SStefano Zampini 
50109566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
50119566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
501214393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
501314393ed6SStefano Zampini             sums[j] = 0.;
50149de2952eSStefano Zampini             for (PetscInt k = 0; k < nz; k++) sums[j] += marr[idxs_zero[k] + j * n_R];
501514393ed6SStefano Zampini           }
50169566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
501714393ed6SStefano Zampini           for (j = 0; j < n; j++) {
501814393ed6SStefano Zampini             PetscScalar val = vals[j];
50199de2952eSStefano 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));
502014393ed6SStefano Zampini           }
50219566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
50229566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
502314393ed6SStefano Zampini         }
50249566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
50259566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
50269de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(A_RRmA_RV, &marr));
502714393ed6SStefano Zampini       }
50289de2952eSStefano Zampini 
5029fb842aefSJose E. Roman       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_VV));
50309de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
50319de2952eSStefano Zampini       PetscCall(MatDestroy(&S_VV));
5032d16cbb6bSStefano Zampini     }
5033d16cbb6bSStefano Zampini 
503406656605SStefano Zampini     /* coarse basis functions */
50359de2952eSStefano Zampini     if (coarse_phi_multi) {
50369de2952eSStefano Zampini       Mat Vid;
503716f15bc4SStefano Zampini 
50389de2952eSStefano Zampini       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, n_vertices, n_vertices, 1, NULL, &Vid));
50399de2952eSStefano Zampini       PetscCall(MatShift_Basic(Vid, 1.0));
50409de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 0, A_RRmA_RV));
50419de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 1, 0, Vid));
50429de2952eSStefano Zampini       PetscCall(MatDestroy(&Vid));
50439de2952eSStefano Zampini     } else {
50449de2952eSStefano Zampini       if (A_RRmA_RV) {
50459de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, pcbddc->coarse_phi_B));
504606656605SStefano Zampini         if (pcbddc->switch_static || pcbddc->dbg_flag) {
50479de2952eSStefano Zampini           PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_D, pcbddc->coarse_phi_D));
50489de2952eSStefano Zampini           if (pcbddc->benign_n) {
50493a7d0413SPierre Jolivet             for (i = 0; i < n_vertices; i++) PetscCall(MatSetValues(pcbddc->coarse_phi_D, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES));
50508a162dc6SStefano Zampini             PetscCall(MatAssemblyBegin(pcbddc->coarse_phi_D, MAT_FINAL_ASSEMBLY));
50518a162dc6SStefano Zampini             PetscCall(MatAssemblyEnd(pcbddc->coarse_phi_D, MAT_FINAL_ASSEMBLY));
5052ab2d12f3SJunchao Zhang           }
505306656605SStefano Zampini         }
505406656605SStefano Zampini       }
50559de2952eSStefano Zampini       for (i = 0; i < n_vertices; i++) PetscCall(MatSetValues(pcbddc->coarse_phi_B, 1, &idx_V_B[i], 1, &i, &one, INSERT_VALUES));
50569de2952eSStefano Zampini       PetscCall(MatAssemblyBegin(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
50579de2952eSStefano Zampini       PetscCall(MatAssemblyEnd(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
50589de2952eSStefano Zampini     }
50599de2952eSStefano Zampini     PetscCall(MatDestroy(&A_RRmA_RV));
50609de2952eSStefano Zampini   }
50619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RV));
50629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
506306656605SStefano Zampini 
506406656605SStefano Zampini   if (n_constraints) {
50659de2952eSStefano Zampini     Mat B, B2;
506606656605SStefano Zampini 
50679566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
50689de2952eSStefano Zampini     PetscCall(MatProductCreate(local_auxmat2_R, S_CC, NULL, &B));
50699566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
50709566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
50719566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
50729566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
5073a961b312SStefano Zampini 
507406656605SStefano Zampini     if (n_vertices) {
507503dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
50769de2952eSStefano Zampini         PetscCall(MatTranspose(S_CV, MAT_INITIAL_MATRIX, &S_VC));
507780677318SStefano Zampini       } else {
5078ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
50799de2952eSStefano Zampini           Mat tB;
508006656605SStefano Zampini 
50819de2952eSStefano Zampini           PetscCall(MatCreateSubMatrix(B, is_R, NULL, MAT_INITIAL_MATRIX, &tB));
50829de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
50839de2952eSStefano Zampini           B = tB;
50849de2952eSStefano Zampini         }
5085fb842aefSJose E. Roman         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &S_VC));
50869de2952eSStefano Zampini       }
50879de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VC, n_vertices, idx_V, n_constraints, idx_C, INSERT_VALUES));
50889de2952eSStefano Zampini     }
50899de2952eSStefano Zampini 
50909de2952eSStefano Zampini     /* coarse basis functions */
50919de2952eSStefano Zampini     if (coarse_phi_multi) {
50929de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 1, B));
50939de2952eSStefano Zampini     } else {
50949de2952eSStefano Zampini       PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_B, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
50959de2952eSStefano Zampini       PetscCall(MatDenseScatter(B, pcbddc->R_to_B, B2));
50969de2952eSStefano Zampini       PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_B, &B2));
509706656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
50989de2952eSStefano Zampini         PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_D, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
50999de2952eSStefano Zampini         PetscCall(MatDenseScatter(B, pcbddc->R_to_D, B2));
51009de2952eSStefano Zampini         if (pcbddc->benign_n) {
51013a7d0413SPierre Jolivet           for (i = 0; i < n_constraints; i++) PetscCall(MatSetValues(B2, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES));
510206656605SStefano Zampini         }
51039de2952eSStefano Zampini         PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_D, &B2));
510406656605SStefano Zampini       }
510506656605SStefano Zampini     }
51069de2952eSStefano Zampini     PetscCall(MatDestroy(&B));
51079de2952eSStefano Zampini   }
51089de2952eSStefano Zampini 
51099de2952eSStefano Zampini   /* assemble sparse coarse basis functions */
51109de2952eSStefano Zampini   if (coarse_phi_multi) {
51119de2952eSStefano Zampini     Mat T;
51129de2952eSStefano Zampini 
51139de2952eSStefano Zampini     PetscCall(MatConvert(coarse_phi_multi, MATSEQAIJ, MAT_INITIAL_MATRIX, &T));
51149de2952eSStefano Zampini     PetscCall(MatDestroy(&coarse_phi_multi));
51159de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(T, pcis->is_B_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_B));
51163a7d0413SPierre Jolivet     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSubMatrix(T, pcis->is_I_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_D));
51179de2952eSStefano Zampini     PetscCall(MatDestroy(&T));
51189de2952eSStefano Zampini   }
51199de2952eSStefano Zampini   PetscCall(MatDestroy(&local_auxmat2_R));
51209566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
512172b8c272SStefano Zampini 
512272b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
512372b8c272SStefano Zampini   if (pcbddc->benign_n) {
512472b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
512572b8c272SStefano Zampini     IS                 is_dummy;
51261683a169SBarry Smith     const PetscScalar *data;
512772b8c272SStefano Zampini     PetscInt           j;
512872b8c272SStefano Zampini 
51299566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
51309566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
51319566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
51329566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
51339566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
51349566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
513572b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
513672b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
513772b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
51389de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, primal_idx, i, data[i * pcbddc->benign_n + j], INSERT_VALUES));
51399de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, i, primal_idx, data[i * pcbddc->benign_n + j], INSERT_VALUES));
514072b8c272SStefano Zampini       }
514172b8c272SStefano Zampini     }
51429566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
51439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
51449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
514572b8c272SStefano Zampini   }
5146019a44ceSStefano Zampini 
514706656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
51483301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
5149ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
51509de2952eSStefano Zampini     PetscScalar *marray, *work;
515106656605SStefano Zampini 
51529de2952eSStefano Zampini     /* TODO multi_element MatDenseScatter */
515306656605SStefano Zampini     if (n_constraints) {
5154ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
515506656605SStefano Zampini 
51569de2952eSStefano Zampini       PetscCall(MatScale(S_CC, m_one));
51579566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
51589566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
5159fb842aefSJose E. Roman       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &B_C));
51609de2952eSStefano Zampini       PetscCall(MatConvert(B_C, MATDENSE, MAT_INPLACE_MATRIX, &B_C));
51619566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
516206656605SStefano Zampini       if (n_vertices) {
5163ffd830a3SStefano Zampini         Mat S_VCT;
516406656605SStefano Zampini 
51659566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
5166fb842aefSJose E. Roman         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &B_V));
51679566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
51689de2952eSStefano Zampini         PetscCall(MatConvert(B_V, MATDENSE, MAT_INPLACE_MATRIX, &B_V));
516906656605SStefano Zampini       }
51709566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
51715b782168SStefano Zampini     } else {
51729566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
517306656605SStefano Zampini     }
517416f15bc4SStefano Zampini     if (n_vertices && n_R) {
5175ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
5176ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
5177ffd830a3SStefano Zampini       PetscInt        n;
5178ffd830a3SStefano Zampini       PetscBool       flg_row;
517906656605SStefano Zampini 
5180ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
51819566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
51829566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
51839566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
51849566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
5185ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
5186ffd830a3SStefano Zampini         PetscInt j;
5187ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
5188ffd830a3SStefano Zampini       }
51899566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
51909566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
51919566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
519206656605SStefano Zampini     }
519306656605SStefano Zampini 
5194ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
51959de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * pcbddc->local_primal_size, &work));
5196abc8f43dSstefano_zampini     if (n_vertices) {
51979566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
5198ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
51999566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
52009566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
52019566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
52029566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
52039566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
52049566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
520506656605SStefano Zampini       }
52069566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
5207abc8f43dSstefano_zampini     }
52085b782168SStefano Zampini     if (B_C) {
52099566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
5210ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
52119566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
52129566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
52139566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
52149566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
52159566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
52169566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
521706656605SStefano Zampini       }
52189566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
52195b782168SStefano Zampini     }
522006656605SStefano Zampini     /* coarse basis functions */
52219de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_B));
52229de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_D));
522306656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
5224ab2d12f3SJunchao Zhang       Vec v;
522506656605SStefano Zampini 
52269566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
52279566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
52289566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
52299566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
523006656605SStefano Zampini       if (i < n_vertices) {
5231ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
52329566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
52339566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
52349566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
523506656605SStefano Zampini       }
52369566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
523706656605SStefano Zampini 
523806656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
52399566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
52409566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
52419566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
52429566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
524306656605SStefano Zampini       }
52449566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
524506656605SStefano Zampini     }
52469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
52479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
52489de2952eSStefano Zampini     PetscCall(PetscFree(work));
52499de2952eSStefano Zampini   } else {
52509de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
52519de2952eSStefano Zampini     pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
52529de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
52539de2952eSStefano Zampini     pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
525406656605SStefano Zampini   }
52559de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(*coarse_submat, MAT_FINAL_ASSEMBLY));
52569de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(*coarse_submat, MAT_FINAL_ASSEMBLY));
5257a6e023c1Sstefano_zampini 
5258d62866d3SStefano Zampini   /* free memory */
52599de2952eSStefano Zampini   PetscCall(PetscFree(V_to_eff_V));
52609de2952eSStefano Zampini   PetscCall(PetscFree(C_to_eff_C));
52619de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_V_J));
52629de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_C_J));
52639de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_V_J));
52649de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_C_J));
52659de2952eSStefano Zampini   PetscCall(ISDestroy(&is_R));
52669de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_V, &idx_V));
52679de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_C, &idx_C));
52689de2952eSStefano Zampini   PetscCall(ISDestroy(&is_V));
52699de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C));
52709566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
52719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
52729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
52739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
527448a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
527548a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
52769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
52778ead10e4SStefano Zampini 
5278da81f932SPierre Jolivet   /* Checking coarse_sub_mat and coarse basis functions */
527988ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
528088ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
5281d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
528225084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
528388ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
528488ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
528588ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
52868bec7fa6SStefano Zampini     Mat       C_B, CPHI;
52878bec7fa6SStefano Zampini     IS        is_dummy;
52888bec7fa6SStefano Zampini     Vec       mones;
528988ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
529088ebb749SStefano Zampini     PetscReal real_value;
529188ebb749SStefano Zampini 
5292a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
5293a3df083aSStefano Zampini       Mat A;
52949566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
52959566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
52969566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
52979566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
52989566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
52999566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
5300a3df083aSStefano Zampini     } else {
53019566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
53029566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
53039566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
53049566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
5305a3df083aSStefano Zampini     }
53069566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
53079566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
5308ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
53099566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
53109566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
531188ebb749SStefano Zampini     }
53129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
53139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
53149566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5315ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
53169566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53179566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
53189566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
53199566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53209566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
53219566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
53229566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53239566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
53249566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
53259566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53269566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
53279566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
532888ebb749SStefano Zampini     } else {
53299566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
53309566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
53319566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53329566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
53339566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
53349566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
53359566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
53369566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
533788ebb749SStefano Zampini     }
53389566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
53399566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
53409566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
53419566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
53424f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5343fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
53441683a169SBarry Smith       const PetscScalar *data2;
53451683a169SBarry Smith       PetscScalar       *data;
53464f1b2e48SStefano Zampini       PetscInt           j;
5347d12edf2fSStefano Zampini 
53489566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
53499566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
53509566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
53519566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
53529566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
53539566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
53544f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
53554f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
5356d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
53574f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
53584f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
53594f1b2e48SStefano Zampini         }
5360d12edf2fSStefano Zampini       }
53619566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
53629566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
53639566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
53649566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
53659566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
5366d12edf2fSStefano Zampini     }
53679de2952eSStefano Zampini     PetscCall(MatAXPY(TM1, m_one, *coarse_submat, DIFFERENT_NONZERO_PATTERN));
53689566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
53699566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
537063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
53718bec7fa6SStefano Zampini 
53728bec7fa6SStefano Zampini     /* check constraints */
53739566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
53749566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
53754f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
53769566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
5377a00504b5SStefano Zampini     } else {
5378a00504b5SStefano Zampini       PetscScalar *data;
5379a00504b5SStefano Zampini       Mat          tmat;
53809566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
53819566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
53829566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
53839566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
53849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
5385a00504b5SStefano Zampini     }
53869566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
53879566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
53889566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
53899566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
539063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
5391ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
53929566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
53939566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
53949566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
53959566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
539663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
539788ebb749SStefano Zampini     }
53989566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
53999566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
54009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
54019566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
54029566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
54039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
54049566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
54059566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
54069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
54079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
54089566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
54099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
54109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
54119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
54129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
5413ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
54149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
54159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
541688ebb749SStefano Zampini     }
541788ebb749SStefano Zampini   }
54187ebab0bbSStefano Zampini 
54199de2952eSStefano Zampini #if 0
54209de2952eSStefano Zampini   {
54219de2952eSStefano Zampini     PetscViewer viewer;
54229de2952eSStefano Zampini     char filename[256];
54239de2952eSStefano Zampini 
54249de2952eSStefano Zampini     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level));
54259de2952eSStefano Zampini     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
54269de2952eSStefano Zampini     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
54279de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)*coarse_submat,"coarse submat"));
54289de2952eSStefano Zampini     PetscCall(MatView(*coarse_submat,viewer));
54299de2952eSStefano Zampini     if (pcbddc->coarse_phi_B) {
54309de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
54319de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
54329de2952eSStefano Zampini     }
54339de2952eSStefano Zampini     if (pcbddc->coarse_phi_D) {
54349de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
54359de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
54369de2952eSStefano Zampini     }
54379de2952eSStefano Zampini     if (pcbddc->coarse_psi_B) {
54389de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
54399de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
54409de2952eSStefano Zampini     }
54419de2952eSStefano Zampini     if (pcbddc->coarse_psi_D) {
54429de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
54439de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
54449de2952eSStefano Zampini     }
54459de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
54469de2952eSStefano Zampini     PetscCall(MatView(pcbddc->local_mat,viewer));
54479de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
54489de2952eSStefano Zampini     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
54499de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
54509de2952eSStefano Zampini     PetscCall(ISView(pcis->is_I_local,viewer));
54519de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
54529de2952eSStefano Zampini     PetscCall(ISView(pcis->is_B_local,viewer));
54539de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
54549de2952eSStefano Zampini     PetscCall(ISView(pcbddc->is_R_local,viewer));
5455648c30bcSBarry Smith     PetscCall(PetscViewerDestroy(&viewer));
54569de2952eSStefano Zampini   }
54579de2952eSStefano Zampini #endif
54589de2952eSStefano Zampini 
54599de2952eSStefano Zampini   /* device support */
54609de2952eSStefano Zampini   {
54619de2952eSStefano Zampini     PetscBool iscuda, iship, iskokkos;
54629de2952eSStefano Zampini     MatType   mtype = NULL;
54639de2952eSStefano Zampini 
54649de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iscuda, VECCUDA, VECMPICUDA, VECSEQCUDA, ""));
54659de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iship, VECHIP, VECMPIHIP, VECSEQHIP, ""));
54669de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iskokkos, VECKOKKOS, VECMPIKOKKOS, VECSEQKOKKOS, ""));
54679de2952eSStefano Zampini     if (iskokkos) {
54689de2952eSStefano Zampini       if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_CUDA)) iscuda = PETSC_TRUE;
54699de2952eSStefano Zampini       else if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_HIP)) iship = PETSC_TRUE;
54709de2952eSStefano Zampini     }
54719de2952eSStefano Zampini     if (iskokkos) mtype = multi_element ? MATSEQAIJKOKKOS : (iscuda ? MATSEQDENSECUDA : MATSEQDENSEHIP);
54729de2952eSStefano Zampini     else if (iship) mtype = multi_element ? MATSEQAIJHIPSPARSE : MATSEQDENSEHIP;
54739de2952eSStefano Zampini     else if (iscuda) mtype = multi_element ? MATSEQAIJCUSPARSE : MATSEQDENSECUDA;
54749de2952eSStefano Zampini     if (mtype) {
54759de2952eSStefano Zampini       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
54769de2952eSStefano Zampini       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
54779de2952eSStefano Zampini       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
54789de2952eSStefano Zampini       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
54799de2952eSStefano Zampini       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
54809de2952eSStefano Zampini       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
54817ebab0bbSStefano Zampini     }
54827ebab0bbSStefano Zampini   }
54833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
548488ebb749SStefano Zampini }
548588ebb749SStefano Zampini 
5486d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B)
5487d71ae5a4SJacob Faibussowitsch {
5488d65f70fdSStefano Zampini   Mat      *work_mat;
5489d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
5490d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
5491c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
5492aa0d41d4SStefano Zampini 
5493aa0d41d4SStefano Zampini   PetscFunctionBegin;
54949566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
54959566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
54969566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
54979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
5498aa0d41d4SStefano Zampini 
5499d65f70fdSStefano Zampini   if (!rsorted) {
5500906d46d4SStefano Zampini     const PetscInt *idxs;
5501906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
5502aa0d41d4SStefano Zampini 
55039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
55049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
5505ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_perm_r[i] = i;
55069566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
55079566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
5508ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_sorted[i] = idxs[idxs_perm_r[i]];
55099566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
55109566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
5511d65f70fdSStefano Zampini   } else {
55129566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
5513d65f70fdSStefano Zampini     isrow_s = isrow;
5514aa0d41d4SStefano Zampini   }
5515906d46d4SStefano Zampini 
5516d65f70fdSStefano Zampini   if (!csorted) {
5517d65f70fdSStefano Zampini     if (isrow == iscol) {
55189566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
5519d65f70fdSStefano Zampini       iscol_s = isrow_s;
5520d65f70fdSStefano Zampini     } else {
5521d65f70fdSStefano Zampini       const PetscInt *idxs;
5522d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
5523906d46d4SStefano Zampini 
55249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
55259566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
5526ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_perm_c[i] = i;
55279566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
55289566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
5529ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_sorted[i] = idxs[idxs_perm_c[i]];
55309566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
55319566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
5532d65f70fdSStefano Zampini     }
5533d65f70fdSStefano Zampini   } else {
55349566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
5535d65f70fdSStefano Zampini     iscol_s = iscol;
5536d65f70fdSStefano Zampini   }
5537d65f70fdSStefano Zampini 
55389566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
5539d65f70fdSStefano Zampini 
5540d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
5541906d46d4SStefano Zampini     Mat new_mat;
5542d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
5543906d46d4SStefano Zampini 
5544d65f70fdSStefano Zampini     if (!rsorted) {
5545d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
55469566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
5547ad540459SPierre Jolivet       for (i = 0; i < rsize; i++) idxs_r[idxs_perm_r[i]] = i;
55489566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
55499566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
5550d65f70fdSStefano Zampini     } else {
55519566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
5552906d46d4SStefano Zampini     }
55539566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
5554d65f70fdSStefano Zampini 
5555d65f70fdSStefano Zampini     if (!csorted) {
5556d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
55579566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
5558d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
5559d65f70fdSStefano Zampini       } else {
5560d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
556128b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
55629566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
5563ad540459SPierre Jolivet         for (i = 0; i < csize; i++) idxs_c[idxs_perm_c[i]] = i;
55649566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
55659566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
5566d65f70fdSStefano Zampini       }
5567d65f70fdSStefano Zampini     } else {
55689566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
5569d65f70fdSStefano Zampini     }
55709566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
5571d65f70fdSStefano Zampini 
55729566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
55739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
5574d65f70fdSStefano Zampini     work_mat[0] = new_mat;
55759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
55769566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
5577d65f70fdSStefano Zampini   }
5578d65f70fdSStefano Zampini 
55799566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
5580d65f70fdSStefano Zampini   *B = work_mat[0];
55819566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
55829566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
55839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
55843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5585d65f70fdSStefano Zampini }
5586d65f70fdSStefano Zampini 
55877b103a85SStefano Zampini static PetscErrorCode MatPtAPWithPrefix_Private(Mat A, Mat P, PetscReal fill, const char *prefix, Mat *C)
55887b103a85SStefano Zampini {
55897b103a85SStefano Zampini   PetscFunctionBegin;
55907b103a85SStefano Zampini   PetscCall(MatProductCreate(A, P, NULL, C));
55917b103a85SStefano Zampini   PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
55927b103a85SStefano Zampini   PetscCall(MatProductSetAlgorithm(*C, "default"));
55937b103a85SStefano Zampini   PetscCall(MatProductSetFill(*C, fill));
55947b103a85SStefano Zampini   PetscCall(MatSetOptionsPrefix(*C, prefix));
55957b103a85SStefano Zampini   PetscCall(MatProductSetFromOptions(*C));
55967b103a85SStefano Zampini   PetscCall(MatProductSymbolic(*C));
55977b103a85SStefano Zampini   PetscCall(MatProductNumeric(*C));
55987b103a85SStefano Zampini   (*C)->symmetric = A->symmetric;
55997b103a85SStefano Zampini   (*C)->spd       = A->spd;
56007b103a85SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
56017b103a85SStefano Zampini }
56027b103a85SStefano Zampini 
5603d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
5604d71ae5a4SJacob Faibussowitsch {
5605aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
56065e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
5607022d8d2bSstefano_zampini   Mat       new_mat, lA;
56085e8657edSStefano Zampini   IS        is_local, is_global;
5609d65f70fdSStefano Zampini   PetscInt  local_size;
5610b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
56117b103a85SStefano Zampini   char      ptapprefix[256];
5612aa0d41d4SStefano Zampini 
5613aa0d41d4SStefano Zampini   PetscFunctionBegin;
56149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
56159566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
56169de2952eSStefano Zampini   if (pcbddc->mat_graph->multi_element) {
56179de2952eSStefano Zampini     Mat     *mats, *bdiags;
56189de2952eSStefano Zampini     IS      *gsubs;
56199de2952eSStefano Zampini     PetscInt nsubs = pcbddc->n_local_subs;
56209de2952eSStefano Zampini 
56219de2952eSStefano Zampini     PetscCall(PetscCalloc1(nsubs * nsubs, &mats));
56227b103a85SStefano Zampini #if 1
56239de2952eSStefano Zampini     PetscCall(PetscMalloc1(nsubs, &gsubs));
56249de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, pcbddc->local_subs[i], &gsubs[i]));
56259de2952eSStefano Zampini     PetscCall(MatCreateSubMatrices(ChangeOfBasisMatrix, nsubs, gsubs, gsubs, MAT_INITIAL_MATRIX, &bdiags));
56269de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISDestroy(&gsubs[i]));
56279de2952eSStefano Zampini     PetscCall(PetscFree(gsubs));
56287b103a85SStefano Zampini #else /* this does not work since MatCreateSubMatrices does not support repeated indices */
56297b103a85SStefano Zampini     Mat *tmats;
56307b103a85SStefano Zampini     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
56317b103a85SStefano Zampini     PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
56327b103a85SStefano Zampini     PetscCall(ISDestroy(&is_local));
56337b103a85SStefano Zampini     PetscCall(MatSetOption(ChangeOfBasisMatrix, MAT_SUBMAT_SINGLEIS, PETSC_TRUE));
56347b103a85SStefano Zampini     PetscCall(MatCreateSubMatrices(ChangeOfBasisMatrix, 1, &is_global, &is_global, MAT_INITIAL_MATRIX, &tmats));
56357b103a85SStefano Zampini     PetscCall(ISDestroy(&is_global));
56367b103a85SStefano Zampini     PetscCall(MatCreateSubMatrices(tmats[0], nsubs, pcbddc->local_subs, pcbddc->local_subs, MAT_INITIAL_MATRIX, &bdiags));
56377b103a85SStefano Zampini     PetscCall(MatDestroySubMatrices(1, &tmats));
56387b103a85SStefano Zampini #endif
56399de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) mats[i * (1 + nsubs)] = bdiags[i];
56409de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, nsubs, pcbddc->local_subs, nsubs, pcbddc->local_subs, mats, &new_mat));
56419de2952eSStefano Zampini     PetscCall(MatConvert(new_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &new_mat));
56429de2952eSStefano Zampini     PetscCall(MatDestroySubMatrices(nsubs, &bdiags));
56439de2952eSStefano Zampini     PetscCall(PetscFree(mats));
56449de2952eSStefano Zampini   } else {
56459566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
56469566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
56479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_local));
56489566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
56499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_global));
56509de2952eSStefano Zampini   }
5651906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
5652906d46d4SStefano Zampini     Vec       x, x_change;
5653906d46d4SStefano Zampini     PetscReal error;
5654906d46d4SStefano Zampini 
56559566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
56569566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
56579566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
56589566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
56599566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
56609566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
566188428137SStefano Zampini     if (!pcbddc->change_interior) {
566288428137SStefano Zampini       const PetscScalar *x, *y, *v;
566388428137SStefano Zampini       PetscReal          lerror = 0.;
566488428137SStefano Zampini       PetscInt           i;
566588428137SStefano Zampini 
56669566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
56679566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
56689566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
566988428137SStefano Zampini       for (i = 0; i < local_size; i++)
56709371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
56719566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
56729566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
56739566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
5674462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
5675637e8532SStefano Zampini       if (error > PETSC_SMALL) {
5676637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
567763a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
5678637e8532SStefano Zampini         } else {
567963a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
5680637e8532SStefano Zampini         }
5681637e8532SStefano Zampini       }
568288428137SStefano Zampini     }
56839566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
56849566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
56859566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
56869566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
5687637e8532SStefano Zampini     if (error > PETSC_SMALL) {
5688637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
568963a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
5690637e8532SStefano Zampini       } else {
569163a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
5692637e8532SStefano Zampini       }
5693637e8532SStefano Zampini     }
56949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
56959566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
5696906d46d4SStefano Zampini   }
5697906d46d4SStefano Zampini 
5698022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
56999566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
5700022d8d2bSstefano_zampini 
570122d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
57027b103a85SStefano Zampini   if (((PetscObject)pc)->prefix) PetscCall(PetscSNPrintf(ptapprefix, sizeof(ptapprefix), "%spc_bddc_change_", ((PetscObject)pc)->prefix));
57037b103a85SStefano Zampini   else PetscCall(PetscSNPrintf(ptapprefix, sizeof(ptapprefix), "pc_bddc_change_"));
57049566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
570522d5777bSStefano Zampini   if (isseqaij) {
57069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
57077b103a85SStefano Zampini     PetscCall(MatPtAPWithPrefix_Private(matis->A, new_mat, PETSC_DEFAULT, ptapprefix, &pcbddc->local_mat));
5708022d8d2bSstefano_zampini     if (lA) {
5709022d8d2bSstefano_zampini       Mat work;
57107b103a85SStefano Zampini       PetscCall(MatPtAPWithPrefix_Private(lA, new_mat, PETSC_DEFAULT, ptapprefix, &work));
57119566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
57129566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5713022d8d2bSstefano_zampini     }
5714aa0d41d4SStefano Zampini   } else {
5715a00504b5SStefano Zampini     Mat work_mat;
57161cf9b237SStefano Zampini 
57179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
57189566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
57197b103a85SStefano Zampini     PetscCall(MatPtAPWithPrefix_Private(work_mat, new_mat, PETSC_DEFAULT, ptapprefix, &pcbddc->local_mat));
57209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
5721022d8d2bSstefano_zampini     if (lA) {
5722022d8d2bSstefano_zampini       Mat work;
57239566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
57247b103a85SStefano Zampini       PetscCall(MatPtAPWithPrefix_Private(work_mat, new_mat, PETSC_DEFAULT, ptapprefix, &work));
57259566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
57269566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5727022d8d2bSstefano_zampini     }
5728aa0d41d4SStefano Zampini   }
5729b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
5730b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
57319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
57323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5733aa0d41d4SStefano Zampini }
5734aa0d41d4SStefano Zampini 
5735d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
5736d71ae5a4SJacob Faibussowitsch {
5737f4f49eeaSPierre Jolivet   PC_IS          *pcis        = (PC_IS *)pc->data;
5738a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
5739d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
574053892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
57413a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
57423a50541eSStefano Zampini   PetscInt        vbs, bs;
57436816873aSStefano Zampini   PetscBT         bitmask = NULL;
5744a64d13efSStefano Zampini 
5745a64d13efSStefano Zampini   PetscFunctionBegin;
5746b23d619eSStefano Zampini   /*
5747b23d619eSStefano Zampini     No need to setup local scatters if
5748b23d619eSStefano Zampini       - primal space is unchanged
5749b23d619eSStefano Zampini         AND
5750b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
5751b23d619eSStefano Zampini         AND
5752b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
5753b23d619eSStefano Zampini   */
57543ba16761SJacob Faibussowitsch   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) PetscFunctionReturn(PETSC_SUCCESS);
5755f4ddd8eeSStefano Zampini   /* destroy old objects */
57569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
57579566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
57589566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
5759a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
5760b371cd4fSStefano Zampini   n_B        = pcis->n_B;
5761b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
5762b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
57633a50541eSStefano Zampini 
5764e602f447SPierre Jolivet   /* Dohrmann's notation: dofs split in R (Remaining: all dofs but the vertices) and V (Vertices) */
57656816873aSStefano Zampini 
576653892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
5767b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
57689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
57699566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
577048a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
57714641a718SStefano Zampini 
5772a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
5773ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, i)) idx_R_local[n_R++] = i;
5774a64d13efSStefano Zampini     }
5775df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5776df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
57776816873aSStefano Zampini 
57789566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
57799566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
57806816873aSStefano Zampini   }
57813a50541eSStefano Zampini 
57823a50541eSStefano Zampini   /* Block code */
57833a50541eSStefano Zampini   vbs = 1;
57849566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
57853a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
57863a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
57873a50541eSStefano Zampini     PetscInt *vary;
5788b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
57899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
57909566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
5791d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5792d3df7717SStefano 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 */
57930e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5794d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
57953a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
57963a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
57973a50541eSStefano Zampini           break;
57983a50541eSStefano Zampini         }
57993a50541eSStefano Zampini       }
58009566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5801d3df7717SStefano Zampini     } else {
5802d3df7717SStefano Zampini       /* Verify directly the R set */
5803d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5804d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5805d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5806d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5807d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5808d3df7717SStefano Zampini             break;
5809d3df7717SStefano Zampini           }
5810d3df7717SStefano Zampini         }
5811d3df7717SStefano Zampini       }
5812d3df7717SStefano Zampini     }
58133a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
58143a50541eSStefano Zampini       vbs = bs;
5815ad540459SPierre Jolivet       for (i = 0; i < n_R / vbs; i++) idx_R_local[i] = idx_R_local[vbs * i] / vbs;
58163a50541eSStefano Zampini     }
58173a50541eSStefano Zampini   }
58189566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5819b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5820df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
582153892102SStefano Zampini 
58229566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
58239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
58249566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5825df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
582653892102SStefano Zampini   } else {
58279566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
582853892102SStefano Zampini   }
5829a64d13efSStefano Zampini 
5830a64d13efSStefano Zampini   /* print some info if requested */
5831a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
58329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
58339566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
58349566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
58359566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
583663a3b9bcSJacob 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));
58379371c9d4SSatish 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,
58389371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
58399566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5840a64d13efSStefano Zampini   }
5841a64d13efSStefano Zampini 
5842a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5843b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
58446816873aSStefano Zampini     IS        is_aux1, is_aux2;
58456816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
58466816873aSStefano Zampini 
58479566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
58489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
58499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
58509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
585148a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
58529566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5853a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
5854ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5855a64d13efSStefano Zampini     }
58569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
58579566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5858a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
5859ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, is_indices[i])) aux_array2[j++] = i;
5860a64d13efSStefano Zampini     }
58619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
58629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
58639566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
58649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
58659566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5866a64d13efSStefano Zampini 
58678eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
58689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5869a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
5870ad540459SPierre Jolivet         if (PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5871a64d13efSStefano Zampini       }
58729566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
58739566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
58749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5875a64d13efSStefano Zampini     }
58769566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
58779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5878d62866d3SStefano Zampini   } else {
5879df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
58806816873aSStefano Zampini     IS                 tis;
58816816873aSStefano Zampini     PetscInt           schur_size;
58826816873aSStefano Zampini 
58839566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
58849566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
58859566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
58869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
58876816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
58889566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
58899566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
58909566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5891d62866d3SStefano Zampini     }
5892d62866d3SStefano Zampini   }
58933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5894a64d13efSStefano Zampini }
5895a64d13efSStefano Zampini 
5896e1614d24SStefano Zampini PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B)
5897d71ae5a4SJacob Faibussowitsch {
589892cccca0SStefano Zampini   MatNullSpace NullSpace;
589992cccca0SStefano Zampini   Mat          dmat;
590092cccca0SStefano Zampini   const Vec   *nullvecs;
590192cccca0SStefano Zampini   Vec          v, v2, *nullvecs2;
59026d9e27e4SStefano Zampini   VecScatter   sct = NULL;
5903eb06acf8SStefano Zampini   PetscScalar *ddata;
5904295df10fSStefano Zampini   PetscInt     k, nnsp_size, bsiz, bsiz2, n, N, bs;
590592cccca0SStefano Zampini   PetscBool    nnsp_has_cnst;
590692cccca0SStefano Zampini 
590792cccca0SStefano Zampini   PetscFunctionBegin;
59086d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
59096d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
59106d9e27e4SStefano Zampini 
591148a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
59126d9e27e4SStefano Zampini     sct = matis->cctx;
59139566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
59146d9e27e4SStefano Zampini   } else {
59159566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
591648a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
59173ba16761SJacob Faibussowitsch     if (NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
59186d9e27e4SStefano Zampini   }
59199566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
592048a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
59213ba16761SJacob Faibussowitsch   if (!NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
59226d9e27e4SStefano Zampini 
59239566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
59249566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
592548a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
5926835f2295SStefano Zampini   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, &nullvecs));
5927295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
59289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
59299566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
59309566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
59319566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
59329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
593392cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
59349566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
59359566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
59369566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
593792cccca0SStefano Zampini   }
593892cccca0SStefano Zampini   if (nnsp_has_cnst) {
59399566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
59409566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
594192cccca0SStefano Zampini   }
59429566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
59439566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5944295df10fSStefano Zampini 
59459566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
594649abdd8aSBarry Smith   PetscCall(PetscObjectContainerCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", ddata, PetscCtxDestroyDefault));
59479566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
59489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5949eb06acf8SStefano Zampini 
595048a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
59519566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
59529566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
59539566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
59549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
59559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
59569566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
59573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
595892cccca0SStefano Zampini }
5959304d26faSStefano Zampini 
5960d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5961d71ae5a4SJacob Faibussowitsch {
5962304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5963304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5964304d26faSStefano Zampini   PC           pc_temp;
5965304d26faSStefano Zampini   Mat          A_RR;
596692cccca0SStefano Zampini   MatNullSpace nnsp;
5967f4ddd8eeSStefano Zampini   MatReuse     reuse;
5968304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5969304d26faSStefano Zampini   PetscReal    value;
597004708bb6SStefano Zampini   PetscInt     n_D, n_R;
5971b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
59720cd8b6e2SStefano Zampini   PetscBool    f = PETSC_FALSE;
5973312be037SStefano Zampini   char         dir_prefix[256], neu_prefix[256], str_level[16];
5974e604994aSStefano Zampini   size_t       len;
5975304d26faSStefano Zampini 
5976304d26faSStefano Zampini   PetscFunctionBegin;
59779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
59786d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
59796d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
59806d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
59816d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
59826d9e27e4SStefano Zampini 
59839566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
59849566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
59859566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
59866d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
59875440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(&lhas, &ghas, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
598848a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
59896d9e27e4SStefano Zampini   }
59906d9e27e4SStefano Zampini 
5991e604994aSStefano Zampini   /* compute prefixes */
5992c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(dir_prefix, "", sizeof(dir_prefix)));
5993c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(neu_prefix, "", sizeof(neu_prefix)));
5994e604994aSStefano Zampini   if (!pcbddc->current_level) {
59959566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
59969566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
59979566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
59989566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5999e604994aSStefano Zampini   } else {
6000835f2295SStefano Zampini     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%" PetscInt_FMT "_", pcbddc->current_level));
60019566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
6002e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
6003312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
6004312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
6005a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
60069566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
60079566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
60089566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
60099566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
60109566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
60119566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
6012e604994aSStefano Zampini   }
6013e604994aSStefano Zampini 
6014304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
6015684f6988SStefano Zampini   if (dirichlet) {
6016d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6017450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
60187827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
6019450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
6020a3df083aSStefano Zampini         Mat A_IIn;
6021a3df083aSStefano Zampini 
60229566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
60239566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
6024a3df083aSStefano Zampini         pcis->A_II = A_IIn;
6025a3df083aSStefano Zampini       }
6026450f8f5eSStefano Zampini     }
6027b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
6028b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
6029b94d7dedSBarry Smith 
6030ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
6031964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
603292cccca0SStefano Zampini     opts = PETSC_FALSE;
6033304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
603492cccca0SStefano Zampini       opts = PETSC_TRUE;
60359566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
60363821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_D, pc->kspnestlevel));
60379566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
6038304d26faSStefano Zampini       /* default */
60399566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
60409566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
60419566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
60429566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
60439577ea80SStefano Zampini       if (issbaij) {
60449566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
60459577ea80SStefano Zampini       } else {
60469566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
60479577ea80SStefano Zampini       }
60489566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
604992cccca0SStefano Zampini     }
60509566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
60519de2952eSStefano Zampini     PetscCall(MatViewFromOptions(pcis->pA_II, NULL, "-mat_view"));
60529566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
6053304d26faSStefano Zampini     /* Allow user's customization */
60541baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
60559566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
60566d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
60579566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
605892cccca0SStefano Zampini     }
60599566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
60609566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
60610cd8b6e2SStefano Zampini     PetscCall(PetscObjectHasFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
606292cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
6063cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
6064cd18cfedSStefano Zampini       const PetscInt *idxs;
6065cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
6066cd18cfedSStefano Zampini 
60679566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
60689566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
60699566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
6070cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
6071ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
6072cd18cfedSStefano Zampini       }
60739566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
60749566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
60759566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
6076cd18cfedSStefano Zampini     }
6077b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
6078df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6079d62866d3SStefano Zampini 
60809566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
6081d5574798SStefano Zampini     }
608292cccca0SStefano Zampini 
6083304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
6084304d26faSStefano Zampini     if (!n_D) {
60859566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
60869566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
6087304d26faSStefano Zampini     }
60889566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
6089304d26faSStefano Zampini     /* set ksp_D into pcis data */
60909566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
60919566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
6092304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
6093684f6988SStefano Zampini   }
6094304d26faSStefano Zampini 
6095304d26faSStefano Zampini   /* NEUMANN PROBLEM */
60960a545947SLisandro Dalcin   A_RR = NULL;
6097684f6988SStefano Zampini   if (neumann) {
6098d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
609904708bb6SStefano Zampini     PetscInt        ibs, mbs;
6100b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
610104708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
61020aa714b2SStefano Zampini 
61030aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
61040aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
61050aa714b2SStefano Zampini       IS iP;
61060aa714b2SStefano Zampini 
61070aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
61089566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
61090aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
61100aa714b2SStefano Zampini     }
6111f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
61129566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
6113f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
6114f4ddd8eeSStefano Zampini       PetscInt nn_R;
61159566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
61169566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
61179566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
6118f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
61199566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
61209566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
6121f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
6122f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
6123727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
61249566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
6125f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
6126f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
6127f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
6128f4ddd8eeSStefano Zampini         }
6129f4ddd8eeSStefano Zampini       }
6130f4ddd8eeSStefano Zampini       /* last check */
6131d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
61329566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
6133f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
6134f4ddd8eeSStefano Zampini       }
6135f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
6136f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
6137f4ddd8eeSStefano Zampini     }
6138365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
6139365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
61409566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
61419566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
61429566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
614304708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
614404708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
61459566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
61469566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
6147af732b37SStefano Zampini       } else {
61489566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
61496816873aSStefano Zampini       }
61504cf0e950SBarry Smith     } else if (issbaij) { /* need to convert to BAIJ to get off-diagonal blocks */
615104708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
61529566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
61539566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
615404708bb6SStefano Zampini       } else {
61559566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
615604708bb6SStefano Zampini       }
615704708bb6SStefano Zampini     }
6158a00504b5SStefano Zampini     /* extract A_RR */
61590aa714b2SStefano Zampini     if (reuse_neumann_solver) {
6160a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6161a00504b5SStefano Zampini 
6162a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
61639566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
6164a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
61659566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
616616e386b8SStefano Zampini         } else {
61679566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
6168a00504b5SStefano Zampini         }
6169a00504b5SStefano Zampini       } else {
61709566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
61719566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
61729566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
6173a00504b5SStefano Zampini       }
6174a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
61759566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
617616e386b8SStefano Zampini     }
6177b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
6178b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
617992cccca0SStefano Zampini     opts = PETSC_FALSE;
6180f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
618192cccca0SStefano Zampini       opts = PETSC_TRUE;
61829566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
61833821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_R, pc->kspnestlevel));
61849566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
6185304d26faSStefano Zampini       /* default */
61869566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
61879566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
61889566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
61899566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
61909577ea80SStefano Zampini       if (issbaij) {
61919566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
61929577ea80SStefano Zampini       } else {
61939566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
61949577ea80SStefano Zampini       }
61959566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
619692cccca0SStefano Zampini     }
61979566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
61989de2952eSStefano Zampini     PetscCall(MatViewFromOptions(A_RR, NULL, "-mat_view"));
61999de2952eSStefano Zampini     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
620092cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
62019566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
620292cccca0SStefano Zampini     }
62039566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
62046d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
62059566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
620692cccca0SStefano Zampini     }
62079566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
62089566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
62090cd8b6e2SStefano Zampini     PetscCall(PetscObjectHasFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
621092cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
6211cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
6212cd18cfedSStefano Zampini       const PetscInt *idxs;
6213cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
6214cd18cfedSStefano Zampini 
62159566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
62169566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
62179566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
6218cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
6219ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
6220cd18cfedSStefano Zampini       }
62219566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
62229566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
62239566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
6224cd18cfedSStefano Zampini     }
622592cccca0SStefano Zampini 
6226304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
6227304d26faSStefano Zampini     if (!n_R) {
62289566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
62299566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
6230304d26faSStefano Zampini     }
6231df4d28bfSStefano Zampini     /* Reuse solver if it is present */
62320aa714b2SStefano Zampini     if (reuse_neumann_solver) {
6233df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6234d62866d3SStefano Zampini 
62359566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
6236d62866d3SStefano Zampini     }
62379566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
6238684f6988SStefano Zampini   }
6239304d26faSStefano Zampini 
6240684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
62419566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
62429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
62439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
6244684f6988SStefano Zampini   }
62459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
6246c7017625SStefano Zampini 
6247c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
624848a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
624948a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
625048a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
6251c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
6252c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
6253684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
62549566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
62559566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
62569566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
62579566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
62589566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
62599566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
6260f4f49eeaSPierre 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));
62619566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6262304d26faSStefano Zampini     }
6263684f6988SStefano Zampini     if (neumann) { /* Neumann */
62649566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
62659566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
62669566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
62679566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
62689566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
62699566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
6270f4f49eeaSPierre 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));
62719566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6272304d26faSStefano Zampini     }
6273684f6988SStefano Zampini   }
62745cbda25cSStefano Zampini   /* free Neumann problem's matrix */
62759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
62763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6277304d26faSStefano Zampini }
6278304d26faSStefano Zampini 
6279d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
6280d71ae5a4SJacob Faibussowitsch {
6281f4f49eeaSPierre Jolivet   PC_BDDC        *pcbddc       = (PC_BDDC *)pc->data;
6282be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
6283b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
6284674ae819SStefano Zampini 
6285674ae819SStefano Zampini   PetscFunctionBegin;
628648a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
628780677318SStefano Zampini   if (!pcbddc->switch_static) {
628880677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
62899566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
62909566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
629120c7b377SStefano Zampini     }
6292b334f244SStefano Zampini     if (!reuse_solver) {
62939566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
62949566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
629520c7b377SStefano Zampini     } else {
6296df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6297be83ff47SStefano Zampini 
62989566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
62999566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
630020c7b377SStefano Zampini     }
6301be83ff47SStefano Zampini   } else {
63029566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
63039566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
63049566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
63059566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
630680677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
63079566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
63089566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
63099566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
63109566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
6311674ae819SStefano Zampini     }
6312674ae819SStefano Zampini   }
63139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
6314b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
631580677318SStefano Zampini     if (applytranspose) {
63169566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
631780677318SStefano Zampini     } else {
63189566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
631980677318SStefano Zampini     }
63209566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
6321be83ff47SStefano Zampini   } else {
6322df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6323be83ff47SStefano Zampini 
6324be83ff47SStefano Zampini     if (applytranspose) {
63259566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6326be83ff47SStefano Zampini     } else {
63279566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6328be83ff47SStefano Zampini     }
6329be83ff47SStefano Zampini   }
63309566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
63319566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
633280677318SStefano Zampini   if (!pcbddc->switch_static) {
6333b334f244SStefano Zampini     if (!reuse_solver) {
63349566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
63359566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
6336be83ff47SStefano Zampini     } else {
6337df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6338be83ff47SStefano Zampini 
63399566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
63409566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
6341be83ff47SStefano Zampini     }
634280677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
63439566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
63449566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
634580677318SStefano Zampini     }
634680677318SStefano Zampini   } else {
63479566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
63489566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
63499566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
63509566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
635180677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
63529566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
63539566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
635480677318SStefano Zampini     }
63559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
63569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
63579566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
63589566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
6359674ae819SStefano Zampini   }
63603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6361674ae819SStefano Zampini }
6362674ae819SStefano Zampini 
6363dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
6364d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
6365d71ae5a4SJacob Faibussowitsch {
6366f4f49eeaSPierre Jolivet   PC_BDDC          *pcbddc = (PC_BDDC *)pc->data;
6367f4f49eeaSPierre Jolivet   PC_IS            *pcis   = (PC_IS *)pc->data;
6368674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
6369674ae819SStefano Zampini 
6370674ae819SStefano Zampini   PetscFunctionBegin;
6371dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
63724fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6373dc359a40SStefano Zampini     if (applytranspose) {
63749566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
63759566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
6376dc359a40SStefano Zampini     } else {
63779566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
63789566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
637915aaf578SStefano Zampini     }
63804fee134fSStefano Zampini   } else {
63819566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
63824fee134fSStefano Zampini   }
6383efc2fbd9SStefano Zampini 
6384efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
63854f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
6386efc2fbd9SStefano Zampini     PetscScalar *array;
63874f1b2e48SStefano Zampini     PetscInt     j;
6388efc2fbd9SStefano Zampini 
63899566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
63904f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
63919566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6392efc2fbd9SStefano Zampini   }
6393efc2fbd9SStefano Zampini 
639412edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
63959566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
63969566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
63979566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
639812edc857SStefano Zampini 
63999f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
6400a1cb837bSStefano Zampini   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
640112edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
640251694757SStefano Zampini     Mat          coarse_mat;
6403964fefecSStefano Zampini     Vec          rhs, sol;
640451694757SStefano Zampini     MatNullSpace nullsp;
640527b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
6406964fefecSStefano Zampini 
640727b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
640827b6a85dSStefano Zampini       PC coarse_pc;
640927b6a85dSStefano Zampini 
64109566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
64119566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
641227b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
641327b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
6414f4f49eeaSPierre Jolivet         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)coarse_pc->data;
641527b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
64163bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
641727b6a85dSStefano Zampini       }
641827b6a85dSStefano Zampini     }
64199566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
64209566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
64219566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
642212edc857SStefano Zampini     if (applytranspose) {
642328b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
64249566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
64259566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
64269566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
64271baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
64282701bc32SStefano Zampini     } else {
64299566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
64301f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
64312701bc32SStefano Zampini         PC coarse_pc;
64322701bc32SStefano Zampini 
64331baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
64349566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
64359566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
64369566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
64379566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
643812edc857SStefano Zampini       } else {
64399566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
64409566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
64411baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
644212edc857SStefano Zampini       }
64432701bc32SStefano Zampini     }
64441d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
644527b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
644627b6a85dSStefano Zampini       PC       coarse_pc;
644727b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
644827b6a85dSStefano Zampini 
64499566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
6450f4f49eeaSPierre Jolivet       coarsepcbddc                           = (PC_BDDC *)coarse_pc->data;
645127b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
64523bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
645327b6a85dSStefano Zampini     }
645412edc857SStefano Zampini   }
6455a1cb837bSStefano Zampini   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
6456674ae819SStefano Zampini 
6457674ae819SStefano Zampini   /* Local solution on R nodes */
6458a1cb837bSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
64599f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
64609566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
64619566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
6462674ae819SStefano Zampini 
64634fee134fSStefano Zampini   /* Sum contributions from the two levels */
64644fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6465dc359a40SStefano Zampini     if (applytranspose) {
64669566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
64679566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6468dc359a40SStefano Zampini     } else {
64699566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
64709566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6471dc359a40SStefano Zampini     }
6472efc2fbd9SStefano Zampini     /* store p0 */
64734f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
6474efc2fbd9SStefano Zampini       PetscScalar *array;
64754f1b2e48SStefano Zampini       PetscInt     j;
6476efc2fbd9SStefano Zampini 
64779566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
64784f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
64799566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6480efc2fbd9SStefano Zampini     }
64814fee134fSStefano Zampini   } else { /* expand the coarse solution */
64824fee134fSStefano Zampini     if (applytranspose) {
64839566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
64844fee134fSStefano Zampini     } else {
64859566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
64864fee134fSStefano Zampini     }
64874fee134fSStefano Zampini   }
64883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6489674ae819SStefano Zampini }
6490674ae819SStefano Zampini 
6491d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode)
6492d71ae5a4SJacob Faibussowitsch {
6493f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
649412edc857SStefano Zampini   Vec                from, to;
64957ebab0bbSStefano Zampini   const PetscScalar *array;
6496674ae819SStefano Zampini 
6497674ae819SStefano Zampini   PetscFunctionBegin;
649812edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
649912edc857SStefano Zampini     from = pcbddc->coarse_vec;
650012edc857SStefano Zampini     to   = pcbddc->vec1_P;
650112edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
650212edc857SStefano Zampini       Vec tvec;
650358da7f69SStefano Zampini 
65049566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
65059566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
65069566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
65079566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
65089566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
65099566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
651012edc857SStefano Zampini     }
6511dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
651212edc857SStefano Zampini     from = pcbddc->vec1_P;
651312edc857SStefano Zampini     to   = pcbddc->coarse_vec;
651412edc857SStefano Zampini   }
65159566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
65163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6517674ae819SStefano Zampini }
6518674ae819SStefano Zampini 
6519d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
6520d71ae5a4SJacob Faibussowitsch {
6521f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
652212edc857SStefano Zampini   Vec                from, to;
65237ebab0bbSStefano Zampini   const PetscScalar *array;
6524674ae819SStefano Zampini 
6525674ae819SStefano Zampini   PetscFunctionBegin;
652612edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
652712edc857SStefano Zampini     from = pcbddc->coarse_vec;
652812edc857SStefano Zampini     to   = pcbddc->vec1_P;
6529dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
653012edc857SStefano Zampini     from = pcbddc->vec1_P;
653112edc857SStefano Zampini     to   = pcbddc->coarse_vec;
653212edc857SStefano Zampini   }
65339566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
653412edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
653512edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
653612edc857SStefano Zampini       Vec tvec;
653758da7f69SStefano Zampini 
65389566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
65399566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
65409566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
65419566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
654258da7f69SStefano Zampini     }
654358da7f69SStefano Zampini   } else {
654458da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
65459566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
654612edc857SStefano Zampini     }
654712edc857SStefano Zampini   }
65483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6549674ae819SStefano Zampini }
6550674ae819SStefano Zampini 
6551d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
6552d71ae5a4SJacob Faibussowitsch {
6553f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
6554674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
6555674ae819SStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
6556984c4197SStefano Zampini   /* one and zero */
6557984c4197SStefano Zampini   PetscScalar one = 1.0, zero = 0.0;
6558984c4197SStefano Zampini   /* space to store constraints and their local indices */
65599162d606SStefano Zampini   PetscScalar *constraints_data;
65609162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
65619162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
65629162d606SStefano Zampini   PetscInt    *constraints_n;
6563984c4197SStefano Zampini   /* iterators */
6564b3d85658SStefano Zampini   PetscInt i, j, k, total_counts, total_counts_cc, cum;
6565984c4197SStefano Zampini   /* BLAS integers */
6566e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
6567e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
6568c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
6569727cdba6SStefano Zampini   /* reuse */
65700e6343abSStefano Zampini   PetscInt  olocal_primal_size, olocal_primal_size_cc;
65710e6343abSStefano Zampini   PetscInt *olocal_primal_ref_node, *olocal_primal_ref_mult;
6572984c4197SStefano Zampini   /* change of basis */
6573b3d85658SStefano Zampini   PetscBool qr_needed;
65749162d606SStefano Zampini   PetscBT   change_basis, qr_needed_idx;
6575984c4197SStefano Zampini   /* auxiliary stuff */
657664efe560SStefano Zampini   PetscInt *nnz, *is_indices;
65778a0068c3SStefano Zampini   PetscInt  ncc;
6578984c4197SStefano Zampini   /* some quantities */
657945a1bb75SStefano Zampini   PetscInt  n_vertices, total_primal_vertices, valid_constraints;
6580a58a30b4SStefano Zampini   PetscInt  size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
658157715f18SStefano Zampini   PetscReal tol; /* tolerance for retaining eigenmodes */
6582984c4197SStefano Zampini 
6583674ae819SStefano Zampini   PetscFunctionBegin;
658457715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
65858e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
65869566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
65879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
65889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
6589088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
6590088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
65910e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
65929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
65939566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
65949566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
65959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
65969566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
6597cf5a6209SStefano Zampini 
6598cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
65999162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
6600cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
6601cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
6602cf5a6209SStefano Zampini     Vec         *localnearnullsp;
6603cf5a6209SStefano Zampini     PetscScalar *array;
660432fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
6605cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
6606674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
6607b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
6608674ae819SStefano Zampini     PetscScalar *work;
6609674ae819SStefano Zampini     PetscReal   *singular_vals;
6610674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
6611674ae819SStefano Zampini     PetscReal *rwork;
6612674ae819SStefano Zampini #endif
661355080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
6614964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
6615964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
661655080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
6617674ae819SStefano Zampini 
661855080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
6619b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
662055080a34SStefano Zampini     use_pod = PETSC_TRUE;
662155080a34SStefano Zampini #endif
6622674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
66239566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
662432fe681dSStefano Zampini     o_nf       = n_ISForFaces;
662532fe681dSStefano Zampini     o_ne       = n_ISForEdges;
662632fe681dSStefano Zampini     n_vertices = 0;
662732fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
6628e4d548c7SStefano Zampini     /* print some info */
66295c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
663032fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
66319566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
66329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
66339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
663432fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
663563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
663663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
66379566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
66389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
6639e4d548c7SStefano Zampini     }
6640e4d548c7SStefano Zampini 
664132fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
664232fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
664332fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
664470022509SStefano Zampini 
6645674ae819SStefano Zampini     /* check if near null space is attached to global mat */
6646ac530a7eSPierre Jolivet     if (pcbddc->use_nnsp) PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
6647ac530a7eSPierre Jolivet     else nearnullsp = NULL;
66486d9e27e4SStefano Zampini 
6649674ae819SStefano Zampini     if (nearnullsp) {
66509566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
6651f4ddd8eeSStefano Zampini       /* remove any stored info */
66529566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
66539566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
6654f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
66559566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
6656f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
66579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
665848a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
6659984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
6660984c4197SStefano Zampini       nnsp_size     = 0;
6661674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
6662674ae819SStefano Zampini     }
6663984c4197SStefano Zampini     /* get max number of constraints on a single cc */
6664984c4197SStefano Zampini     max_constraints = nnsp_size;
6665984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
6666984c4197SStefano Zampini 
6667674ae819SStefano Zampini     /*
6668674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
66699162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
66709162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
66719162d606SStefano Zampini          There can be multiple constraints per connected component
6672674ae819SStefano Zampini                                                                                                                                                            */
66739162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
66749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
66759162d606SStefano Zampini 
66769162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
66779162d606SStefano Zampini     total_counts *= max_constraints;
6678674ae819SStefano Zampini     total_counts += n_vertices;
66799566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
66809162d606SStefano Zampini 
6681674ae819SStefano Zampini     total_counts           = 0;
6682674ae819SStefano Zampini     max_size_of_constraint = 0;
6683674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
66849162d606SStefano Zampini       IS used_is;
6685674ae819SStefano Zampini       if (i < n_ISForEdges) {
66869162d606SStefano Zampini         used_is = ISForEdges[i];
6687674ae819SStefano Zampini       } else {
66889162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
6689674ae819SStefano Zampini       }
66909566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
6691674ae819SStefano Zampini       total_counts += j;
6692674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
6693674ae819SStefano Zampini     }
66949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
66959162d606SStefano Zampini 
6696984c4197SStefano Zampini     /* get local part of global near null space vectors */
66979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
6698984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
66999566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
67009566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
67019566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
6702984c4197SStefano Zampini     }
6703674ae819SStefano Zampini 
6704242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
6705242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
6706a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
6707242a89d7SStefano Zampini 
6708984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
6709a773dcb8SStefano Zampini     if (!skip_lapack) {
6710674ae819SStefano Zampini       PetscScalar temp_work;
6711911cabfeSStefano Zampini 
671255080a34SStefano Zampini       if (use_pod) {
6713984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
67149566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
67159566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
67169566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
6717674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
67189566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
6719674ae819SStefano Zampini #endif
6720674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
67219566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
67229566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
6723674ae819SStefano Zampini         lwork = -1;
67249566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6725674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6726792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
6727674ae819SStefano Zampini #else
6728792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
6729674ae819SStefano Zampini #endif
67309566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
6731835f2295SStefano Zampini         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %" PetscBLASInt_FMT, lierr);
673255080a34SStefano Zampini       } else {
673355080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
6734674ae819SStefano Zampini         /* SVD */
6735674ae819SStefano Zampini         PetscInt max_n, min_n;
6736674ae819SStefano Zampini         max_n = max_size_of_constraint;
6737984c4197SStefano Zampini         min_n = max_constraints;
6738984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
6739674ae819SStefano Zampini           min_n = max_size_of_constraint;
6740984c4197SStefano Zampini           max_n = max_constraints;
6741674ae819SStefano Zampini         }
67429566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
6743674ae819SStefano Zampini   #if defined(PETSC_USE_COMPLEX)
67449566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
6745674ae819SStefano Zampini   #endif
6746674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
6747674ae819SStefano Zampini         lwork = -1;
67489566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
67499566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
67509566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
67519566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6752674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6753792fecdfSBarry 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));
6754674ae819SStefano Zampini   #else
6755792fecdfSBarry 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));
6756674ae819SStefano Zampini   #endif
67579566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
6758835f2295SStefano Zampini         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %" PetscBLASInt_FMT, lierr);
675955080a34SStefano Zampini #else
676055080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6761984c4197SStefano Zampini #endif /* on missing GESVD */
676255080a34SStefano Zampini       }
6763674ae819SStefano Zampini       /* Allocate optimal workspace */
67649566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
67659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
6766674ae819SStefano Zampini     }
6767674ae819SStefano Zampini     /* Now we can loop on constraining sets */
6768674ae819SStefano Zampini     total_counts            = 0;
67699162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
67709162d606SStefano Zampini     constraints_data_ptr[0] = 0;
6771674ae819SStefano Zampini     /* vertices */
67729162d606SStefano Zampini     if (n_vertices) {
67739566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
67749566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
6775674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
67769162d606SStefano Zampini         constraints_n[total_counts]            = 1;
67779162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
67789162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
67799162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
6780674ae819SStefano Zampini         total_counts++;
6781674ae819SStefano Zampini       }
67829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
6783674ae819SStefano Zampini     }
6784984c4197SStefano Zampini 
6785674ae819SStefano Zampini     /* edges and faces */
67869162d606SStefano Zampini     total_counts_cc = total_counts;
6787911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
67889162d606SStefano Zampini       IS        used_is;
67899162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
67909162d606SStefano Zampini 
6791911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
67929162d606SStefano Zampini         used_is       = ISForEdges[ncc];
6793984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
6794674ae819SStefano Zampini       } else {
67959162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6796984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6797674ae819SStefano Zampini       }
6798674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
67999162d606SStefano Zampini 
68009566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
680132fe681dSStefano Zampini       if (!size_of_constraint) continue;
68029566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6803674ae819SStefano Zampini       if (nnsp_has_cnst) {
68045b08dc53SStefano Zampini         PetscScalar quad_value;
68059162d606SStefano Zampini 
68069566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
68079162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
68089162d606SStefano Zampini 
6809a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6810674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6811a773dcb8SStefano Zampini         } else {
6812a773dcb8SStefano Zampini           quad_value = 1.0;
6813a773dcb8SStefano Zampini         }
6814ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value;
68159162d606SStefano Zampini         temp_constraints++;
6816674ae819SStefano Zampini         total_counts++;
6817674ae819SStefano Zampini       }
6818674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6819984c4197SStefano Zampini         PetscReal    real_value;
68209162d606SStefano Zampini         PetscScalar *ptr_to_data;
68219162d606SStefano Zampini 
68229566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
68239162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
6824ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) ptr_to_data[j] = array[is_indices[j]];
68259566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6826984c4197SStefano Zampini         /* check if array is null on the connected component */
68279566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6828792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
682957715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6830674ae819SStefano Zampini           temp_constraints++;
6831674ae819SStefano Zampini           total_counts++;
68329162d606SStefano Zampini           if (!idxs_copied) {
68339566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
68349162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6835674ae819SStefano Zampini           }
6836674ae819SStefano Zampini         }
68379162d606SStefano Zampini       }
68389566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
683945a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6840eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6841a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
68429162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
68439162d606SStefano Zampini 
68449162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
68459566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6846792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6847a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6848792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6849a773dcb8SStefano Zampini         } else { /* perform SVD */
68509162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6851674ae819SStefano Zampini 
685255080a34SStefano Zampini           if (use_pod) {
6853984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6854984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6855984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6856984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6857984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6858984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6859984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
68609566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6861674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
68629566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
68639566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6864674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
686548a46eb9SPierre 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));
6866674ae819SStefano Zampini             }
6867e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
68689566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
68699566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6870674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6871792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6872674ae819SStefano Zampini #else
6873792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6874674ae819SStefano Zampini #endif
68759566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6876835f2295SStefano Zampini             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %" PetscBLASInt_FMT, lierr);
6877984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6878674ae819SStefano Zampini             j = 0;
687987b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6880674ae819SStefano Zampini             total_counts      = total_counts - j;
688145a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6882e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
68839566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
68849566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
68859566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
68869566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
68879566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
68889566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6889674ae819SStefano Zampini             if (j < temp_constraints) {
6890984c4197SStefano Zampini               PetscInt ii;
6891984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
68929566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6893792fecdfSBarry 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));
68949566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6895984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
6896ad540459SPierre 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];
6897674ae819SStefano Zampini               }
6898674ae819SStefano Zampini             }
689955080a34SStefano Zampini           } else {
690055080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
69019566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
69029566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
69039566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
69049566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6905674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6906792fecdfSBarry 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));
6907674ae819SStefano Zampini   #else
6908792fecdfSBarry 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));
6909674ae819SStefano Zampini   #endif
6910835f2295SStefano Zampini             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %" PetscBLASInt_FMT, lierr);
69119566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6912984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6913e310c8b4SStefano Zampini             k = temp_constraints;
6914e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6915674ae819SStefano Zampini             j = 0;
691687b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
691745a1bb75SStefano Zampini             valid_constraints = k - j;
6918911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
691955080a34SStefano Zampini #else
692055080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6921984c4197SStefano Zampini #endif /* on missing GESVD */
6922674ae819SStefano Zampini           }
6923a773dcb8SStefano Zampini         }
692455080a34SStefano Zampini       }
69259162d606SStefano Zampini       /* update pointers information */
69269162d606SStefano Zampini       if (valid_constraints) {
69279162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
69289162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
69299162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
69309162d606SStefano Zampini         /* set change_of_basis flag */
69313ba16761SJacob Faibussowitsch         if (boolforchange) PetscCall(PetscBTSet(change_basis, total_counts_cc));
6932b3d85658SStefano Zampini         total_counts_cc++;
693345a1bb75SStefano Zampini       }
693445a1bb75SStefano Zampini     }
6935984c4197SStefano Zampini     /* free workspace */
69368f1c130eSStefano Zampini     if (!skip_lapack) {
69379566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6938984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
69399566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6940984c4197SStefano Zampini #endif
69419566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
69429566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
69439566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6944984c4197SStefano Zampini     }
694548a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
69469566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6947cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
694832fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
694908122e43SStefano Zampini   } else {
695008122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6951984c4197SStefano Zampini 
695208122e43SStefano Zampini     total_counts = 0;
695308122e43SStefano Zampini     n_vertices   = 0;
695448a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
695508122e43SStefano Zampini     max_constraints = 0;
69569162d606SStefano Zampini     total_counts_cc = 0;
695708122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
695808122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
69599162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
696008122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
696108122e43SStefano Zampini     }
69629162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
69639162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
69649162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
69659162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
696674d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
69679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
69689162d606SStefano Zampini     total_counts_cc = 0;
69699162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
6970ad540459SPierre Jolivet       if (pcbddc->adaptive_constraints_n[i]) constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
697108122e43SStefano Zampini     }
697208122e43SStefano Zampini 
69738bec7fa6SStefano Zampini     max_size_of_constraint = 0;
69749162d606SStefano 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]);
69759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
697608122e43SStefano Zampini     /* Change of basis */
69779566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
697808122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
697908122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
698048a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
698108122e43SStefano Zampini       }
698208122e43SStefano Zampini     }
698308122e43SStefano Zampini   }
6984984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
69859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
698608122e43SStefano Zampini 
69879162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
698832fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
69899566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
699063a3b9bcSJacob 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);
699132fe681dSStefano Zampini   }
6992674ae819SStefano Zampini 
6993674ae819SStefano Zampini   /* Create constraint matrix */
69949566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
69959566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
69969566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6997984c4197SStefano Zampini 
6998984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6999a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
70005a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
70019566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
7002984c4197SStefano Zampini   total_primal_vertices        = 0;
7003b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
70049162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
70059162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
700672b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
70079162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
7008b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
700964efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
7010ad540459SPierre Jolivet       for (k = 0; k < constraints_n[i]; k++) pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k];
7011b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
701291af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
70133ba16761SJacob Faibussowitsch         PetscCall(PetscBTSet(qr_needed_idx, i));
7014a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
7015a717540cSStefano Zampini       }
7016fa434743SStefano Zampini     } else {
7017b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
7018fa434743SStefano Zampini     }
7019a717540cSStefano Zampini   }
7020b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
7021b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
7022674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
70239566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
70249566063dSJacob 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));
70259566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
70260e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
7027984c4197SStefano Zampini 
7028984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
702974d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
70309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
7031984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
703274d5cdf7SStefano Zampini 
7033984c4197SStefano Zampini   j            = total_primal_vertices;
703474d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
7035b3d85658SStefano Zampini   cum          = total_primal_vertices;
70369162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
70374641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
7038b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
7039b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
7040b3d85658SStefano Zampini       cum++;
70419162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
704274d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
704374d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
704474d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
704574d5cdf7SStefano Zampini       }
70469162d606SStefano Zampini       j += constraints_n[i];
7047674ae819SStefano Zampini     }
7048674ae819SStefano Zampini   }
70499566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
70509566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
7051a75bf7bfSStefano Zampini   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
70529566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
7053088faed8SStefano Zampini 
7054674ae819SStefano Zampini   /* set values in constraint matrix */
705548a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
7056984c4197SStefano Zampini   total_counts = total_primal_vertices;
70579162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
70584641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
70599162d606SStefano Zampini       PetscInt *cols;
70609162d606SStefano Zampini 
70619162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
70629162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
70639162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
70649162d606SStefano Zampini         PetscInt     row = total_counts + k;
70659162d606SStefano Zampini         PetscScalar *vals;
70669162d606SStefano Zampini 
70679162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
70689566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
70699162d606SStefano Zampini       }
70709162d606SStefano Zampini       total_counts += constraints_n[i];
7071674ae819SStefano Zampini     }
7072674ae819SStefano Zampini   }
7073674ae819SStefano Zampini   /* assembling */
70749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
70759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
70769566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
7077088faed8SStefano Zampini 
7078674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
7079674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
7080026de310SStefano Zampini     /* dual and primal dofs on a single cc */
7081984c4197SStefano Zampini     PetscInt dual_dofs, primal_dofs;
7082984c4197SStefano Zampini     /* working stuff for GEQRF */
70835a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
7084984c4197SStefano Zampini     PetscBLASInt lqr_work;
7085984c4197SStefano Zampini     /* working stuff for UNGQR */
70863c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
7087984c4197SStefano Zampini     PetscBLASInt lgqr_work;
7088984c4197SStefano Zampini     /* working stuff for TRTRS */
70895a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
70903f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
7091984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
7092984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
7093984c4197SStefano Zampini     PetscScalar *start_vals;
7094984c4197SStefano Zampini     /* working stuff for values insertion */
70954641a718SStefano Zampini     PetscBT   is_primal;
709664efe560SStefano Zampini     PetscInt *aux_primal_numbering_B;
7097906d46d4SStefano Zampini     /* matrix sizes */
7098906d46d4SStefano Zampini     PetscInt global_size, local_size;
7099906d46d4SStefano Zampini     /* temporary change of basis */
7100906d46d4SStefano Zampini     Mat localChangeOfBasisMatrix;
7101cf5a6209SStefano Zampini     /* extra space for debugging */
71025a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
7103984c4197SStefano Zampini 
71049566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
71059566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
71069566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
7107906d46d4SStefano Zampini     /* nonzeros for local mat */
71089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
71091dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
7110bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
71111dd7afcfSStefano Zampini     } else {
71121dd7afcfSStefano Zampini       const PetscInt *ii;
71131dd7afcfSStefano Zampini       PetscInt        n;
71141dd7afcfSStefano Zampini       PetscBool       flg_row;
71159566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
71161dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
71179566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
71181dd7afcfSStefano Zampini     }
71199162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
7120a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
71219162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
7122a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
71239162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
7124a717540cSStefano Zampini         } else {
71259162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
71269162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
7127a717540cSStefano Zampini         }
7128a717540cSStefano Zampini       }
7129a717540cSStefano Zampini     }
71309566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
71319566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
71329566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
71331dd7afcfSStefano Zampini     /* Set interior change in the matrix */
71341dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
713548a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
71361dd7afcfSStefano Zampini     } else {
71371dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
71381dd7afcfSStefano Zampini       PetscScalar    *aa;
71391dd7afcfSStefano Zampini       PetscInt        n;
71401dd7afcfSStefano Zampini       PetscBool       flg_row;
71419566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
71429566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
714348a46eb9SPierre 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));
71449566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
71459566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
71461dd7afcfSStefano Zampini     }
7147a717540cSStefano Zampini 
7148a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
71499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
71509566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
7151a717540cSStefano Zampini     }
7152a717540cSStefano Zampini 
7153a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
7154a717540cSStefano Zampini     /*
7155a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
7156a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
7157a717540cSStefano Zampini 
71587c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
7159a717540cSStefano Zampini 
71607c625d9fSStefano 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)
7161a6b551f4SStefano Zampini 
7162a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
7163a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
7164a717540cSStefano Zampini             |              ...                        |
7165a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
7166a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
7167a717540cSStefano Zampini 
7168a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
7169a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
7170a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
7171a6b551f4SStefano Zampini 
7172a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
7173a717540cSStefano Zampini     */
71745a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
7175984c4197SStefano Zampini       /* space to store Q */
71769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
71774e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
71789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
7179984c4197SStefano Zampini       /* first we issue queries for optimal work */
71809566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
71819566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
71829566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
7183984c4197SStefano Zampini       lqr_work = -1;
7184792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
7185835f2295SStefano Zampini       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %" PetscBLASInt_FMT, lierr);
71869566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
718759b05608SBarry Smith       PetscCall(PetscMalloc1(lqr_work, &qr_work));
7188984c4197SStefano Zampini       lgqr_work = -1;
71899566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
71909566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
71919566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
71929566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
71933f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
7194792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
7195835f2295SStefano Zampini       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %" PetscBLASInt_FMT, lierr);
71969566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
719759b05608SBarry Smith       PetscCall(PetscMalloc1(lgqr_work, &gqr_work));
7198984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
71999566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
7200a717540cSStefano Zampini       /* allocating workspace for check */
720148a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
7202a717540cSStefano Zampini     }
7203984c4197SStefano Zampini     /* array to store whether a node is primal or not */
72049566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
72059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
72069566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
720763a3b9bcSJacob 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);
720848a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
72099566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
7210984c4197SStefano Zampini 
7211a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
72129162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
72139162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
72144641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
7215984c4197SStefano Zampini         /* get constraint info */
72169162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
7217984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
7218984c4197SStefano Zampini 
721948a46eb9SPierre 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));
7220984c4197SStefano Zampini 
7221fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
7222a717540cSStefano Zampini 
7223a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
722448a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7225984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
72269566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7227984c4197SStefano Zampini 
7228984c4197SStefano Zampini           /* compute QR decomposition of constraints */
72299566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
72309566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
72319566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
72329566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7233792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
7234835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %" PetscBLASInt_FMT, lierr);
72359566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7236984c4197SStefano Zampini 
7237a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
72389566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
7239984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
72409566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
72419566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
72429566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
72439566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
72449566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7245792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
7246835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %" PetscBLASInt_FMT, lierr);
72479566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7248984c4197SStefano Zampini 
7249a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
72509566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
72519566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
72529566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
72539566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
72549566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7255792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
7256835f2295SStefano Zampini           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %" PetscBLASInt_FMT, lierr);
72579566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7258984c4197SStefano Zampini 
7259984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
7260984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
7261984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
72629566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
72639566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
72649566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
72659566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
72669566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
72679566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
72689566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7269792fecdfSBarry 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));
72709566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
72719566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7272984c4197SStefano Zampini 
7273984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
72749162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
7275984c4197SStefano Zampini           /* insert cols for primal dofs */
7276984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
7277984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
72789162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
72799566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7280984c4197SStefano Zampini           }
7281984c4197SStefano Zampini           /* insert cols for dual dofs */
7282984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
72839162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
7284984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
72859162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
72869566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7287984c4197SStefano Zampini               j++;
7288674ae819SStefano Zampini             }
7289674ae819SStefano Zampini           }
7290984c4197SStefano Zampini 
7291984c4197SStefano Zampini           /* check change of basis */
7292984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
7293984c4197SStefano Zampini             PetscInt  ii, jj;
7294984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
72959566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
72969566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
72979566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
72989566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
72999566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
73009566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
73019566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7302792fecdfSBarry 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));
73039566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
7304984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
7305984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
7306cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
7307c068d9bbSLisandro 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;
7308674ae819SStefano Zampini               }
7309674ae819SStefano Zampini             }
7310984c4197SStefano Zampini             if (!valid_qr) {
73119566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
7312984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
7313984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
7314cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
731563a3b9bcSJacob 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])));
7316674ae819SStefano Zampini                   }
7317c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
731863a3b9bcSJacob 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])));
7319984c4197SStefano Zampini                   }
7320984c4197SStefano Zampini                 }
7321984c4197SStefano Zampini               }
7322674ae819SStefano Zampini             } else {
73239566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
7324674ae819SStefano Zampini             }
7325674ae819SStefano Zampini           }
7326a717540cSStefano Zampini         } else { /* simple transformation block */
7327a717540cSStefano Zampini           PetscInt    row, col;
7328a6b551f4SStefano Zampini           PetscScalar val, norm;
7329a6b551f4SStefano Zampini 
73309566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
7331792fecdfSBarry 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));
7332a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
73339162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
73349162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
7335bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
73369162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
73379566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
73389566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
7339a717540cSStefano Zampini             } else {
7340a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
73419162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
7342a717540cSStefano Zampini                 if (row != col) {
73439162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
7344a717540cSStefano Zampini                 } else {
73459162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
7346a717540cSStefano Zampini                 }
73479566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
7348a717540cSStefano Zampini               }
7349a717540cSStefano Zampini             }
7350a717540cSStefano Zampini           }
735148a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
7352a717540cSStefano Zampini         }
7353984c4197SStefano Zampini       } else {
735448a46eb9SPierre 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));
7355674ae819SStefano Zampini       }
7356674ae819SStefano Zampini     }
7357a717540cSStefano Zampini 
7358a717540cSStefano Zampini     /* free workspace */
7359a717540cSStefano Zampini     if (qr_needed) {
73601baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
73619566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
73629566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
73639566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
73649566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
73659566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
7366674ae819SStefano Zampini     }
73679566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
73689566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
73699566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
7370906d46d4SStefano Zampini 
7371906d46d4SStefano Zampini     /* assembling of global change of variable */
737288c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
7373bbb9e6c6SStefano Zampini       Mat tmat;
737416f15bc4SStefano Zampini 
73759566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
73769566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
73779566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
73789566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
73799566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
73809566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
7381ac7f1a8bSStefano Zampini       PetscCall(MatConvert(tmat, MATAIJ, MAT_INITIAL_MATRIX, &pcbddc->ChangeOfBasisMatrix));
73829566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
73839566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
73849566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
73859566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
73869566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
73879566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
73889566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
738988c03ad3SStefano Zampini 
7390906d46d4SStefano Zampini       /* check */
7391906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
7392906d46d4SStefano Zampini         PetscReal error;
7393906d46d4SStefano Zampini         Vec       x, x_change;
7394906d46d4SStefano Zampini 
73959566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
73969566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
73979566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
73989566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
73999566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
74009566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
74019566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
74029566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
74039566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
74049566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
74059566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
74069566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
7407049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
74089566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
74099566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
7410906d46d4SStefano Zampini       }
7411b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
7412b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
7413b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
7414bf3a8328SStefano Zampini 
741508401ef6SPierre 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");
7416b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
7417ac632422SStefano Zampini           Mat S_new, tmat;
7418bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
7419bbb9e6c6SStefano Zampini 
74209566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
74219566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
7422bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7423bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
7424bf3a8328SStefano Zampini             IS                     is_V;
74259566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
74269566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
74279566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
74289566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
74299566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
7430bf3a8328SStefano Zampini           }
74319566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
74329566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
74339566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
74349566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
7435bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7436bf3a8328SStefano Zampini             const PetscScalar *array;
7437bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
7438bf3a8328SStefano Zampini             PetscInt           i, n_V;
7439bf3a8328SStefano Zampini 
74409566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
74419566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
74429566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
74439566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
74449566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
7445b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
7446b087196eSStefano Zampini               PetscScalar val;
7447b087196eSStefano Zampini               PetscInt    idx;
7448b087196eSStefano Zampini 
7449b087196eSStefano Zampini               idx = idxs_V[i];
7450b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
74519566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
7452b087196eSStefano Zampini             }
74539566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
74549566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
74559566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
74569566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
74579566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
7458bf3a8328SStefano Zampini           }
7459ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
74609566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
7461ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
74629566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
74639566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
74649566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
74651baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
7466ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
74679566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
7468ac632422SStefano Zampini           }
74699566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
74709566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
7471b96c3477SStefano Zampini         }
7472c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
7473b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
7474c9db6a07SStefano Zampini           PetscInt i;
7475c9db6a07SStefano Zampini 
747648a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
74779566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
7478c9db6a07SStefano Zampini         }
7479b96c3477SStefano Zampini       }
748016909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
748116909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
748216909a7fSStefano Zampini       } else {
74839566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
748416909a7fSStefano Zampini       }
74851dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
748627b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
748772b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
74889566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
748972b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
749072b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
749172b8c272SStefano Zampini     }
74921dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
749327b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
74949566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
7495b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
7496906d46d4SStefano Zampini     } else {
74971dd7afcfSStefano Zampini       Mat benign_global = NULL;
749827b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
74991dd7afcfSStefano Zampini         Mat M;
75001dd7afcfSStefano Zampini 
75019e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
75029566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
75039566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
75049566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
75059e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
75069566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
75079566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
7508906d46d4SStefano Zampini         } else {
75099566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
75109566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
7511906d46d4SStefano Zampini         }
75129566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
75139566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
75149566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
75159566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
75161dd7afcfSStefano Zampini       }
75171dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
7518fb842aefSJose E. Roman         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &pcbddc->ChangeOfBasisMatrix));
75199566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
752027b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
75211dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
75221dd7afcfSStefano Zampini       }
75231dd7afcfSStefano Zampini     }
752416909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
752516909a7fSStefano Zampini       IS              is_global;
752616909a7fSStefano Zampini       const PetscInt *gidxs;
752716909a7fSStefano Zampini 
75289566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
75299566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
75309566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
75319566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
75329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
753316909a7fSStefano Zampini     }
75341dd7afcfSStefano Zampini   }
753548a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
7536a717540cSStefano Zampini 
753772b8c272SStefano Zampini   if (!pcbddc->fake_change) {
75384f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
75394f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
75404f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
75414f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
7542019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
7543019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
7544019a44ceSStefano Zampini       pcbddc->local_primal_size++;
7545019a44ceSStefano Zampini     }
7546019a44ceSStefano Zampini 
7547019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
7548727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
7549727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
75509566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7551c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
75520e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
75539566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7554727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
7555727cdba6SStefano Zampini       }
75560e6343abSStefano Zampini     }
7557727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
75585440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
755972b8c272SStefano Zampini   }
75609566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
7561727cdba6SStefano Zampini 
7562a717540cSStefano Zampini   /* flush dbg viewer */
75631baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7564a717540cSStefano Zampini 
7565e310c8b4SStefano Zampini   /* free workspace */
75669566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
75679566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
756808122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
75699566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
75709566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
757108122e43SStefano Zampini   } else {
7572d0609cedSBarry 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));
75739566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
75749566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
757508122e43SStefano Zampini   }
75763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7577674ae819SStefano Zampini }
7578674ae819SStefano Zampini 
7579d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
7580d71ae5a4SJacob Faibussowitsch {
758171582508SStefano Zampini   ISLocalToGlobalMapping map;
7582674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7583674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
758466da6bd7Sstefano_zampini   PetscInt               i, N;
758566da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
7586674ae819SStefano Zampini 
7587674ae819SStefano Zampini   PetscFunctionBegin;
75888af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
7589b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
75908e61c736SStefano Zampini     /* Reset previously computed graph */
75919566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
7592674ae819SStefano Zampini     /* Init local Graph struct */
75939566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
75949566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
75959566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
7596674ae819SStefano Zampini 
759748a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
7598575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
75999371c9d4SSatish 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,
76009371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
76019577ea80SStefano Zampini 
7602674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
760366da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
76044d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
76054d379d7bSStefano Zampini       PetscInt  nvtxs;
76069de2952eSStefano Zampini       PetscBool flg_row;
76079de2952eSStefano Zampini       Mat       A;
7608674ae819SStefano Zampini 
76099de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
76109de2952eSStefano Zampini       A = matis->A;
76119de2952eSStefano Zampini       for (PetscInt i = 0; i < pcbddc->local_adj_square; i++) {
76129de2952eSStefano Zampini         Mat AtA;
76139de2952eSStefano Zampini 
76149de2952eSStefano Zampini         PetscCall(MatProductCreate(A, A, NULL, &AtA));
76159de2952eSStefano Zampini         PetscCall(MatSetOptionsPrefix(AtA, "pc_bddc_graph_"));
76169de2952eSStefano Zampini         PetscCall(MatProductSetType(AtA, MATPRODUCT_AtB));
76179de2952eSStefano Zampini         PetscCall(MatProductSetFromOptions(AtA));
76189de2952eSStefano Zampini         PetscCall(MatProductSymbolic(AtA));
76199de2952eSStefano Zampini         PetscCall(MatProductClear(AtA));
76209de2952eSStefano Zampini         /* we only need the sparsity, cheat and tell PETSc the matrix has been assembled */
76219de2952eSStefano Zampini         AtA->assembled = PETSC_TRUE;
76229de2952eSStefano Zampini         PetscCall(MatDestroy(&A));
76239de2952eSStefano Zampini         A = AtA;
76249de2952eSStefano Zampini       }
76259de2952eSStefano Zampini       PetscCall(MatGetRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
76262fffb893SStefano Zampini       if (flg_row) {
76279566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
7628b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
76299de2952eSStefano Zampini         PetscCall(MatRestoreRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
763066da6bd7Sstefano_zampini         rcsr = PETSC_TRUE;
7631674ae819SStefano Zampini       }
76329de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
76339de2952eSStefano Zampini     }
76341baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7635674ae819SStefano Zampini 
7636ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
7637ab8c8b98SStefano Zampini       PetscReal   *lcoords;
7638ab8c8b98SStefano Zampini       PetscInt     n;
7639ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
7640835f2295SStefano Zampini       PetscMPIInt  cdimi;
7641ab8c8b98SStefano Zampini 
76424f819b78SStefano Zampini       /* TODO: support for blocked */
764363a3b9bcSJacob 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);
76449566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
76459566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
7646835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(pcbddc->mat_graph->cdim, &cdimi));
7647835f2295SStefano Zampini       PetscCallMPI(MPI_Type_contiguous(cdimi, MPIU_REAL, &dimrealtype));
76489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
76499566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
76509566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
76519566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
76529566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
7653ab8c8b98SStefano Zampini 
7654ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
7655ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
7656ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
7657ab8c8b98SStefano Zampini     }
76589371c9d4SSatish 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,
76599371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
7660625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
7661ab8c8b98SStefano Zampini 
76624f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
76634f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
766420c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
76654f1b2e48SStefano Zampini 
76669566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
76679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
766820c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
76694f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
76704f1b2e48SStefano Zampini         const PetscInt *idxs;
76714f1b2e48SStefano Zampini         PetscInt        nl, j;
76724f1b2e48SStefano Zampini 
76739566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
76749566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
767571582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
76769566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
76774f1b2e48SStefano Zampini       }
767820c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
767920c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
76804f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
76814f1b2e48SStefano Zampini     }
76829de2952eSStefano Zampini 
76839de2952eSStefano Zampini     /* Setup of Graph */
76849de2952eSStefano Zampini     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
76858af8fcf9SStefano Zampini   }
76864f1b2e48SStefano Zampini 
7687cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
7688674ae819SStefano Zampini     /* Graph's connected components analysis */
76899566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
769071582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
76914f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
76928af8fcf9SStefano Zampini   }
769366da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
76943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7695674ae819SStefano Zampini }
7696674ae819SStefano Zampini 
7697d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[])
7698d71ae5a4SJacob Faibussowitsch {
7699295df10fSStefano Zampini   PetscInt     i, j, n;
77009a7d3425SStefano Zampini   PetscScalar *alphas;
7701295df10fSStefano Zampini   PetscReal    norm, *onorms;
77029a7d3425SStefano Zampini 
77039a7d3425SStefano Zampini   PetscFunctionBegin;
7704295df10fSStefano Zampini   n = *nio;
77053ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
77069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
77079566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
770892cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
7709295df10fSStefano Zampini     onorms[0] = 0.0;
77109566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
7711295df10fSStefano Zampini   } else {
7712295df10fSStefano Zampini     onorms[0] = norm;
771392cccca0SStefano Zampini   }
7714295df10fSStefano Zampini 
77158c0031efSStefano Zampini   for (i = 1; i < n; i++) {
77169566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
77178c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
77189566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
77199566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
772092cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
7721295df10fSStefano Zampini       onorms[i] = 0.0;
77229566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
7723295df10fSStefano Zampini     } else {
7724295df10fSStefano Zampini       onorms[i] = norm;
772592cccca0SStefano Zampini     }
77269a7d3425SStefano Zampini   }
7727295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
7728295df10fSStefano Zampini   for (i = 0; i < n; i++) {
7729295df10fSStefano Zampini     if (onorms[i] == 0.0) {
7730295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
7731295df10fSStefano Zampini         if (onorms[j] != 0.0) {
77329566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
7733e1614d24SStefano Zampini           onorms[i] = onorms[j];
7734295df10fSStefano Zampini           onorms[j] = 0.0;
7735e1614d24SStefano Zampini           break;
7736295df10fSStefano Zampini         }
7737295df10fSStefano Zampini       }
7738295df10fSStefano Zampini     }
7739295df10fSStefano Zampini   }
7740295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
77419566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
77423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
77439a7d3425SStefano Zampini }
77449a7d3425SStefano Zampini 
7745ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void)
7746d71ae5a4SJacob Faibussowitsch {
7747e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
774857de7509SStefano Zampini   Mat                    A;
7749e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
7750e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
775152e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
775252e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
7753bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
775457de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
775527b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
775627b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
775727b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
775827b6a85dSStefano Zampini   MPI_Comm               subcomm;
7759a57a6d2fSStefano Zampini 
7760e7931f94SStefano Zampini   PetscFunctionBegin;
776157de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
77629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
776328b400f6SJacob 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);
776457de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
776557de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
776663a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
776757de7509SStefano Zampini 
776857de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
77699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
77709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
77719566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
77729566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
7773bb360cb4SStefano Zampini   im_active = !!n;
7774462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
777557de7509SStefano Zampini   void_procs = size - active_procs;
777615229ffcSPierre Jolivet   /* get ranks of non-active processes in mat communicator */
777757de7509SStefano Zampini   if (void_procs) {
777857de7509SStefano Zampini     PetscInt ncand;
777957de7509SStefano Zampini 
778057de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
77819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
77829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
778357de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
7784ad540459SPierre Jolivet       if (!procs_candidates[i]) procs_candidates[ncand++] = i;
778557de7509SStefano Zampini     }
778657de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
778757de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
778857de7509SStefano Zampini   }
778957de7509SStefano Zampini 
7790bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
77919dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
77929566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
7793bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
779414f0bfb9SStefano Zampini     PetscInt  issize, isidx, dest;
7795b96ec092SStefano Zampini     PetscBool default_sub;
7796b96ec092SStefano Zampini 
779714f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
779814f0bfb9SStefano Zampini     else dest = rank;
779957de7509SStefano Zampini     if (im_active) {
780057de7509SStefano Zampini       issize = 1;
780157de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
780214f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
780357de7509SStefano Zampini       } else {
780414f0bfb9SStefano Zampini         isidx = dest;
780557de7509SStefano Zampini       }
780657de7509SStefano Zampini     } else {
780757de7509SStefano Zampini       issize = 0;
7808b96ec092SStefano Zampini       isidx  = rank;
780957de7509SStefano Zampini     }
7810bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
78119566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
7812b96ec092SStefano Zampini     default_sub = (PetscBool)(isidx == rank);
78135440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &default_sub, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
7814b96ec092SStefano Zampini     if (default_sub) PetscCall(PetscObjectSetName((PetscObject)*is_sends, "default subassembling"));
78159566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
78163ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
781757de7509SStefano Zampini   }
78189de2952eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_use_vwgt", &use_vwgt, NULL));
78199de2952eSStefano Zampini   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_threshold", &threshold, NULL));
782027b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7821e7931f94SStefano Zampini 
7822e7931f94SStefano Zampini   /* Get info on mapping */
78239566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
78249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7825e7931f94SStefano Zampini 
7826e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
78279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7828e7931f94SStefano Zampini   xadj[0] = 0;
7829e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
78309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
78319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
78329566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
783327b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
78349371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7835e7931f94SStefano Zampini 
783627b6a85dSStefano Zampini   xadj_count = 0;
78372b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
783827b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
783927b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7840d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7841d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7842d023bfaeSStefano Zampini         xadj_count++;
784327b6a85dSStefano Zampini         break;
784427b6a85dSStefano Zampini       }
7845e7931f94SStefano Zampini     }
7846e7931f94SStefano Zampini   }
7847d023bfaeSStefano Zampini   xadj[1] = xadj_count;
78489566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
78499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
78509566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7851e7931f94SStefano Zampini 
78529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7853e7931f94SStefano Zampini 
785427b6a85dSStefano Zampini   /* Restrict work on active processes only */
78559566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
785627b6a85dSStefano Zampini   if (void_procs) {
78579566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
78589566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
78599566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
786027b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
786127b6a85dSStefano Zampini   } else {
786227b6a85dSStefano Zampini     psubcomm = NULL;
786327b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
786427b6a85dSStefano Zampini   }
786527b6a85dSStefano Zampini 
786627b6a85dSStefano Zampini   v_wgt = NULL;
786727b6a85dSStefano Zampini   if (!color) {
78689566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
78699566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
78709566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7871c8587f34SStefano Zampini   } else {
787252e5ac9dSStefano Zampini     Mat             subdomain_adj;
787352e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
787452e5ac9dSStefano Zampini     MatPartitioning partitioner;
78756497c311SBarry Smith     PetscInt        rstart, rend;
78766497c311SBarry Smith     PetscMPIInt     irstart = 0, irend = 0;
787752e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
787857de7509SStefano Zampini     PetscMPIInt     size;
7879b0c7d250SStefano Zampini     PetscBool       aggregate;
7880b0c7d250SStefano Zampini 
78819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
788227b6a85dSStefano Zampini     if (void_procs) {
788327b6a85dSStefano Zampini       PetscInt prank = rank;
78849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
78859566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
788648a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
78879566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
788827b6a85dSStefano Zampini     } else {
788927b6a85dSStefano Zampini       oldranks = NULL;
789027b6a85dSStefano Zampini     }
7891b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
789227b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7893b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7894b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7895b0c7d250SStefano Zampini       PetscScalar *vals;
7896b0c7d250SStefano Zampini 
78979566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7898b0c7d250SStefano Zampini       lrows = 0;
7899b0c7d250SStefano Zampini       if (nrank < redprocs) {
7900b0c7d250SStefano Zampini         lrows = size / redprocs;
7901b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7902b0c7d250SStefano Zampini       }
79039566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
79049566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
7905835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(rstart, &irstart));
7906835f2295SStefano Zampini       PetscCall(PetscMPIIntCast(rend, &irend));
79079566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
79089566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7909b0c7d250SStefano Zampini       row   = nrank;
7910b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7911b0c7d250SStefano Zampini       cols  = adjncy;
79129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7913b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
79149566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
79159566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
79169566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
79179566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
79189566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
79199566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
79209566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
792127b6a85dSStefano Zampini       if (use_vwgt) {
792227b6a85dSStefano Zampini         Vec                v;
792327b6a85dSStefano Zampini         const PetscScalar *array;
792427b6a85dSStefano Zampini         PetscInt           nl;
792527b6a85dSStefano Zampini 
79269566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
79279566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
79289566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
79299566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
79309566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
79319566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
79329566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
793322db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
79349566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
79359566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
793627b6a85dSStefano Zampini       }
7937b0c7d250SStefano Zampini     } else {
7938835f2295SStefano Zampini       PetscCall(MatCreateMPIAdj(subcomm, 1, size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
793927b6a85dSStefano Zampini       if (use_vwgt) {
79409566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7941bb360cb4SStefano Zampini         v_wgt[0] = n;
794227b6a85dSStefano Zampini       }
7943b0c7d250SStefano Zampini     }
79449566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7945e7931f94SStefano Zampini 
7946e7931f94SStefano Zampini     /* Partition */
79479566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7948ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
79499566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7950ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
79519566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7952ce64c636SStefano Zampini #else
79539566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7954ce64c636SStefano Zampini #endif
79559566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
79561baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
7957835f2295SStefano Zampini     *n_subdomains = PetscMin(size, *n_subdomains);
79589566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
79599566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
79609566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
79619566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7962e7931f94SStefano Zampini 
796352e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
79649566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
79659566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
79669566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
796757de7509SStefano Zampini     if (!aggregate) {
796857de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
79696bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
797057de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
797127b6a85dSStefano Zampini       } else if (oldranks) {
7972b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
797327b6a85dSStefano Zampini       } else {
797427b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
797557de7509SStefano Zampini       }
797628143c3dSStefano Zampini     } else {
79777fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7978b0c7d250SStefano Zampini       PetscMPIInt  tag;
7979b0c7d250SStefano Zampini       MPI_Request *reqs;
7980b0c7d250SStefano Zampini 
79819566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
79829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
79836497c311SBarry Smith       for (PetscMPIInt i = irstart; i < irend; i++) PetscCallMPI(MPIU_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
79846497c311SBarry Smith       PetscCallMPI(MPIU_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
79856497c311SBarry Smith       PetscCallMPI(MPI_Waitall(irend - irstart, reqs, MPI_STATUSES_IGNORE));
79869566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
798757de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
79886bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
79897fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
799027b6a85dSStefano Zampini       } else if (oldranks) {
79917fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
799227b6a85dSStefano Zampini       } else {
79937fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
799428143c3dSStefano Zampini       }
799557de7509SStefano Zampini     }
79969566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7997e7931f94SStefano Zampini     /* clean up */
79989566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
79999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
80009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
80019566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
8002e7931f94SStefano Zampini   }
80039566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
80049566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
8005e7931f94SStefano Zampini 
8006e7931f94SStefano Zampini   /* assemble parallel IS for sends */
8007e7931f94SStefano Zampini   i = 1;
800827b6a85dSStefano Zampini   if (!color) i = 0;
80099566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
80103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8011e7931f94SStefano Zampini }
8012e7931f94SStefano Zampini 
80139371c9d4SSatish Balay typedef enum {
80149371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
80159371c9d4SSatish Balay   MATAIJ_PRIVATE,
80169371c9d4SSatish Balay   MATBAIJ_PRIVATE,
80179371c9d4SSatish Balay   MATSBAIJ_PRIVATE
80189371c9d4SSatish Balay } MatTypePrivate;
8019e7931f94SStefano Zampini 
8020ba38deedSJacob 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[])
8021d71ae5a4SJacob Faibussowitsch {
802270cf5478SStefano Zampini   Mat                    local_mat;
8023e7931f94SStefano Zampini   IS                     is_sends_internal;
80249d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
80251ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
80269d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
8027e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
8028e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
8029e7931f94SStefano Zampini   const PetscInt        *is_indices;
8030e7931f94SStefano Zampini   MatType                new_local_type;
8031e7931f94SStefano Zampini   /* buffers */
8032e7931f94SStefano Zampini   PetscInt          *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
803328143c3dSStefano Zampini   PetscInt          *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
80349d30be91SStefano Zampini   PetscInt          *recv_buffer_idxs_local;
80351683a169SBarry Smith   PetscScalar       *ptr_vals, *recv_buffer_vals;
80361683a169SBarry Smith   const PetscScalar *send_buffer_vals;
80371ae86dd6SStefano Zampini   PetscScalar       *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
8038e7931f94SStefano Zampini   /* MPI */
803928143c3dSStefano Zampini   MPI_Comm     comm, comm_n;
804028143c3dSStefano Zampini   PetscSubcomm subcomm;
8041e569e4e1SStefano Zampini   PetscMPIInt  n_sends, n_recvs, size;
804228143c3dSStefano Zampini   PetscMPIInt *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
804328143c3dSStefano Zampini   PetscMPIInt *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
804460b1fa21SPierre Jolivet   PetscMPIInt  len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
80451ae86dd6SStefano Zampini   MPI_Request *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
80461ae86dd6SStefano Zampini   MPI_Request *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
8047e7931f94SStefano Zampini 
8048e7931f94SStefano Zampini   PetscFunctionBegin;
804957de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
80509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
80515f80ce2aSJacob 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);
805257de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
805357de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
805457de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
805557de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
805657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
80571ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
80581ae86dd6SStefano Zampini   if (nvecs) {
805908401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
80601ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
80611ae86dd6SStefano Zampini   }
806257de7509SStefano Zampini   /* further checks */
80639566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
80649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
80655f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
80669de2952eSStefano Zampini 
80679566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
80685f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
806957de7509SStefano Zampini   if (reuse && *mat_n) {
807070cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
807157de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
80729566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
80735f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
80749566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
80759566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
807663a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
807763a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
807870cf5478SStefano Zampini   }
80799566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
8080064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
808157de7509SStefano Zampini 
8082e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
8083e7931f94SStefano Zampini   if (!is_sends) {
80845f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
80859566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
8086c8587f34SStefano Zampini   } else {
80879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
8088e7931f94SStefano Zampini     is_sends_internal = is_sends;
8089c8587f34SStefano Zampini   }
8090e7931f94SStefano Zampini 
8091e7931f94SStefano Zampini   /* get comm */
80929566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
8093e7931f94SStefano Zampini 
8094e7931f94SStefano Zampini   /* compute number of sends */
80959566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
80969566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
8097e7931f94SStefano Zampini 
8098e7931f94SStefano Zampini   /* compute number of receives */
80999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
81009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
81019566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
81029566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
8103e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
81049566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
81059566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
8106e7931f94SStefano Zampini 
810728143c3dSStefano Zampini   /* restrict comm if requested */
81080a545947SLisandro Dalcin   subcomm     = NULL;
810928143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
811028143c3dSStefano Zampini   if (restrict_comm) {
8111779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
8112779c1cceSStefano Zampini 
811328143c3dSStefano Zampini     color = 0;
811453a05cb3SStefano Zampini     if (restrict_full) {
81156aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
811653a05cb3SStefano Zampini     } else {
81176aad120cSJose 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 */
811853a05cb3SStefano Zampini     }
8119462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
8120e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
812128143c3dSStefano Zampini     /* check if reuse has been requested */
812257de7509SStefano Zampini     if (reuse) {
812328143c3dSStefano Zampini       if (*mat_n) {
812428143c3dSStefano Zampini         PetscMPIInt subcommsize2;
81259566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
81265f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
812728143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
812828143c3dSStefano Zampini       } else {
812928143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
813028143c3dSStefano Zampini       }
813128143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
8132779c1cceSStefano Zampini       PetscMPIInt rank;
8133779c1cceSStefano Zampini 
81349566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
81359566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
81369566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
81379566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
8138306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
813928143c3dSStefano Zampini     }
814028143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
814128143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
814228143c3dSStefano Zampini   } else {
814328143c3dSStefano Zampini     comm_n = comm;
814428143c3dSStefano Zampini   }
814528143c3dSStefano Zampini 
8146e7931f94SStefano Zampini   /* prepare send/receive buffers */
81479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
81489566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
81499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
81509566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
815148a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
8152e7931f94SStefano Zampini 
815328143c3dSStefano Zampini   /* Get data from local matrices */
8154e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
8155e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
8156e7931f94SStefano Zampini   /*
8157e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
8158e7931f94SStefano Zampini        send_buffer_idxs should contain:
8159e7931f94SStefano Zampini        - MatType_PRIVATE type
8160e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
8161e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
8162e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
8163e7931f94SStefano Zampini     */
8164e432b41dSStefano Zampini   {
8165e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
8166e432b41dSStefano Zampini 
81679566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
81689566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
81699566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
81709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
8171e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
8172e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
81739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
81749566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
81759566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
81769566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
8177e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
8178e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
8179e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
8180c8587f34SStefano Zampini     }
8181c8587f34SStefano Zampini   }
81829566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
818328143c3dSStefano Zampini   /* additional is (if any) */
818428143c3dSStefano Zampini   if (nis) {
818528143c3dSStefano Zampini     PetscMPIInt psum;
818628143c3dSStefano Zampini     PetscInt    j;
818728143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
818828143c3dSStefano Zampini       PetscInt plen;
81899566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
81909566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
81916aad120cSJose E. Roman       psum += len + 1; /* indices + length */
819228143c3dSStefano Zampini     }
81939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
819428143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
819528143c3dSStefano Zampini       PetscInt        plen;
819628143c3dSStefano Zampini       const PetscInt *is_array_idxs;
81979566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
819828143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
81999566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
82009566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
82019566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
82026aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
820328143c3dSStefano Zampini     }
8204ad540459SPierre Jolivet     for (i = 0; i < n_sends; i++) ilengths_idxs_is[is_indices[i]] = psum;
82059566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
820628143c3dSStefano Zampini   }
82079566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
820828143c3dSStefano Zampini 
8209e7931f94SStefano Zampini   buf_size_idxs    = 0;
8210e7931f94SStefano Zampini   buf_size_vals    = 0;
821128143c3dSStefano Zampini   buf_size_idxs_is = 0;
82121ae86dd6SStefano Zampini   buf_size_vecs    = 0;
8213e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8214835f2295SStefano Zampini     buf_size_idxs += olengths_idxs[i];
8215835f2295SStefano Zampini     buf_size_vals += olengths_vals[i];
8216835f2295SStefano Zampini     if (nis) buf_size_idxs_is += olengths_idxs_is[i];
8217835f2295SStefano Zampini     if (nvecs) buf_size_vecs += olengths_idxs[i];
8218e7931f94SStefano Zampini   }
82199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
82209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
82219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
82229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
8223e7931f94SStefano Zampini 
8224e7931f94SStefano Zampini   /* get new tags for clean communications */
82259566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
82269566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
82279566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
82289566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
8229e7931f94SStefano Zampini 
8230e7931f94SStefano Zampini   /* allocate for requests */
82319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
82329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
82339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
82349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
82359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
82369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
82379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
82389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
8239e7931f94SStefano Zampini 
8240e7931f94SStefano Zampini   /* communications */
8241e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
8242e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
824328143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
82441ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
8245e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8246e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, onodes[i], tag_idxs, comm, &recv_req_idxs[i]));
8247e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, onodes[i], tag_vals, comm, &recv_req_vals[i]));
8248e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8249e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
825028143c3dSStefano Zampini     if (nis) {
8251e91c04dfSPierre 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]));
825228143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
825328143c3dSStefano Zampini     }
82541ae86dd6SStefano Zampini     if (nvecs) {
8255e91c04dfSPierre Jolivet       PetscCallMPI(MPIU_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, onodes[i], tag_vecs, comm, &recv_req_vecs[i]));
82561ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
82571ae86dd6SStefano Zampini     }
8258e7931f94SStefano Zampini   }
8259e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
826060b1fa21SPierre Jolivet     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
826160b1fa21SPierre Jolivet     PetscCallMPI(MPIU_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
826260b1fa21SPierre Jolivet     PetscCallMPI(MPIU_Isend(send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
826360b1fa21SPierre 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]));
82641ae86dd6SStefano Zampini     if (nvecs) {
82659566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
826660b1fa21SPierre Jolivet       PetscCallMPI(MPIU_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
82671ae86dd6SStefano Zampini     }
8268e7931f94SStefano Zampini   }
82699566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
82709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
8271e7931f94SStefano Zampini 
8272e7931f94SStefano Zampini   /* assemble new l2g map */
82739566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
8274e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
82759d30be91SStefano Zampini   new_local_rows = 0;
8276e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
82779d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8278e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8279e7931f94SStefano Zampini   }
82809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
8281e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
82829d30be91SStefano Zampini   new_local_rows = 0;
8283e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
82849566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
82859d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8286e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8287e7931f94SStefano Zampini   }
82889566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
82899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
82909566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
8291e7931f94SStefano Zampini 
8292e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
8293e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
8294e7931f94SStefano 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) */
8295e7931f94SStefano Zampini   if (n_recvs) {
829628143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
8297e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
8298e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
8299e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
8300e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
8301e7931f94SStefano Zampini         break;
8302e7931f94SStefano Zampini       }
8303e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
8304e7931f94SStefano Zampini     }
8305e7931f94SStefano Zampini     switch (new_local_type_private) {
830628143c3dSStefano Zampini     case MATDENSE_PRIVATE:
8307e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8308e7931f94SStefano Zampini       bs             = 1;
8309e7931f94SStefano Zampini       break;
8310e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
8311e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8312e7931f94SStefano Zampini       bs             = 1;
8313e7931f94SStefano Zampini       break;
8314d71ae5a4SJacob Faibussowitsch     case MATBAIJ_PRIVATE:
8315d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQBAIJ;
8316d71ae5a4SJacob Faibussowitsch       break;
8317d71ae5a4SJacob Faibussowitsch     case MATSBAIJ_PRIVATE:
8318d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQSBAIJ;
8319d71ae5a4SJacob Faibussowitsch       break;
8320d71ae5a4SJacob Faibussowitsch     default:
8321d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
8322e7931f94SStefano Zampini     }
8323ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
8324ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
832528143c3dSStefano Zampini     bs             = 1;
8326e7931f94SStefano Zampini   }
8327e7931f94SStefano Zampini 
832870cf5478SStefano Zampini   /* create MATIS object if needed */
832957de7509SStefano Zampini   if (!reuse) {
83309566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
83319566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
833270cf5478SStefano Zampini   } else {
833370cf5478SStefano Zampini     /* it also destroys the local matrices */
833457de7509SStefano Zampini     if (*mat_n) {
83359566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
833657de7509SStefano Zampini     } else { /* this is a fake object */
83379566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
833857de7509SStefano Zampini     }
833970cf5478SStefano Zampini   }
83409566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
83419566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
83429d30be91SStefano Zampini 
83439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
83449d30be91SStefano Zampini 
83459d30be91SStefano Zampini   /* Global to local map of received indices */
83469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
83479566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
83489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
83499d30be91SStefano Zampini 
83509d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
83519d30be91SStefano Zampini   buf_size_idxs = 0;
83529d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
83539d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
83549d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
8355835f2295SStefano Zampini     buf_size_idxs += olengths_idxs[i];
83569d30be91SStefano Zampini   }
83579566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
83589d30be91SStefano Zampini 
83599d30be91SStefano Zampini   /* set preallocation */
83609566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
83619d30be91SStefano Zampini   if (!newisdense) {
83620a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
83639d30be91SStefano Zampini 
83649d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
836548a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
83669d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
83679d30be91SStefano Zampini       PetscInt j;
83689d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
8369ad540459SPierre Jolivet         for (j = 0; j < *(ptr_idxs + 1); j++) new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1);
83709d30be91SStefano Zampini       } else {
83719d30be91SStefano Zampini         /* TODO */
83729d30be91SStefano Zampini       }
83739d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
83749d30be91SStefano Zampini     }
83759d30be91SStefano Zampini     if (new_local_nnz) {
83769d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
83779566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
83789d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
83799566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
83809d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
83819566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
83829d30be91SStefano Zampini     } else {
83839566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
83849d30be91SStefano Zampini     }
83859566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
83869d30be91SStefano Zampini   } else {
83879566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
83889d30be91SStefano Zampini   }
8389e7931f94SStefano Zampini 
8390e7931f94SStefano Zampini   /* set values */
8391e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
83929d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
8393e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8394e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
83959566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
83969566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
83979566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
83989566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
83999566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
840028143c3dSStefano Zampini     } else {
840128143c3dSStefano Zampini       /* TODO */
8402e7931f94SStefano Zampini     }
8403e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8404e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
8405e7931f94SStefano Zampini   }
84069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
84079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
84089566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
84099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
84109566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
84119566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
8412e7931f94SStefano Zampini 
8413dfd14d43SStefano Zampini #if 0
841428143c3dSStefano Zampini   if (!restrict_comm) { /* check */
8415e7931f94SStefano Zampini     Vec       lvec,rvec;
8416e7931f94SStefano Zampini     PetscReal infty_error;
8417e7931f94SStefano Zampini 
84189566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
84199566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
84209566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
84219566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
84229566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
84239566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
84249566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
84259566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
84269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
8427e7931f94SStefano Zampini   }
842828143c3dSStefano Zampini #endif
8429e7931f94SStefano Zampini 
843028143c3dSStefano Zampini   /* assemble new additional is (if any) */
843128143c3dSStefano Zampini   if (nis) {
843228143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
843328143c3dSStefano Zampini 
84349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
84359566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
843628143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
843728143c3dSStefano Zampini     psum     = 0;
843828143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
843928143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
844028143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
844128143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
844228143c3dSStefano Zampini         psum += plen;
844328143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
844428143c3dSStefano Zampini       }
844528143c3dSStefano Zampini     }
84469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
84479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
84488e3a54c0SPierre Jolivet     for (i = 1; i < nis; i++) temp_idxs[i] = PetscSafePointerPlusOffset(temp_idxs[i - 1], count_is[i - 1]);
84499566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
845028143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
845128143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
845228143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
845328143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
84549566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
845528143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
845628143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
845728143c3dSStefano Zampini       }
845828143c3dSStefano Zampini     }
845928143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
84609566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
84619566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
84629566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
846328143c3dSStefano Zampini     }
84649566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
84659566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
84669566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
846728143c3dSStefano Zampini   }
8468e7931f94SStefano Zampini   /* free workspace */
84699566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
84709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
84719566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
84729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
8473e7931f94SStefano Zampini   if (isdense) {
84749566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
84759566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
84769566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
8477e7931f94SStefano Zampini   } else {
84789566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
8479e7931f94SStefano Zampini   }
848028143c3dSStefano Zampini   if (nis) {
84819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
84829566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
848328143c3dSStefano Zampini   }
84841ae86dd6SStefano Zampini 
84851ae86dd6SStefano Zampini   if (nvecs) {
84869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
84879566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
84889566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
84899566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
84909566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
84919566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
84929566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
84931ae86dd6SStefano Zampini     /* set values */
84941ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
84951ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
84969566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
84971ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
84981ae86dd6SStefano Zampini       PetscInt j;
8499ad540459SPierre Jolivet       for (j = 0; j < *(ptr_idxs + 1); j++) send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j);
85001ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
85011ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
85021ae86dd6SStefano Zampini     }
85039566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
85049566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
85059566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
85061ae86dd6SStefano Zampini   }
85071ae86dd6SStefano Zampini 
85089566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
85099566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
85109566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
85119566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
85129566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
85139566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
85149566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
85159566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
85169566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
85179566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
85189566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
85199566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
85209566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
85219566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
85229566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
852328143c3dSStefano Zampini   if (nis) {
85249566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
85259566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
85269566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
852728143c3dSStefano Zampini   }
85289566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
85296aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
85309566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
853148a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
85321ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
85339566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
85341ae86dd6SStefano Zampini     }
853553a05cb3SStefano Zampini     *mat_n = NULL;
853628143c3dSStefano Zampini   }
85373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8538e7931f94SStefano Zampini }
8539a57a6d2fSStefano Zampini 
854012edc857SStefano Zampini /* temporary hack into ksp private data structure */
8541af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
854212edc857SStefano Zampini 
85439de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, Mat coarse_submat)
8544d71ae5a4SJacob Faibussowitsch {
8545c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
8546c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
85479de2952eSStefano Zampini   PCBDDCGraph            graph  = pcbddc->mat_graph;
85489de2952eSStefano Zampini   Mat                    coarse_mat, coarse_mat_is;
85491ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
85501e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
85519881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
855220a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
85534f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
85546e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
855530368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
85569de2952eSStefano Zampini   PetscInt               coarse_eqs_per_proc, coarsening_ratio;
8557f9eb5b7dSStefano Zampini   PC                     pc_temp;
8558c8587f34SStefano Zampini   PCType                 coarse_pc_type;
8559c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
8560f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
85619de2952eSStefano Zampini   PetscBool              coarse_reuse, multi_element = graph->multi_element;
85621e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
856368457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
856422bc73bbSStefano Zampini   PetscScalar           *array;
856557de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
856657de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
8567e569e4e1SStefano Zampini   PetscMPIInt            size;
8568fdc09c96SStefano Zampini 
8569c8587f34SStefano Zampini   PetscFunctionBegin;
85709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8571c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
857268457ee5SStefano 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 */
8573fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
85745a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
85757de4f681Sstefano_zampini 
85767de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
8577fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
85789566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
85799566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
8580f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
8581fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
858251bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
858351bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
85849566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
8585fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
8586fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
8587fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
8588f4ddd8eeSStefano Zampini       }
8589fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
8590fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
8591f4ddd8eeSStefano Zampini     }
859270cf5478SStefano Zampini     /* reset any subassembling information */
859348a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
85946e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
8595fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
8596f4ddd8eeSStefano Zampini   }
859757de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
85989566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
85999566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
860057de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
860118a45a71SStefano Zampini   } else {
860257de7509SStefano Zampini     coarse_mat       = NULL;
860357de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
86046e683305SStefano Zampini   }
8605e7931f94SStefano Zampini 
8606abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
86079566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
86089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
8609abbbba34SStefano Zampini 
8610abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
86119de2952eSStefano Zampini   PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &t_coarse_mat_is));
86129de2952eSStefano Zampini   PetscCall(MatSetType(t_coarse_mat_is, MATIS));
86139de2952eSStefano Zampini   PetscCall(MatSetSizes(t_coarse_mat_is, PETSC_DECIDE, PETSC_DECIDE, pcbddc->coarse_size, pcbddc->coarse_size));
8614b96ec092SStefano Zampini   PetscCall(MatISSetAllowRepeated(t_coarse_mat_is, multi_element));
86159de2952eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(t_coarse_mat_is, coarse_islg, coarse_islg));
86169de2952eSStefano Zampini   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat));
86179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
86189566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
86199de2952eSStefano Zampini   PetscCall(MatViewFromOptions(t_coarse_mat_is, (PetscObject)pc, "-pc_bddc_coarse_mat_is_view"));
8620abbbba34SStefano Zampini 
862157de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
8622f4f49eeaSPierre Jolivet   im_active = !!pcis->n;
8623462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
862457de7509SStefano Zampini 
862514f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
862628d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
862757de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
86289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
862957de7509SStefano Zampini   coarse_mat_is        = NULL;
863057de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
863157de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
8632e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
86339de2952eSStefano Zampini   if (coarse_eqs_per_proc < 0 || size == 1) coarse_eqs_per_proc = PetscMax(pcbddc->coarse_size, 1);
863457de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
8635e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
86369de2952eSStefano Zampini   coarsening_ratio = multi_element ? 1 : pcbddc->coarsening_ratio;
863757de7509SStefano Zampini   if (multilevel_requested) {
86389de2952eSStefano Zampini     ncoarse    = active_procs / coarsening_ratio;
863957de7509SStefano Zampini     restr      = PETSC_FALSE;
864057de7509SStefano Zampini     full_restr = PETSC_FALSE;
864157de7509SStefano Zampini   } else {
8642e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
864357de7509SStefano Zampini     restr      = PETSC_TRUE;
864457de7509SStefano Zampini     full_restr = PETSC_TRUE;
864557de7509SStefano Zampini   }
8646b96ec092SStefano Zampini   if (!pcbddc->coarse_size || (size == 1 && !multi_element)) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
864757de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
864857de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
86499de2952eSStefano Zampini     if (coarsening_ratio > 1) {
8650bb360cb4SStefano Zampini       if (multilevel_requested) {
86519566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8652bb360cb4SStefano Zampini       } else {
86539566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8654bb360cb4SStefano Zampini       }
8655a198735bSStefano Zampini     } else {
86567de4f681Sstefano_zampini       PetscMPIInt rank;
865728d58a37SPierre Jolivet 
86589566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
8659835f2295SStefano Zampini       have_void = (active_procs == size) ? PETSC_FALSE : PETSC_TRUE;
86609566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
8661b96ec092SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_subassembling, "default subassembling"));
8662a198735bSStefano Zampini     }
866357de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
866457de7509SStefano Zampini     PetscInt psum;
866557de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
866657de7509SStefano Zampini     else psum = 0;
8667462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
8668075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
866957de7509SStefano Zampini   }
867057de7509SStefano Zampini   /* determine if we can go multilevel */
867157de7509SStefano Zampini   if (multilevel_requested) {
867257de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
867357de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
867457de7509SStefano Zampini   }
867557de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
867657de7509SStefano Zampini 
8677e4d548c7SStefano Zampini   /* dump subassembling pattern */
867848a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
86796e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
86801e0482f5SStefano Zampini   nedcfield = -1;
86814f819b78SStefano Zampini   corners   = NULL;
86828966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
86836e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
86846e683305SStefano Zampini     const PetscInt        *idxs;
86856e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
86866e683305SStefano Zampini 
86876e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
86889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
86896e683305SStefano Zampini     /* allocate space for temporary storage */
86909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
86919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
86926e683305SStefano Zampini     /* allocate for IS array */
86936e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
86941e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
86951e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
86961e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
86971e0482f5SStefano Zampini       } else {
86981e0482f5SStefano Zampini         nedcfield = 0;
869963a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
87001e0482f5SStefano Zampini         nisdofs = 1;
87011e0482f5SStefano Zampini       }
87021e0482f5SStefano Zampini     }
87036e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
870427b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
870530368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
87069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
87076e683305SStefano Zampini     /* dofs splitting */
87086e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
87099566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
87101e0482f5SStefano Zampini       if (nedcfield != i) {
87119566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
87129566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
87139566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
87149566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
87151e0482f5SStefano Zampini       } else {
87169566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
87179566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
87189566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
871963a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
87209566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
87211e0482f5SStefano Zampini       }
87229566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
87239566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
87249566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
87256e683305SStefano Zampini     }
87266e683305SStefano Zampini     /* neumann boundaries */
87276e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
87289566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
87299566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
87309566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
87319566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
87329566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
87339566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
87349566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
87359566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
87366e683305SStefano Zampini     }
87374f819b78SStefano Zampini     /* coordinates */
87384f819b78SStefano Zampini     if (pcbddc->corner_selected) {
87399566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
87409566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
87419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
87429566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
874363a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
87449566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
87459566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
87469566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
87479566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
87484f819b78SStefano Zampini     }
87499566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
87509566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
87519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
87526e683305SStefano Zampini   } else {
87536e683305SStefano Zampini     nis     = 0;
87546e683305SStefano Zampini     nisdofs = 0;
87556e683305SStefano Zampini     nisneu  = 0;
875630368db7SStefano Zampini     nisvert = 0;
87576e683305SStefano Zampini     isarray = NULL;
87586e683305SStefano Zampini   }
87596e683305SStefano Zampini   /* destroy no longer needed map */
87609566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
87616e683305SStefano Zampini 
876257de7509SStefano Zampini   /* subassemble */
876357de7509SStefano Zampini   if (multilevel_allowed) {
87641ae86dd6SStefano Zampini     Vec       vp[1];
87651ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
87669de2952eSStefano Zampini     PetscBool reuse;
87671ae86dd6SStefano Zampini 
87681ae86dd6SStefano Zampini     vp[0] = NULL;
87699de2952eSStefano Zampini     /* XXX HDIV also */
87701ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
87719566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
87729566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
87739566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
87741ae86dd6SStefano Zampini       nvecs = 1;
87751ae86dd6SStefano Zampini 
87761ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
8777a198735bSStefano Zampini         Mat      B, loc_divudotp;
87781ae86dd6SStefano Zampini         Vec      v, p;
87791ae86dd6SStefano Zampini         IS       dummy;
87801ae86dd6SStefano Zampini         PetscInt np;
87811ae86dd6SStefano Zampini 
87829566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
87839566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
87849566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
87859566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
87869566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
87879566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
87889566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
87899566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
87909566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
87919566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
87929566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
87939566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
87949566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
87959566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
87969566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
87979566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
879874e2c79eSStefano Zampini       }
87991ae86dd6SStefano Zampini     }
88009de2952eSStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
88019de2952eSStefano Zampini     else reuse = PETSC_FALSE;
88029de2952eSStefano Zampini     if (multi_element) {
88039de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
88049de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
88059de2952eSStefano Zampini     } else {
88065440e5dcSBarry Smith       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &reuse, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
88079de2952eSStefano Zampini       if (reuse) {
88089566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
880974e2c79eSStefano Zampini       } else {
88109566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
88111ae86dd6SStefano Zampini       }
88121ae86dd6SStefano Zampini       if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
88131683a169SBarry Smith         PetscScalar       *arraym;
88141683a169SBarry Smith         const PetscScalar *arrayv;
88151ae86dd6SStefano Zampini         PetscInt           nl;
88169566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(vp[0], &nl));
88179566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
88189566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
88199566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vp[0], &arrayv));
88209566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(arraym, arrayv, nl));
88219566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
88229566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
88239566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&vp[0]));
8824a198735bSStefano Zampini       } else {
88259566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
88261ae86dd6SStefano Zampini       }
88279de2952eSStefano Zampini     }
88281ae86dd6SStefano Zampini   } else {
8829b96ec092SStefano Zampini     PetscBool default_sub;
8830b96ec092SStefano Zampini 
8831b96ec092SStefano Zampini     PetscCall(PetscStrcmp(((PetscObject)pcbddc->coarse_subassembling)->name, "default subassembling", &default_sub));
8832b96ec092SStefano Zampini     if (!default_sub) PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
88339de2952eSStefano Zampini     else {
88349de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
88359de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
88369de2952eSStefano Zampini     }
88376e683305SStefano Zampini   }
883857de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
883957de7509SStefano Zampini     if (!multilevel_allowed) {
88409566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
88416e683305SStefano Zampini     } else {
884257de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
884357de7509SStefano Zampini       if (coarse_mat_is) {
884428b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
88459566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
884657de7509SStefano Zampini         coarse_mat = coarse_mat_is;
884757de7509SStefano Zampini       }
8848779c1cceSStefano Zampini     }
8849779c1cceSStefano Zampini   }
88509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
88519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
88526e683305SStefano Zampini 
88536e683305SStefano Zampini   /* create local to global scatters for coarse problem */
885468457ee5SStefano Zampini   if (compute_vecs) {
88556e683305SStefano Zampini     PetscInt lrows;
88569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
885757de7509SStefano Zampini     if (coarse_mat) {
88589566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
88596e683305SStefano Zampini     } else {
88606e683305SStefano Zampini       lrows = 0;
88616e683305SStefano Zampini     }
88629566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
88639566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
88649566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
88659566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
88669566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
88676e683305SStefano Zampini   }
88689566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8869c8587f34SStefano Zampini 
8870f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8871f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8872f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8873f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8874f9eb5b7dSStefano Zampini   } else {
8875f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8876f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8877c8587f34SStefano Zampini   }
8878c8587f34SStefano Zampini 
88796e683305SStefano Zampini   /* print some info if requested */
88806e683305SStefano Zampini   if (pcbddc->dbg_flag) {
88816e683305SStefano Zampini     if (!multilevel_allowed) {
88829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
88836e683305SStefano Zampini       if (multilevel_requested) {
88849de2952eSStefano 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));
88856e683305SStefano Zampini       } else if (pcbddc->max_levels) {
888663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
88876e683305SStefano Zampini       }
88889566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
88896e683305SStefano Zampini     }
88906e683305SStefano Zampini   }
88916e683305SStefano Zampini 
88921e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
88931e0482f5SStefano Zampini   coarseG = NULL;
88941e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
88951e0482f5SStefano Zampini     MPI_Comm ccomm;
88961e0482f5SStefano Zampini     if (coarse_mat) {
88971e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
88981e0482f5SStefano Zampini     } else {
88991e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
89001e0482f5SStefano Zampini     }
89019566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
89021e0482f5SStefano Zampini   }
89031e0482f5SStefano Zampini 
8904f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
890557de7509SStefano Zampini   if (coarse_mat) {
890628d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
89076a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8908b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
89097274672aSStefano Zampini 
89106e683305SStefano Zampini     if (pcbddc->dbg_flag) {
891157de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
89129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
89136e683305SStefano Zampini     }
8914f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8915312be037SStefano Zampini       char   prefix[256], str_level[16];
8916e604994aSStefano Zampini       size_t len;
89171e0482f5SStefano Zampini 
89189566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
89193821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->coarse_ksp, pc->kspnestlevel));
89209566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
89219566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
8922fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, 1));
89239566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
89249566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
89259566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
89269566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
89271e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
89289566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8929e604994aSStefano Zampini       /* prefix */
8930c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(prefix, "", sizeof(prefix)));
8931c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(str_level, "", sizeof(str_level)));
8932e604994aSStefano Zampini       if (!pcbddc->current_level) {
89339566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
89349566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8935c8587f34SStefano Zampini       } else {
89369566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8937312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8938312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8939a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
89409566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
8941835f2295SStefano Zampini         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%" PetscInt_FMT "_", pcbddc->current_level));
89429566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8943e604994aSStefano Zampini       }
89449566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
89453e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
89469566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
89479566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
89489566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8949f9eb5b7dSStefano Zampini       /* allow user customization */
89509566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8951e569e4e1SStefano Zampini       /* get some info after set from options */
89529566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
895328d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
895428d58a37SPierre Jolivet       force = PETSC_FALSE;
89559566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
89569566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
89579566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
895828d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8959e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
89609566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
89619566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
89629566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
89639566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
89644f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8965d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8966dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8967dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8968d0609cedSBarry Smith           PetscOptionsEnd();
89694f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
89704f819b78SStefano Zampini         }
8971e569e4e1SStefano Zampini       }
89723e3c6dadSStefano Zampini     }
89733e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
89749566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
89753e3c6dadSStefano Zampini     if (nisdofs) {
89769566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
897748a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
89783e3c6dadSStefano Zampini     }
89793e3c6dadSStefano Zampini     if (nisneu) {
89809566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
89819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8982312be037SStefano Zampini     }
898330368db7SStefano Zampini     if (nisvert) {
89849566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
89859566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
898630368db7SStefano Zampini     }
89871baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8988f9eb5b7dSStefano Zampini 
8989f9eb5b7dSStefano Zampini     /* get some info after set from options */
89909566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
89914f819b78SStefano Zampini 
8992b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
899348a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
899428d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
899528d58a37SPierre Jolivet     force = PETSC_FALSE;
89969566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
89979566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
899848a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
89999566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
90004f3a063dSStefano Zampini     if (isredundant) {
90014f3a063dSStefano Zampini       KSP inner_ksp;
90024f3a063dSStefano Zampini       PC  inner_pc;
90039326c5c6Sstefano_zampini 
90049566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
90059566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
90064f3a063dSStefano Zampini     }
9007f9eb5b7dSStefano Zampini 
900857de7509SStefano Zampini     /* parameters which miss an API */
90099566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
901057de7509SStefano Zampini     if (isbddc) {
9011720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
90127274672aSStefano Zampini 
9013720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
901457de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
9015e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
901627b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
901727b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
9018a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
9019a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
9020a198735bSStefano Zampini         IS                     row, col;
9021a198735bSStefano Zampini         const PetscInt        *gidxs;
9022a198735bSStefano Zampini         PetscInt               n, st, M, N;
9023a198735bSStefano Zampini 
90249566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
90259566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
9026a198735bSStefano Zampini         st = st - n;
90279566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
90289566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
90299566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
90309566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
90319566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
90329566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
90339566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
90349566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
90359566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
90369566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
90379566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
90389566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
90399566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
90409566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
90419566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
90429566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
90439566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
90449566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
90459566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
90469566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
90479566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
90489566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
9049720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
9050bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
9051720d30f9SStefano Zampini       }
9052d4d8cf7bSStefano Zampini     }
90539881197aSStefano Zampini 
90543301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
90559566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
9056b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
9057b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
9058b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
9059b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
9060b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
9061b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
9062b94d7dedSBarry Smith 
906348a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
90646e683305SStefano Zampini     /* set operators */
90659566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
90669566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
90679566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
90681baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
90696e683305SStefano Zampini   }
90709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
90719566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
9072b1ecc7b1SStefano Zampini #if 0
9073b9b85e73SStefano Zampini   {
9074b9b85e73SStefano Zampini     PetscViewer viewer;
9075b9b85e73SStefano Zampini     char filename[256];
9076a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "coarse_mat_level%d.m",pcbddc->current_level));
90779566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
90789566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
90799566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
90809566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
90819566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
9082b9b85e73SStefano Zampini   }
9083b9b85e73SStefano Zampini #endif
9084f9eb5b7dSStefano Zampini 
90854f819b78SStefano Zampini   if (corners) {
90864f819b78SStefano Zampini     Vec             gv;
90874f819b78SStefano Zampini     IS              is;
90884f819b78SStefano Zampini     const PetscInt *idxs;
90894f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
90904f819b78SStefano Zampini     PetscScalar    *coords;
90914f819b78SStefano Zampini 
909228b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
90939566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
90949566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
90959566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
90969566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
90979566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
90989566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
90999566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
91009566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
91014f819b78SStefano Zampini 
91029566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
91039566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
91049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
91059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
91064f819b78SStefano Zampini     for (i = 0; i < n; i++) {
9107ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d];
91084f819b78SStefano Zampini     }
91099566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
91109566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
91114f819b78SStefano Zampini 
91129566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
91139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
91149566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
91159566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
91169566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
91179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
91189566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
91199566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
91204f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
91214f819b78SStefano Zampini       PC        coarse_pc;
91224f819b78SStefano Zampini       PetscBool isbddc;
91234f819b78SStefano Zampini 
91249566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
91259566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
91264f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
91274f819b78SStefano Zampini         PetscReal *realcoords;
91284f819b78SStefano Zampini 
91299566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
91304f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
91319566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
91324f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
91334f819b78SStefano Zampini #else
91344f819b78SStefano Zampini         realcoords = coords;
91354f819b78SStefano Zampini #endif
91369566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
91374f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
91389566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
91394f819b78SStefano Zampini #endif
91404f819b78SStefano Zampini       }
91414f819b78SStefano Zampini     }
91429566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
91439566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
91444f819b78SStefano Zampini   }
91459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
91464f819b78SStefano Zampini 
914798a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
914898a51de6SStefano Zampini     Vec crhs, csol;
914904708bb6SStefano Zampini 
91509566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
91519566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
9152f4f49eeaSPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &pcbddc->coarse_ksp->vec_sol, NULL));
9153f4f49eeaSPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &pcbddc->coarse_ksp->vec_rhs));
9154b0f5fe93SStefano Zampini   }
91559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
9156b0f5fe93SStefano Zampini 
9157b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
9158b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
91599566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
916048a46eb9SPierre 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));
91619566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
91629566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
91639566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
91649566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
9165b0f5fe93SStefano Zampini     if (coarse_mat) {
9166b0f5fe93SStefano Zampini       Vec          nullv;
9167b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
9168b0f5fe93SStefano Zampini       PetscInt     nl;
9169b0f5fe93SStefano Zampini 
91709566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
91719566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
91729566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
91739566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
91749566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
91759566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
91769566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
91779566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
91789566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
91799566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
9180b0f5fe93SStefano Zampini     }
9181b0f5fe93SStefano Zampini   }
91829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
9183b0f5fe93SStefano Zampini 
91849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
9185b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
9186b0f5fe93SStefano Zampini     PetscBool ispreonly;
9187b0f5fe93SStefano Zampini 
9188b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
9189b0f5fe93SStefano Zampini       PetscBool isnull;
91907c625d9fSStefano Zampini 
91919566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
91921baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
9193bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
9194b0f5fe93SStefano Zampini     }
9195b0f5fe93SStefano Zampini     /* setup coarse ksp */
91969566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
9197cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
91989566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
91996e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
9200c8587f34SStefano Zampini       KSP         check_ksp;
92012b510759SStefano Zampini       KSPType     check_ksp_type;
9202c8587f34SStefano Zampini       PC          check_pc;
92036e683305SStefano Zampini       Vec         check_vec, coarse_vec;
92046a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
92052b510759SStefano Zampini       PetscInt    its;
92066e683305SStefano Zampini       PetscBool   compute_eigs;
92076e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
92086e683305SStefano Zampini       PetscInt    neigs;
92098e185a42SStefano Zampini       const char *prefix;
9210c8587f34SStefano Zampini 
92112b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
92129566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
92133821be0aSBarry Smith       PetscCall(KSPSetNestLevel(check_ksp, pc->kspnestlevel));
92149566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
92159566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
92169566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
9217fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_CURRENT, pcbddc->coarse_size));
9218e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
92199566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
92209566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
92212b510759SStefano Zampini       if (ispreonly) {
92222b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
92236e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
92242b510759SStefano Zampini       } else {
9225cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
92266e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
9227c8587f34SStefano Zampini       }
92289566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
92299566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
92309566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
92319566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
92329566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
92339566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
92349566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
92359566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
92369566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
92379566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
92389566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
9239c8587f34SStefano Zampini       /* create random vec */
92409566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
92419566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
92429566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
9243c8587f34SStefano Zampini       /* solve coarse problem */
92449566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
92459566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
9246cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
92476e683305SStefano Zampini       if (compute_eigs) {
92489566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
92499566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
92509566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
92511ae86dd6SStefano Zampini         if (neigs) {
92526e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
92536e683305SStefano Zampini           lambda_min = eigs_r[0];
92546e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
92552701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
92569566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
92579566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
9258cbcc2c2aSStefano Zampini             }
9259c8587f34SStefano Zampini           }
9260c8587f34SStefano Zampini         }
92611ae86dd6SStefano Zampini       }
9262cbcc2c2aSStefano Zampini 
9263c8587f34SStefano Zampini       /* check coarse problem residual error */
92646e683305SStefano Zampini       if (pcbddc->dbg_flag) {
92656e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
92669566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
92679566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
92689566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
92699566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
92709566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
92719566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
9272f4f49eeaSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pcbddc->coarse_ksp, dbg_viewer));
927357508eceSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)check_pc, dbg_viewer));
927463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
927563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
927648a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
92776e683305SStefano Zampini         if (compute_eigs) {
92786e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
9279b03ebc13SStefano Zampini           KSPConvergedReason reason;
92809566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
92819566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
92829566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
92839566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
928463a3b9bcSJacob 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));
928548a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
92866e683305SStefano Zampini         }
92879566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
92889566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
92896e683305SStefano Zampini       }
92909566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
92919566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
92929566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
92936e683305SStefano Zampini       if (compute_eigs) {
92949566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
92959566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
9296c8587f34SStefano Zampini       }
92976e683305SStefano Zampini     }
92986e683305SStefano Zampini   }
92999566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
9300cbcc2c2aSStefano Zampini   /* print additional info */
9301cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
93026e683305SStefano Zampini     /* waits until all processes reaches this point */
93039566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
930463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
93059566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9306cbcc2c2aSStefano Zampini   }
9307cbcc2c2aSStefano Zampini 
93082b510759SStefano Zampini   /* free memory */
93099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
93109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
93113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9312c8587f34SStefano Zampini }
9313674ae819SStefano Zampini 
9314d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n)
9315d71ae5a4SJacob Faibussowitsch {
9316f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
9317f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
9318dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
9319dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
932073be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
9321dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
9322f34684f1SStefano Zampini 
9323f34684f1SStefano Zampini   PetscFunctionBegin;
9324f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
932508401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
9326f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
93279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
93289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9329f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
93309566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
93319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
93329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
93339566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
933463a3b9bcSJacob 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);
93359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
93369566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
93379566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
93389566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
93399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9340f34684f1SStefano Zampini 
9341f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
93429566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
93439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
93449de2952eSStefano Zampini     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT "\n", coarse_size));
93459566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9346f34684f1SStefano Zampini   }
93476080607fSStefano Zampini 
9348f34684f1SStefano Zampini   /* get back data */
9349f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
9350f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
93513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9352674ae819SStefano Zampini }
9353674ae819SStefano Zampini 
9354d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis)
9355d71ae5a4SJacob Faibussowitsch {
9356e456f2a8SStefano Zampini   IS           localis_t;
9357a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
9358e456f2a8SStefano Zampini   PetscScalar *vals;
9359e456f2a8SStefano Zampini 
9360e456f2a8SStefano Zampini   PetscFunctionBegin;
9361a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
93629566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
93639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
9364e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
93659566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
93669566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
93679566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
93681035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
93699566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
93709566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
93711035eff8SStefano Zampini   }
93729566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
93739566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
93749566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
93759566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
9376a7dc3881SStefano Zampini   /* now compute set in local ordering */
93779566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
93789566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
93799566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
93809566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
9381a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9382ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) lsize++;
9383e456f2a8SStefano Zampini   }
93849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
9385a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9386ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) idxs[lsize++] = i;
9387e456f2a8SStefano Zampini   }
93889566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
93899566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
9390e456f2a8SStefano Zampini   *localis = localis_t;
93913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9392e456f2a8SStefano Zampini }
9393906d46d4SStefano Zampini 
9394d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr)
9395d71ae5a4SJacob Faibussowitsch {
93967c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
93977c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
93987c625d9fSStefano Zampini   PC_IS   *pcisf;
93997c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
94007c625d9fSStefano Zampini   PC       pcf;
94017c625d9fSStefano Zampini 
94027c625d9fSStefano Zampini   PetscFunctionBegin;
94037c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
94047c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
94057c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
94067c625d9fSStefano Zampini 
94077c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
940832fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
940932fe681dSStefano Zampini 
94107c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
94117c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
94127c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
94137c625d9fSStefano Zampini   pcisf->n          = pcis->n;
94147c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
94157c625d9fSStefano Zampini 
94167c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
941732fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
94187c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
941932fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
942032fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
942132fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
942232fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
942332fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
942432fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
94257c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
942632fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
942732fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
942832fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
94297c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
943032fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
943132fe681dSStefano Zampini 
943232fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
94337c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
94347c625d9fSStefano Zampini 
94357c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
94367c625d9fSStefano 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));
94377c625d9fSStefano 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));
94387c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
94397c625d9fSStefano Zampini 
944032fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
94417c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
944232fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
944332fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
944432fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
944532fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
94467c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
94473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
94487c625d9fSStefano Zampini }
94497c625d9fSStefano Zampini 
9450d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
9451d71ae5a4SJacob Faibussowitsch {
9452a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
9453b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
9454b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
9455a64f4aa4SStefano Zampini   Mat             S_j;
9456b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
9457b96c3477SStefano Zampini   PetscBool       free_used_adj;
9458b96c3477SStefano Zampini 
9459b96c3477SStefano Zampini   PetscFunctionBegin;
94609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
9461b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
9462b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
946308122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
9464b96c3477SStefano Zampini     used_xadj   = NULL;
9465b96c3477SStefano Zampini     used_adjncy = NULL;
9466b96c3477SStefano Zampini   } else {
946708122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
946808122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
946908122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
947008122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
9471b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
9472b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
9473b96c3477SStefano Zampini     } else {
94742fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
9475b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
9476b96c3477SStefano Zampini       PetscInt        nvtxs;
9477b96c3477SStefano Zampini 
94789566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
94792fffb893SStefano Zampini       if (flg_row) {
94809566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
94819566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
94829566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
9483b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
94842fffb893SStefano Zampini       } else {
94852fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
94862fffb893SStefano Zampini         used_xadj                 = NULL;
94872fffb893SStefano Zampini         used_adjncy               = NULL;
94882fffb893SStefano Zampini       }
94899566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
9490b96c3477SStefano Zampini     }
9491b96c3477SStefano Zampini   }
9492d5574798SStefano Zampini 
9493d5574798SStefano Zampini   /* setup sub_schurs data */
94949566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
9495df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
9496df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
94979566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
94989566063dSJacob 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));
9499a64f4aa4SStefano Zampini   } else {
950072b8c272SStefano Zampini     Mat       change        = NULL;
95019d54b7f4SStefano Zampini     Vec       scaling       = NULL;
9502111315fdSstefano_zampini     IS        change_primal = NULL, iP;
9503111315fdSstefano_zampini     PetscInt  benign_n;
9504111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
95057ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
9506111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
9507a3df083aSStefano Zampini 
95085feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
95095feab87aSStefano Zampini       PetscInt n_vertices;
95105feab87aSStefano Zampini 
95119566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
95122034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
95135feab87aSStefano Zampini     }
9514a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
9515a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
9516ca92afb2SStefano Zampini     } else {
9517a3df083aSStefano Zampini       benign_n = 0;
9518ca92afb2SStefano Zampini     }
9519b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
9520b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
9521b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
952272b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
952322db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
95245440e5dcSBarry Smith       PetscCallMPI(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
952522db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
9526b7ab4a40SStefano Zampini     }
95277c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
9528b7ab4a40SStefano Zampini     if (need_change) {
952928b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
953032fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
953188c03ad3SStefano Zampini     }
95329d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
9533111315fdSstefano_zampini 
95349566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
9535111315fdSstefano_zampini     if (iP) {
9536d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
95379566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
9538d0609cedSBarry Smith       PetscOptionsEnd();
9539111315fdSstefano_zampini     }
9540111315fdSstefano_zampini     if (discrete_harmonic) {
9541111315fdSstefano_zampini       Mat A;
95429566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
95439566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
95449566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
95459371c9d4SSatish 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,
95469371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
95479566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
9548111315fdSstefano_zampini     } else {
95499371c9d4SSatish 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,
95509371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
9551111315fdSstefano_zampini     }
95529566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
95539566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
9554ca92afb2SStefano Zampini   }
95559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
9556b96c3477SStefano Zampini 
9557b96c3477SStefano Zampini   /* free adjacency */
95581baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
95599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
95603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9561b96c3477SStefano Zampini }
9562b96c3477SStefano Zampini 
9563d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCInitSubSchurs(PC pc)
9564d71ae5a4SJacob Faibussowitsch {
9565b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
9566b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
9567b96c3477SStefano Zampini   PCBDDCGraph graph;
9568b96c3477SStefano Zampini 
9569b96c3477SStefano Zampini   PetscFunctionBegin;
9570b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
957108122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
95723301b35fSStefano Zampini     IS       verticesIS, verticescomm;
95733301b35fSStefano Zampini     PetscInt vsize, *idxs;
9574b96c3477SStefano Zampini 
95759566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
95769566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
95779566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
95789566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
95799566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
95809566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
95819566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
95829566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
95839566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
95849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
95859566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
9586b96c3477SStefano Zampini   } else {
9587b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
9588b96c3477SStefano Zampini   }
9589e4d548c7SStefano Zampini   /* print some info */
95905c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
9591e4d548c7SStefano Zampini     IS       vertices;
9592e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
95939566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
95949566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
95959566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
95969566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
95979566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
959863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
959963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
960063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
96019566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
96029566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
96039566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
9604e4d548c7SStefano Zampini   }
9605b96c3477SStefano Zampini 
9606b96c3477SStefano Zampini   /* sub_schurs init */
960748a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
960832fe681dSStefano 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));
9609a64f4aa4SStefano Zampini 
9610b96c3477SStefano Zampini   /* free graph struct */
961148a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
96123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9613b96c3477SStefano Zampini }
9614fa34dd3eSStefano Zampini 
96159de2952eSStefano Zampini static PetscErrorCode PCBDDCViewGlobalIS(PC pc, IS is, PetscViewer viewer)
96169de2952eSStefano Zampini {
96179de2952eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
96189de2952eSStefano Zampini   PetscInt        n     = pc->pmat->rmap->n, ln, ni, st;
96199de2952eSStefano Zampini   const PetscInt *idxs;
96209de2952eSStefano Zampini   IS              gis;
96219de2952eSStefano Zampini 
96229de2952eSStefano Zampini   PetscFunctionBegin;
96239de2952eSStefano Zampini   if (!is) PetscFunctionReturn(PETSC_SUCCESS);
96249de2952eSStefano Zampini   PetscCall(MatGetOwnershipRange(pc->pmat, &st, NULL));
96259de2952eSStefano Zampini   PetscCall(MatGetLocalSize(matis->A, NULL, &ln));
96269de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_leafdata, ln));
96279de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_rootdata, n));
96289de2952eSStefano Zampini   PetscCall(ISGetLocalSize(is, &ni));
96299de2952eSStefano Zampini   PetscCall(ISGetIndices(is, &idxs));
96309de2952eSStefano Zampini   for (PetscInt i = 0; i < ni; i++) {
96319de2952eSStefano Zampini     if (idxs[i] < 0 || idxs[i] >= ln) continue;
96329de2952eSStefano Zampini     matis->sf_leafdata[idxs[i]] = 1;
96339de2952eSStefano Zampini   }
96349de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is, &idxs));
96359de2952eSStefano Zampini   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
96369de2952eSStefano Zampini   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
96379de2952eSStefano Zampini   ln = 0;
96389de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
96399de2952eSStefano Zampini     if (matis->sf_rootdata[i]) matis->sf_rootdata[ln++] = i + st;
96409de2952eSStefano Zampini   }
96419de2952eSStefano Zampini   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), ln, matis->sf_rootdata, PETSC_USE_POINTER, &gis));
96429de2952eSStefano Zampini   PetscCall(ISView(gis, viewer));
96439de2952eSStefano Zampini   PetscCall(ISDestroy(&gis));
96449de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
96459de2952eSStefano Zampini }
96469de2952eSStefano Zampini 
96479de2952eSStefano Zampini PetscErrorCode PCBDDCLoadOrViewCustomization(PC pc, PetscBool load, const char *outfile)
96489de2952eSStefano Zampini {
96499de2952eSStefano Zampini   PetscInt    header[11];
96509de2952eSStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
96519de2952eSStefano Zampini   PetscViewer viewer;
96529de2952eSStefano Zampini   MPI_Comm    comm = PetscObjectComm((PetscObject)pc);
96539de2952eSStefano Zampini 
96549de2952eSStefano Zampini   PetscFunctionBegin;
96559de2952eSStefano Zampini   PetscCall(PetscViewerBinaryOpen(comm, outfile ? outfile : "bddc_dump.dat", load ? FILE_MODE_READ : FILE_MODE_WRITE, &viewer));
96569de2952eSStefano Zampini   if (load) {
96579de2952eSStefano Zampini     IS  is;
96589de2952eSStefano Zampini     Mat A;
96599de2952eSStefano Zampini 
96609de2952eSStefano Zampini     PetscCall(PetscViewerBinaryRead(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), NULL, PETSC_INT));
96619de2952eSStefano Zampini     PetscCheck(header[0] == 0 || header[0] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96629de2952eSStefano Zampini     PetscCheck(header[1] == 0 || header[1] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96639de2952eSStefano Zampini     PetscCheck(header[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96649de2952eSStefano Zampini     PetscCheck(header[3] == 0 || header[3] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96659de2952eSStefano Zampini     PetscCheck(header[4] == 0 || header[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96669de2952eSStefano Zampini     PetscCheck(header[5] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96679de2952eSStefano Zampini     PetscCheck(header[7] == 0 || header[7] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96689de2952eSStefano Zampini     PetscCheck(header[8] == 0 || header[8] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96699de2952eSStefano Zampini     PetscCheck(header[9] == 0 || header[9] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96709de2952eSStefano Zampini     PetscCheck(header[10] == 0 || header[10] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
96719de2952eSStefano Zampini     if (header[0]) {
96729de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
96739de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
96749de2952eSStefano Zampini       PetscCall(PCBDDCSetDirichletBoundaries(pc, is));
96759de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
96769de2952eSStefano Zampini     }
96779de2952eSStefano Zampini     if (header[1]) {
96789de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
96799de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
96809de2952eSStefano Zampini       PetscCall(PCBDDCSetNeumannBoundaries(pc, is));
96819de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
96829de2952eSStefano Zampini     }
96839de2952eSStefano Zampini     if (header[2]) {
96849de2952eSStefano Zampini       IS *isarray;
96859de2952eSStefano Zampini 
96869de2952eSStefano Zampini       PetscCall(PetscMalloc1(header[2], &isarray));
96879de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) {
96889de2952eSStefano Zampini         PetscCall(ISCreate(comm, &isarray[i]));
96899de2952eSStefano Zampini         PetscCall(ISLoad(isarray[i], viewer));
96909de2952eSStefano Zampini       }
96919de2952eSStefano Zampini       PetscCall(PCBDDCSetDofsSplitting(pc, header[2], isarray));
96929de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) PetscCall(ISDestroy(&isarray[i]));
96939de2952eSStefano Zampini       PetscCall(PetscFree(isarray));
96949de2952eSStefano Zampini     }
96959de2952eSStefano Zampini     if (header[3]) {
96969de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
96979de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
96989de2952eSStefano Zampini       PetscCall(PCBDDCSetPrimalVerticesIS(pc, is));
96999de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
97009de2952eSStefano Zampini     }
97019de2952eSStefano Zampini     if (header[4]) {
97029de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
97039de2952eSStefano Zampini       PetscCall(MatSetType(A, MATAIJ));
97049de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
97059de2952eSStefano Zampini       PetscCall(PCBDDCSetDiscreteGradient(pc, A, header[5], header[6], (PetscBool)header[7], (PetscBool)header[8]));
97069de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
97079de2952eSStefano Zampini     }
97089de2952eSStefano Zampini     if (header[9]) {
97099de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
97109de2952eSStefano Zampini       PetscCall(MatSetType(A, MATIS));
97119de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
97129de2952eSStefano Zampini       PetscCall(PCBDDCSetDivergenceMat(pc, A, (PetscBool)header[10], NULL));
97139de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
97149de2952eSStefano Zampini     }
97159de2952eSStefano Zampini   } else {
97169de2952eSStefano Zampini     header[0]  = (PetscInt)!!pcbddc->DirichletBoundariesLocal;
97179de2952eSStefano Zampini     header[1]  = (PetscInt)!!pcbddc->NeumannBoundariesLocal;
97189de2952eSStefano Zampini     header[2]  = pcbddc->n_ISForDofsLocal;
97199de2952eSStefano Zampini     header[3]  = (PetscInt)!!pcbddc->user_primal_vertices_local;
97209de2952eSStefano Zampini     header[4]  = (PetscInt)!!pcbddc->discretegradient;
97219de2952eSStefano Zampini     header[5]  = pcbddc->nedorder;
97229de2952eSStefano Zampini     header[6]  = pcbddc->nedfield;
97239de2952eSStefano Zampini     header[7]  = (PetscInt)pcbddc->nedglobal;
97249de2952eSStefano Zampini     header[8]  = (PetscInt)pcbddc->conforming;
97259de2952eSStefano Zampini     header[9]  = (PetscInt)!!pcbddc->divudotp;
97269de2952eSStefano Zampini     header[10] = (PetscInt)pcbddc->divudotp_trans;
97279de2952eSStefano Zampini     if (header[4]) header[3] = 0;
97289de2952eSStefano Zampini 
97299de2952eSStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), PETSC_INT));
97309de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->DirichletBoundariesLocal, viewer));
97319de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->NeumannBoundariesLocal, viewer));
97329de2952eSStefano Zampini     for (PetscInt i = 0; i < header[2]; i++) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->ISForDofsLocal[i], viewer));
97339de2952eSStefano Zampini     if (header[3]) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->user_primal_vertices_local, viewer));
97349de2952eSStefano Zampini     if (header[4]) PetscCall(MatView(pcbddc->discretegradient, viewer));
97359de2952eSStefano Zampini     if (header[9]) PetscCall(MatView(pcbddc->divudotp, viewer));
97369de2952eSStefano Zampini   }
97379de2952eSStefano Zampini   PetscCall(PetscViewerDestroy(&viewer));
97389de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
97399de2952eSStefano Zampini }
97409de2952eSStefano Zampini 
97411e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
9742ba38deedSJacob Faibussowitsch static PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
9743d71ae5a4SJacob Faibussowitsch {
97441e0482f5SStefano Zampini   Mat         At;
97451e0482f5SStefano Zampini   IS          rows;
97461e0482f5SStefano Zampini   PetscInt    rst, ren;
97471e0482f5SStefano Zampini   PetscLayout rmap;
97481e0482f5SStefano Zampini 
97491e0482f5SStefano Zampini   PetscFunctionBegin;
97501e0482f5SStefano Zampini   rst = ren = 0;
97511e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
97529566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
97539566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
97549566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
97559566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
97569566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
97571e0482f5SStefano Zampini   }
97589566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
97599566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
97609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
97611e0482f5SStefano Zampini 
97621e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
97631e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
97641e0482f5SStefano Zampini     IS          from, to;
97651e0482f5SStefano Zampini     Vec         gvec;
97661e0482f5SStefano Zampini     PetscInt    lsize;
97671e0482f5SStefano Zampini 
97689566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
97699566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
97709566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
977157508eceSPierre Jolivet     PetscCall(PetscLayoutDestroy(&(*B)->rmap));
97729566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
97731e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
97741e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
97759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
97769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
97779566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
97789566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
97791e0482f5SStefano Zampini     b->A = a->A;
97801e0482f5SStefano Zampini     b->B = a->B;
97811e0482f5SStefano Zampini 
97821e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
97831e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
97840a545947SLisandro Dalcin     b->rowindices   = NULL;
97850a545947SLisandro Dalcin     b->rowvalues    = NULL;
97861e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
97871e0482f5SStefano Zampini 
97881e0482f5SStefano Zampini     (*B)->rmap         = rmap;
97891e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
97901e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
97911e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
97921e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
97931e0482f5SStefano Zampini 
97941e0482f5SStefano Zampini     if (a->colmap) {
97951e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
9796eec179cfSJacob Faibussowitsch       PetscCall(PetscHMapIDuplicate(a->colmap, &b->colmap));
97971e0482f5SStefano Zampini #else
97989566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
97999566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
98001e0482f5SStefano Zampini #endif
98010a545947SLisandro Dalcin     } else b->colmap = NULL;
98021e0482f5SStefano Zampini     if (a->garray) {
98031e0482f5SStefano Zampini       PetscInt len;
98041e0482f5SStefano Zampini       len = a->B->cmap->n;
98059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
98069566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
98070a545947SLisandro Dalcin     } else b->garray = NULL;
98081e0482f5SStefano Zampini 
98099566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
98101e0482f5SStefano Zampini     b->lvec = a->lvec;
98111e0482f5SStefano Zampini 
98121e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
98139566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
98149566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
98159566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
98169566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
98179566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
98189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
98199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
98209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
98211e0482f5SStefano Zampini   }
98229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
98233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98241e0482f5SStefano Zampini }
98259de2952eSStefano Zampini 
98269de2952eSStefano Zampini /* same as MatCreateSubMatrix(A, rows, NULL,...) but allows repeated rows */
98279de2952eSStefano Zampini static PetscErrorCode MatAIJExtractRows(Mat A, IS rows, Mat *sA)
98289de2952eSStefano Zampini {
98299de2952eSStefano Zampini   PetscBool isaij;
98309de2952eSStefano Zampini   MPI_Comm  comm;
98319de2952eSStefano Zampini 
98329de2952eSStefano Zampini   PetscFunctionBegin;
98339de2952eSStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
98349de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &isaij, MATSEQAIJ, MATMPIAIJ, ""));
98359de2952eSStefano Zampini   PetscCheck(isaij, comm, PETSC_ERR_SUP, "Not implemented");
98369de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isaij));
98379de2952eSStefano Zampini   if (isaij) { /* SeqAIJ supports repeated rows */
98389de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, sA));
98399de2952eSStefano Zampini   } else {
98409de2952eSStefano Zampini     Mat                A_loc;
98419de2952eSStefano Zampini     Mat_SeqAIJ        *da;
98429de2952eSStefano Zampini     PetscSF            sf;
98439de2952eSStefano Zampini     PetscInt           ni, *di, *dj, m = A->rmap->n, c, *ldata, *rdata;
98449de2952eSStefano Zampini     PetscScalar       *daa;
98459de2952eSStefano Zampini     const PetscInt    *idxs;
98469de2952eSStefano Zampini     const PetscSFNode *iremotes;
98479de2952eSStefano Zampini     PetscSFNode       *remotes;
98489de2952eSStefano Zampini 
98499de2952eSStefano Zampini     /* SF for incoming rows */
98509de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &sf));
98519de2952eSStefano Zampini     PetscCall(ISGetLocalSize(rows, &ni));
98529de2952eSStefano Zampini     PetscCall(ISGetIndices(rows, &idxs));
98539de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, ni, NULL, PETSC_USE_POINTER, idxs));
98549de2952eSStefano Zampini     PetscCall(ISRestoreIndices(rows, &idxs));
98559de2952eSStefano Zampini 
98569de2952eSStefano Zampini     PetscCall(MatMPIAIJGetLocalMat(A, MAT_INITIAL_MATRIX, &A_loc));
98579de2952eSStefano Zampini     da = (Mat_SeqAIJ *)A_loc->data;
98589de2952eSStefano Zampini     PetscCall(PetscMalloc2(2 * ni, &ldata, 2 * m, &rdata));
98599de2952eSStefano Zampini     for (PetscInt i = 0; i < m; i++) {
98609de2952eSStefano Zampini       rdata[2 * i + 0] = da->i[i + 1] - da->i[i];
98619de2952eSStefano Zampini       rdata[2 * i + 1] = da->i[i];
98629de2952eSStefano Zampini     }
98639de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
98649de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
98659de2952eSStefano Zampini     PetscCall(PetscMalloc1(ni + 1, &di));
98669de2952eSStefano Zampini     di[0] = 0;
98679de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) di[i + 1] = di[i] + ldata[2 * i + 0];
98689de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &dj));
98699de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &daa));
98709de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &remotes));
98719de2952eSStefano Zampini 
98729de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(sf, NULL, NULL, NULL, &iremotes));
98739de2952eSStefano Zampini 
98749de2952eSStefano Zampini     /* SF graph for nonzeros */
98759de2952eSStefano Zampini     c = 0;
98769de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) {
9877835f2295SStefano Zampini       const PetscInt rank  = iremotes[i].rank;
98789de2952eSStefano Zampini       const PetscInt rsize = ldata[2 * i];
98799de2952eSStefano Zampini       for (PetscInt j = 0; j < rsize; j++) {
98809de2952eSStefano Zampini         remotes[c].rank  = rank;
98819de2952eSStefano Zampini         remotes[c].index = ldata[2 * i + 1] + j;
98829de2952eSStefano Zampini         c++;
98839de2952eSStefano Zampini       }
98849de2952eSStefano Zampini     }
98859de2952eSStefano Zampini     PetscCheck(c == di[ni], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of local nonzeros %" PetscInt_FMT " != %" PetscInt_FMT, c, di[ni]);
98869de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(sf, da->i[m], di[ni], NULL, PETSC_USE_POINTER, remotes, PETSC_USE_POINTER));
98879de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
98889de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
98899de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
98909de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
98919de2952eSStefano Zampini 
98929de2952eSStefano Zampini     PetscCall(MatCreateMPIAIJWithArrays(comm, ni, A->cmap->n, PETSC_DECIDE, A->cmap->N, di, dj, daa, sA));
98939de2952eSStefano Zampini     PetscCall(MatDestroy(&A_loc));
98949de2952eSStefano Zampini     PetscCall(PetscSFDestroy(&sf));
98959de2952eSStefano Zampini     PetscCall(PetscFree(di));
98969de2952eSStefano Zampini     PetscCall(PetscFree(dj));
98979de2952eSStefano Zampini     PetscCall(PetscFree(daa));
98989de2952eSStefano Zampini     PetscCall(PetscFree(remotes));
98999de2952eSStefano Zampini     PetscCall(PetscFree2(ldata, rdata));
99009de2952eSStefano Zampini   }
99019de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
99029de2952eSStefano Zampini }
9903