xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
11cf9b237SStefano Zampini #include <../src/mat/impls/aij/seq/aij.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
4837cedc9SStefano Zampini #include <../src/mat/impls/dense/seq/dense.h>
5c80a6c00SStefano Zampini #include <petscdmplex.h>
6674ae819SStefano Zampini #include <petscblaslapack.h>
7daf8a457SStefano Zampini #include <petsc/private/sfimpl.h>
8c80a6c00SStefano Zampini #include <petsc/private/dmpleximpl.h>
97620a527SStefano Zampini #include <petscdmda.h>
10674ae819SStefano Zampini 
111e0482f5SStefano Zampini static PetscErrorCode MatMPIAIJRestrict(Mat, MPI_Comm, Mat *);
121e0482f5SStefano Zampini 
13f498cd09SStefano Zampini /* if range is true,  it returns B s.t. span{B} = range(A)
14f498cd09SStefano Zampini    if range is false, it returns B s.t. range(B) _|_ range(A) */
159371c9d4SSatish Balay PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B) {
16a13144ffSStefano Zampini   PetscScalar *uwork, *data, *U, ds = 0.;
17a13144ffSStefano Zampini   PetscReal   *sing;
18a13144ffSStefano Zampini   PetscBLASInt bM, bN, lwork, lierr, di = 1;
19a13144ffSStefano Zampini   PetscInt     ulw, i, nr, nc, n;
20abee2b68SSebastian Grimberg #if defined(PETSC_USE_COMPLEX)
21abee2b68SSebastian Grimberg   PetscReal *rwork2;
22abee2b68SSebastian Grimberg #endif
23a13144ffSStefano Zampini 
24a13144ffSStefano Zampini   PetscFunctionBegin;
259566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
26a13144ffSStefano Zampini   if (!nr || !nc) PetscFunctionReturn(0);
27a13144ffSStefano Zampini 
28a13144ffSStefano Zampini   /* workspace */
29a13144ffSStefano Zampini   if (!work) {
30a13144ffSStefano Zampini     ulw = PetscMax(PetscMax(1, 5 * PetscMin(nr, nc)), 3 * PetscMin(nr, nc) + PetscMax(nr, nc));
319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ulw, &uwork));
32a13144ffSStefano Zampini   } else {
33a13144ffSStefano Zampini     ulw   = lw;
34a13144ffSStefano Zampini     uwork = work;
35a13144ffSStefano Zampini   }
36a13144ffSStefano Zampini   n = PetscMin(nr, nc);
37a13144ffSStefano Zampini   if (!rwork) {
389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &sing));
39a13144ffSStefano Zampini   } else {
40a13144ffSStefano Zampini     sing = rwork;
41a13144ffSStefano Zampini   }
42a13144ffSStefano Zampini 
43a13144ffSStefano Zampini   /* SVD */
449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nr, &U));
459566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nr, &bM));
469566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nc, &bN));
479566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(ulw, &lwork));
489566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(A, &data));
499566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
50abee2b68SSebastian Grimberg #if !defined(PETSC_USE_COMPLEX)
51792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, &lierr));
52abee2b68SSebastian Grimberg #else
539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(5 * n, &rwork2));
54792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, rwork2, &lierr));
559566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork2));
56abee2b68SSebastian Grimberg #endif
579566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPop());
5828b400f6SJacob Faibussowitsch   PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
599566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(A, &data));
609371c9d4SSatish Balay   for (i = 0; i < n; i++)
619371c9d4SSatish Balay     if (sing[i] < PETSC_SMALL) break;
62*48a46eb9SPierre Jolivet   if (!rwork) PetscCall(PetscFree(sing));
63*48a46eb9SPierre Jolivet   if (!work) PetscCall(PetscFree(uwork));
64a13144ffSStefano Zampini   /* create B */
65f498cd09SStefano Zampini   if (!range) {
669566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, nr - i, NULL, B));
679566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
689566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U + nr * i, (nr - i) * nr));
69f498cd09SStefano Zampini   } else {
709566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, i, NULL, B));
719566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
729566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U, i * nr));
73f498cd09SStefano Zampini   }
749566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(*B, &data));
759566063dSJacob Faibussowitsch   PetscCall(PetscFree(U));
76a13144ffSStefano Zampini   PetscFunctionReturn(0);
77a13144ffSStefano Zampini }
78a13144ffSStefano Zampini 
791e0482f5SStefano Zampini /* TODO REMOVE */
801e0482f5SStefano Zampini #if defined(PRINT_GDET)
811e0482f5SStefano Zampini static int inc = 0;
821e0482f5SStefano Zampini static int lev = 0;
831e0482f5SStefano Zampini #endif
841e0482f5SStefano Zampini 
859371c9d4SSatish Balay PetscErrorCode PCBDDCComputeNedelecChangeEdge(Mat lG, IS edge, IS extrow, IS extcol, IS corners, Mat *Gins, Mat *GKins, PetscScalar cvals[2], PetscScalar *work, PetscReal *rwork) {
86a13144ffSStefano Zampini   Mat          GE, GEd;
87a13144ffSStefano Zampini   PetscInt     rsize, csize, esize;
88a13144ffSStefano Zampini   PetscScalar *ptr;
89a13144ffSStefano Zampini 
90a13144ffSStefano Zampini   PetscFunctionBegin;
919566063dSJacob Faibussowitsch   PetscCall(ISGetSize(edge, &esize));
92c3c0e390SStefano Zampini   if (!esize) PetscFunctionReturn(0);
939566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extrow, &rsize));
949566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extcol, &csize));
95a13144ffSStefano Zampini 
96a13144ffSStefano Zampini   /* gradients */
97a13144ffSStefano Zampini   ptr = work + 5 * esize;
989566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, extrow, extcol, MAT_INITIAL_MATRIX, &GE));
999566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, rsize, csize, ptr, Gins));
1009566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, Gins));
1019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
102a13144ffSStefano Zampini 
103a13144ffSStefano Zampini   /* constants */
104a13144ffSStefano Zampini   ptr += rsize * csize;
1059566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, esize, csize, ptr, &GEd));
1069566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, edge, extcol, MAT_INITIAL_MATRIX, &GE));
1079566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, &GEd));
1089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
1099566063dSJacob Faibussowitsch   PetscCall(MatDenseOrthogonalRangeOrComplement(GEd, PETSC_FALSE, 5 * esize, work, rwork, GKins));
1109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GEd));
1111e0482f5SStefano Zampini 
1121e0482f5SStefano Zampini   if (corners) {
1131e0482f5SStefano Zampini     Mat                GEc;
1141683a169SBarry Smith     const PetscScalar *vals;
1151683a169SBarry Smith     PetscScalar        v;
1161e0482f5SStefano Zampini 
1179566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(lG, edge, corners, MAT_INITIAL_MATRIX, &GEc));
1189566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(GEc, *GKins, MAT_INITIAL_MATRIX, 1.0, &GEd));
1199566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(GEd, &vals));
120637e8532SStefano Zampini     /* v    = PetscAbsScalar(vals[0]) */;
121637e8532SStefano Zampini     v        = 1.;
1221e0482f5SStefano Zampini     cvals[0] = vals[0] / v;
1231e0482f5SStefano Zampini     cvals[1] = vals[1] / v;
1249566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(GEd, &vals));
1259566063dSJacob Faibussowitsch     PetscCall(MatScale(*GKins, 1. / v));
1261e0482f5SStefano Zampini #if defined(PRINT_GDET)
1271e0482f5SStefano Zampini     {
1281e0482f5SStefano Zampini       PetscViewer viewer;
1291e0482f5SStefano Zampini       char        filename[256];
1301e0482f5SStefano Zampini       sprintf(filename, "Gdet_l%d_r%d_cc%d.m", lev, PetscGlobalRank, inc++);
1319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &viewer));
1329566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
1339566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEc, "GEc"));
1349566063dSJacob Faibussowitsch       PetscCall(MatView(GEc, viewer));
1359566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)(*GKins), "GK"));
1369566063dSJacob Faibussowitsch       PetscCall(MatView(*GKins, viewer));
1379566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEd, "Gproj"));
1389566063dSJacob Faibussowitsch       PetscCall(MatView(GEd, viewer));
1399566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
1401e0482f5SStefano Zampini     }
1411e0482f5SStefano Zampini #endif
1429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEd));
1439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEc));
1441e0482f5SStefano Zampini   }
1451e0482f5SStefano Zampini 
146a13144ffSStefano Zampini   PetscFunctionReturn(0);
147a13144ffSStefano Zampini }
148a13144ffSStefano Zampini 
1499371c9d4SSatish Balay PetscErrorCode PCBDDCNedelecSupport(PC pc) {
150a13144ffSStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
151a13144ffSStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
1520569b399SStefano Zampini   Mat                    G, T, conn, lG, lGt, lGis, lGall, lGe, lGinit;
153eee23b56SStefano Zampini   Vec                    tvec;
154a13144ffSStefano Zampini   PetscSF                sfv;
1551e0482f5SStefano Zampini   ISLocalToGlobalMapping el2g, vl2g, fl2g, al2g;
156a13144ffSStefano Zampini   MPI_Comm               comm;
157c2151214SStefano Zampini   IS                     lned, primals, allprimals, nedfieldlocal;
158c2151214SStefano Zampini   IS                    *eedges, *extrows, *extcols, *alleedges;
1597d871cd7SStefano Zampini   PetscBT                btv, bte, btvc, btb, btbd, btvcand, btvi, btee, bter;
160a13144ffSStefano Zampini   PetscScalar           *vals, *work;
161a13144ffSStefano Zampini   PetscReal             *rwork;
162a13144ffSStefano Zampini   const PetscInt        *idxs, *ii, *jj, *iit, *jjt;
1631e0482f5SStefano Zampini   PetscInt               ne, nv, Lv, order, n, field;
164a13144ffSStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
165eee23b56SStefano Zampini   PetscInt               i, j, extmem, cum, maxsize, nee;
166b03ebc13SStefano Zampini   PetscInt              *extrow, *extrowcum, *marks, *vmarks, *gidxs;
167a13144ffSStefano Zampini   PetscInt              *sfvleaves, *sfvroots;
168b03ebc13SStefano Zampini   PetscInt              *corners, *cedges;
169637e8532SStefano Zampini   PetscInt              *ecount, **eneighs, *vcount, **vneighs;
170b03ebc13SStefano Zampini   PetscInt              *emarks;
171213b8bfaSStefano Zampini   PetscBool              print, eerr, done, lrc[2], conforming, global, singular, setprimal;
172a13144ffSStefano Zampini 
173a13144ffSStefano Zampini   PetscFunctionBegin;
174213b8bfaSStefano Zampini   /* If the discrete gradient is defined for a subset of dofs and global is true,
175213b8bfaSStefano Zampini      it assumes G is given in global ordering for all the dofs.
176213b8bfaSStefano Zampini      Otherwise, the ordering is global for the Nedelec field */
177213b8bfaSStefano Zampini   order      = pcbddc->nedorder;
178213b8bfaSStefano Zampini   conforming = pcbddc->conforming;
179213b8bfaSStefano Zampini   field      = pcbddc->nedfield;
180213b8bfaSStefano Zampini   global     = pcbddc->nedglobal;
181213b8bfaSStefano Zampini   setprimal  = PETSC_FALSE;
182a13144ffSStefano Zampini   print      = PETSC_FALSE;
183213b8bfaSStefano Zampini   singular   = PETSC_FALSE;
184a13144ffSStefano Zampini 
185213b8bfaSStefano Zampini   /* Command line customization */
186d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC Nedelec options", "PC");
1879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_field_primal", "All edge dofs set as primals: Toselli's algorithm C", NULL, setprimal, &setprimal, NULL));
1889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_singular", "Infer nullspace from discrete gradient", NULL, singular, &singular, NULL));
1899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bddc_nedelec_order", "Test variable order code (to be removed)", NULL, order, &order, NULL));
190213b8bfaSStefano Zampini   /* print debug info TODO: to be removed */
1919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_print", "Print debug info", NULL, print, &print, NULL));
192d0609cedSBarry Smith   PetscOptionsEnd();
193213b8bfaSStefano Zampini 
194213b8bfaSStefano Zampini   /* Return if there are no edges in the decomposition and the problem is not singular */
1959566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &al2g, NULL));
1969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(al2g, &n));
1979566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
198213b8bfaSStefano Zampini   if (!singular) {
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));
2081c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lrc[0], &lrc[1], 1, MPIU_BOOL, MPI_LOR, comm));
209a13144ffSStefano Zampini     if (!lrc[1]) PetscFunctionReturn(0);
210213b8bfaSStefano Zampini   }
211a13144ffSStefano Zampini 
212213b8bfaSStefano Zampini   /* Get Nedelec field */
21363a3b9bcSJacob 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);
214213b8bfaSStefano Zampini   if (pcbddc->n_ISForDofsLocal && field >= 0) {
2159566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofsLocal[field]));
216c2151214SStefano Zampini     nedfieldlocal = pcbddc->ISForDofsLocal[field];
2179566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nedfieldlocal, &ne));
218213b8bfaSStefano Zampini   } else if (!pcbddc->n_ISForDofsLocal && field != PETSC_DECIDE) {
219213b8bfaSStefano Zampini     ne            = n;
220213b8bfaSStefano Zampini     nedfieldlocal = NULL;
221213b8bfaSStefano Zampini     global        = PETSC_TRUE;
222213b8bfaSStefano Zampini   } else if (field == PETSC_DECIDE) {
223213b8bfaSStefano Zampini     PetscInt rst, ren, *idx;
224213b8bfaSStefano Zampini 
2259566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_leafdata, n));
2269566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
2279566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(pcbddc->discretegradient, &rst, &ren));
228213b8bfaSStefano Zampini     for (i = rst; i < ren; i++) {
229213b8bfaSStefano Zampini       PetscInt nc;
230213b8bfaSStefano Zampini 
2319566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
232213b8bfaSStefano Zampini       if (nc > 1) matis->sf_rootdata[i - rst] = 1;
2339566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
234213b8bfaSStefano Zampini     }
2359566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2369566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &idx));
2389371c9d4SSatish Balay     for (i = 0, ne = 0; i < n; i++)
2399371c9d4SSatish Balay       if (matis->sf_leafdata[i]) idx[ne++] = i;
2409566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, ne, idx, PETSC_OWN_POINTER, &nedfieldlocal));
241213b8bfaSStefano Zampini   } else {
242213b8bfaSStefano Zampini     SETERRQ(comm, PETSC_ERR_USER, "When multiple fields are present, the Nedelec field has to be specified");
243213b8bfaSStefano Zampini   }
244213b8bfaSStefano Zampini 
245213b8bfaSStefano Zampini   /* Sanity checks */
2467827d75bSBarry Smith   PetscCheck(order || conforming, comm, PETSC_ERR_SUP, "Variable order and non-conforming spaces are not supported at the same time");
24728b400f6SJacob Faibussowitsch   PetscCheck(!pcbddc->user_ChangeOfBasisMatrix, comm, PETSC_ERR_SUP, "Cannot generate Nedelec support with user defined change of basis");
24863a3b9bcSJacob 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);
249213b8bfaSStefano Zampini 
250213b8bfaSStefano Zampini   /* Just set primal dofs and return */
2511e0482f5SStefano Zampini   if (setprimal) {
252eee23b56SStefano Zampini     IS        enedfieldlocal;
253eee23b56SStefano Zampini     PetscInt *eidxs;
254eee23b56SStefano Zampini 
2559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &eidxs));
2569566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
257213b8bfaSStefano Zampini     if (nedfieldlocal) {
2589566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
259eee23b56SStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
2609371c9d4SSatish Balay         if (PetscRealPart(vals[idxs[i]]) > 2.) { eidxs[cum++] = idxs[i]; }
261eee23b56SStefano Zampini       }
2629566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
263213b8bfaSStefano Zampini     } else {
264213b8bfaSStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
2659371c9d4SSatish Balay         if (PetscRealPart(vals[i]) > 2.) { eidxs[cum++] = i; }
266213b8bfaSStefano Zampini       }
267213b8bfaSStefano Zampini     }
2689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2699566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, eidxs, PETSC_COPY_VALUES, &enedfieldlocal));
2709566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, enedfieldlocal));
2719566063dSJacob Faibussowitsch     PetscCall(PetscFree(eidxs));
2729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nedfieldlocal));
2739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&enedfieldlocal));
2741e0482f5SStefano Zampini     PetscFunctionReturn(0);
2751e0482f5SStefano Zampini   }
276a13144ffSStefano Zampini 
277213b8bfaSStefano Zampini   /* Compute some l2g maps */
278213b8bfaSStefano Zampini   if (nedfieldlocal) {
279c2151214SStefano Zampini     IS is;
280c2151214SStefano Zampini 
281c2151214SStefano Zampini     /* need to map from the local Nedelec field to local numbering */
2829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(nedfieldlocal, &fl2g));
2831e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering for the whole dofs*/
2849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(al2g, nedfieldlocal, &is));
2859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &al2g));
2861e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering (for Nedelec only) */
2871e0482f5SStefano Zampini     if (global) {
2889566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)al2g));
2891e0482f5SStefano Zampini       el2g = al2g;
2901e0482f5SStefano Zampini     } else {
2911e0482f5SStefano Zampini       IS gis;
2921e0482f5SStefano Zampini 
2939566063dSJacob Faibussowitsch       PetscCall(ISRenumber(is, NULL, NULL, &gis));
2949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(gis, &el2g));
2959566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&gis));
2961e0482f5SStefano Zampini     }
2979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
298c2151214SStefano Zampini   } else {
2991e0482f5SStefano Zampini     /* restore default */
3001e0482f5SStefano Zampini     pcbddc->nedfield = -1;
3011e0482f5SStefano Zampini     /* one ref for the destruction of al2g, one for el2g */
3029566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3039566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3041e0482f5SStefano Zampini     el2g = al2g;
305c2151214SStefano Zampini     fl2g = NULL;
306c2151214SStefano Zampini   }
307a13144ffSStefano Zampini 
308213b8bfaSStefano Zampini   /* Start communication to drop connections for interior edges (for cc analysis only) */
3099566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
3109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
311c2151214SStefano Zampini   if (nedfieldlocal) {
3129566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
313c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[idxs[i]] = 1;
3149566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
315c2151214SStefano Zampini   } else {
316c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[i] = 1;
317c2151214SStefano Zampini   }
3189566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
3199566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
320213b8bfaSStefano Zampini 
321213b8bfaSStefano Zampini   if (!singular) { /* drop connections with interior edges to avoid unneeded communications and memory movements */
3229566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(pcbddc->discretegradient, MAT_COPY_VALUES, &G));
3239566063dSJacob Faibussowitsch     PetscCall(MatSetOption(G, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3241e0482f5SStefano Zampini     if (global) {
3251e0482f5SStefano Zampini       PetscInt rst;
3261e0482f5SStefano Zampini 
3279566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(G, &rst, NULL));
328c2151214SStefano Zampini       for (i = 0, cum = 0; i < pc->pmat->rmap->n; i++) {
3299371c9d4SSatish Balay         if (matis->sf_rootdata[i] < 2) { matis->sf_rootdata[cum++] = i + rst; }
330c2151214SStefano Zampini       }
3319566063dSJacob Faibussowitsch       PetscCall(MatSetOption(G, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE));
3329566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, matis->sf_rootdata, 0., NULL, NULL));
3331e0482f5SStefano Zampini     } else {
3341e0482f5SStefano Zampini       PetscInt *tbz;
3351e0482f5SStefano Zampini 
3369566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ne, &tbz));
3379566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3389566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3399566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
3401e0482f5SStefano Zampini       for (i = 0, cum = 0; i < ne; i++)
3419371c9d4SSatish Balay         if (matis->sf_leafdata[idxs[i]] == 1) tbz[cum++] = i;
3429566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
3439566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(el2g, cum, tbz, tbz));
3449566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, tbz, 0., NULL, NULL));
3459566063dSJacob Faibussowitsch       PetscCall(PetscFree(tbz));
3461e0482f5SStefano Zampini     }
347213b8bfaSStefano Zampini   } else { /* we need the entire G to infer the nullspace */
3489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->discretegradient));
349213b8bfaSStefano Zampini     G = pcbddc->discretegradient;
350213b8bfaSStefano Zampini   }
351a13144ffSStefano Zampini 
352a13144ffSStefano Zampini   /* Extract subdomain relevant rows of G */
3539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(el2g, &idxs));
3549566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, ne, idxs, PETSC_USE_POINTER, &lned));
3559566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(G, lned, NULL, MAT_INITIAL_MATRIX, &lGall));
3569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(el2g, &idxs));
3579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&lned));
3589566063dSJacob Faibussowitsch   PetscCall(MatConvert(lGall, MATIS, MAT_INITIAL_MATRIX, &lGis));
3599566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGall));
3609566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(lGis, &lG));
361a13144ffSStefano Zampini 
362213b8bfaSStefano Zampini   /* SF for nodal dofs communications */
3639566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(G, NULL, &Lv));
3649566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(lGis, NULL, &vl2g));
3659566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)vl2g));
3669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(vl2g, &nv));
3679566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sfv));
3689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(vl2g, &idxs));
3699566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sfv, lGis->cmap, nv, NULL, PETSC_OWN_POINTER, idxs));
3709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(vl2g, &idxs));
371213b8bfaSStefano Zampini   i = singular ? 2 : 1;
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i * nv, &sfvleaves, i * Lv, &sfvroots));
373a13144ffSStefano Zampini 
3741e0482f5SStefano Zampini   /* Destroy temporary G created in MATIS format and modified G */
3759566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)lG));
3769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGis));
3779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&G));
378a13144ffSStefano Zampini 
379213b8bfaSStefano Zampini   if (print) {
3809566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "initial_lG"));
3819566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
382213b8bfaSStefano Zampini   }
383213b8bfaSStefano Zampini 
384213b8bfaSStefano Zampini   /* Save lG for values insertion in change of basis */
3859566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGinit));
3860569b399SStefano Zampini 
387a13144ffSStefano Zampini   /* Analyze the edge-nodes connections (duplicate lG) */
3889566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGe));
3899566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGe, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3909566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btv));
3919566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &bte));
3929566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btb));
3939566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btbd));
3949566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvcand));
395a13144ffSStefano Zampini   /* need to import the boundary specification to ensure the
396a13144ffSStefano Zampini      proper detection of coarse edges' endpoints */
397a13144ffSStefano Zampini   if (pcbddc->DirichletBoundariesLocal) {
398c2151214SStefano Zampini     IS is;
399c2151214SStefano Zampini 
400c2151214SStefano Zampini     if (fl2g) {
4019566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->DirichletBoundariesLocal, &is));
402c2151214SStefano Zampini     } else {
403c2151214SStefano Zampini       is = pcbddc->DirichletBoundariesLocal;
404c2151214SStefano Zampini     }
4059566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4069566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
407a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
408a13144ffSStefano Zampini       if (idxs[i] >= 0) {
4099566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btb, idxs[i]));
4109566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btbd, idxs[i]));
411a13144ffSStefano Zampini       }
412a13144ffSStefano Zampini     }
4139566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
414*48a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
415a13144ffSStefano Zampini   }
416a13144ffSStefano Zampini   if (pcbddc->NeumannBoundariesLocal) {
417c2151214SStefano Zampini     IS is;
418c2151214SStefano Zampini 
419c2151214SStefano Zampini     if (fl2g) {
4209566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->NeumannBoundariesLocal, &is));
421c2151214SStefano Zampini     } else {
422c2151214SStefano Zampini       is = pcbddc->NeumannBoundariesLocal;
423c2151214SStefano Zampini     }
4249566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4259566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
426a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
427*48a46eb9SPierre Jolivet       if (idxs[i] >= 0) PetscCall(PetscBTSet(btb, idxs[i]));
428a13144ffSStefano Zampini     }
4299566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
430*48a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
431c2151214SStefano Zampini   }
432c2151214SStefano Zampini 
433213b8bfaSStefano Zampini   /* Count neighs per dof */
4349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, &ecount, &eneighs));
4359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, &vcount, &vneighs));
436637e8532SStefano Zampini 
4377d871cd7SStefano Zampini   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
4387d871cd7SStefano Zampini      for proper detection of coarse edges' endpoints */
4399566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btee));
44062b0c6f7SStefano Zampini   for (i = 0; i < ne; i++) {
441*48a46eb9SPierre Jolivet     if ((ecount[i] > 2 && !PetscBTLookup(btbd, i)) || (ecount[i] == 2 && PetscBTLookup(btb, i))) PetscCall(PetscBTSet(btee, i));
44262b0c6f7SStefano Zampini   }
4439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ne, &marks));
44462b0c6f7SStefano Zampini   if (!conforming) {
4459566063dSJacob Faibussowitsch     PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
4469566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
44762b0c6f7SStefano Zampini   }
4489566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
4499566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGe, &vals));
45062b0c6f7SStefano Zampini   cum = 0;
451a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
452dec27d64SStefano Zampini     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
45362b0c6f7SStefano Zampini     if (!PetscBTLookup(btee, i)) {
454a13144ffSStefano Zampini       marks[cum++] = i;
455dec27d64SStefano Zampini       continue;
456dec27d64SStefano Zampini     }
457dec27d64SStefano Zampini     /* set badly connected edge dofs as primal */
45862b0c6f7SStefano Zampini     if (!conforming) {
45962b0c6f7SStefano Zampini       if (ii[i + 1] - ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
460a13144ffSStefano Zampini         marks[cum++] = i;
4619566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(bte, i));
462*48a46eb9SPierre Jolivet         for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
46362b0c6f7SStefano Zampini       } else {
46462b0c6f7SStefano Zampini         /* every edge dofs should be connected trough a certain number of nodal dofs
46562b0c6f7SStefano Zampini            to other edge dofs belonging to coarse edges
46662b0c6f7SStefano Zampini            - at most 2 endpoints
46762b0c6f7SStefano Zampini            - order-1 interior nodal dofs
46862b0c6f7SStefano Zampini            - no undefined nodal dofs (nconn < order)
46962b0c6f7SStefano Zampini         */
47062b0c6f7SStefano Zampini         PetscInt ends = 0, ints = 0, undef = 0;
47162b0c6f7SStefano Zampini         for (j = ii[i]; j < ii[i + 1]; j++) {
47262b0c6f7SStefano Zampini           PetscInt v     = jj[j], k;
47362b0c6f7SStefano Zampini           PetscInt nconn = iit[v + 1] - iit[v];
4749371c9d4SSatish Balay           for (k = iit[v]; k < iit[v + 1]; k++)
4759371c9d4SSatish Balay             if (!PetscBTLookup(btee, jjt[k])) nconn--;
47662b0c6f7SStefano Zampini           if (nconn > order) ends++;
47762b0c6f7SStefano Zampini           else if (nconn == order) ints++;
47862b0c6f7SStefano Zampini           else undef++;
47962b0c6f7SStefano Zampini         }
48062b0c6f7SStefano Zampini         if (undef || ends > 2 || ints != order - 1) {
48162b0c6f7SStefano Zampini           marks[cum++] = i;
4829566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(bte, i));
483*48a46eb9SPierre Jolivet           for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
48462b0c6f7SStefano Zampini         }
48562b0c6f7SStefano Zampini       }
486a13144ffSStefano Zampini     }
487dec27d64SStefano Zampini     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
488dec27d64SStefano Zampini     if (!order && ii[i + 1] != ii[i]) {
489dec27d64SStefano Zampini       PetscScalar val = 1. / (ii[i + 1] - ii[i] - 1);
490dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vals[j] = val;
491a13144ffSStefano Zampini     }
492dec27d64SStefano Zampini   }
4939566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btee));
4949566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGe, &vals));
4959566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
49662b0c6f7SStefano Zampini   if (!conforming) {
4979566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
4989566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lGt));
49962b0c6f7SStefano Zampini   }
5009566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGe, cum, marks, 0., NULL, NULL));
501637e8532SStefano Zampini 
502b03ebc13SStefano Zampini   /* identify splitpoints and corner candidates */
5039566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
504a13144ffSStefano Zampini   if (print) {
5059566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGe, "edgerestr_lG"));
5069566063dSJacob Faibussowitsch     PetscCall(MatView(lGe, NULL));
5079566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "edgerestr_lGt"));
5089566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
509a13144ffSStefano Zampini   }
5109566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5119566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGt, &vals));
512a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
513637e8532SStefano Zampini     PetscInt  ord = order, test = ii[i + 1] - ii[i], vc = vcount[i];
5147d871cd7SStefano Zampini     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
515b03ebc13SStefano Zampini     if (!order) { /* variable order */
516dec27d64SStefano Zampini       PetscReal vorder = 0.;
517dec27d64SStefano Zampini 
518dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vorder += PetscRealPart(vals[j]);
519dec27d64SStefano Zampini       test = PetscFloorReal(vorder + 10. * PETSC_SQRT_MACHINE_EPSILON);
52063a3b9bcSJacob Faibussowitsch       PetscCheck(vorder - test <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected value for vorder: %g (%" PetscInt_FMT ")", (double)vorder, test);
521dec27d64SStefano Zampini       ord = 1;
522dec27d64SStefano Zampini     }
5236bdcaf15SBarry Smith     PetscAssert(test % ord == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of edge dofs %" PetscInt_FMT " connected with nodal dof %" PetscInt_FMT " with order %" PetscInt_FMT, test, i, ord);
524637e8532SStefano Zampini     for (j = ii[i]; j < ii[i + 1] && sneighs; j++) {
5257d871cd7SStefano Zampini       if (PetscBTLookup(btbd, jj[j])) {
5267d871cd7SStefano Zampini         bdir = PETSC_TRUE;
5277d871cd7SStefano Zampini         break;
5287d871cd7SStefano Zampini       }
529637e8532SStefano Zampini       if (vc != ecount[jj[j]]) {
530637e8532SStefano Zampini         sneighs = PETSC_FALSE;
531637e8532SStefano Zampini       } else {
532637e8532SStefano Zampini         PetscInt k, *vn = vneighs[i], *en = eneighs[jj[j]];
533637e8532SStefano Zampini         for (k = 0; k < vc; k++) {
534637e8532SStefano Zampini           if (vn[k] != en[k]) {
535637e8532SStefano Zampini             sneighs = PETSC_FALSE;
536637e8532SStefano Zampini             break;
537637e8532SStefano Zampini           }
538637e8532SStefano Zampini         }
539637e8532SStefano Zampini       }
540637e8532SStefano Zampini     }
5417d871cd7SStefano Zampini     if (!sneighs || test >= 3 * ord || bdir) { /* splitpoints */
54263a3b9bcSJacob Faibussowitsch       if (print) PetscPrintf(PETSC_COMM_SELF, "SPLITPOINT %" PetscInt_FMT " (%s %s %s)\n", i, PetscBools[!sneighs], PetscBools[test >= 3 * ord], PetscBools[bdir]);
5439566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
544dec27d64SStefano Zampini     } else if (test == ord) {
545b03ebc13SStefano Zampini       if (order == 1 || (!order && ii[i + 1] - ii[i] == 1)) {
54663a3b9bcSJacob Faibussowitsch         if (print) PetscPrintf(PETSC_COMM_SELF, "ENDPOINT %" PetscInt_FMT "\n", i);
5479566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btv, i));
548a13144ffSStefano Zampini       } else {
54963a3b9bcSJacob Faibussowitsch         if (print) PetscPrintf(PETSC_COMM_SELF, "CORNER CANDIDATE %" PetscInt_FMT "\n", i);
5509566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btvcand, i));
551a13144ffSStefano Zampini       }
552a13144ffSStefano Zampini     }
553a13144ffSStefano Zampini   }
5549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(el2g, NULL, &ecount, &eneighs));
5559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(vl2g, NULL, &vcount, &vneighs));
5569566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btbd));
557b03ebc13SStefano Zampini 
558b03ebc13SStefano Zampini   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
559b03ebc13SStefano Zampini   if (order != 1) {
560b03ebc13SStefano Zampini     if (print) PetscPrintf(PETSC_COMM_SELF, "INSPECTING CANDIDATES\n");
5619566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
562b03ebc13SStefano Zampini     for (i = 0; i < nv; i++) {
563b03ebc13SStefano Zampini       if (PetscBTLookup(btvcand, i)) {
564b03ebc13SStefano Zampini         PetscBool found = PETSC_FALSE;
565b03ebc13SStefano Zampini         for (j = ii[i]; j < ii[i + 1] && !found; j++) {
566b03ebc13SStefano Zampini           PetscInt k, e = jj[j];
567b03ebc13SStefano Zampini           if (PetscBTLookup(bte, e)) continue;
568b03ebc13SStefano Zampini           for (k = iit[e]; k < iit[e + 1]; k++) {
569b03ebc13SStefano Zampini             PetscInt v = jjt[k];
570b03ebc13SStefano Zampini             if (v != i && PetscBTLookup(btvcand, v)) {
571b03ebc13SStefano Zampini               found = PETSC_TRUE;
572b03ebc13SStefano Zampini               break;
573b03ebc13SStefano Zampini             }
574b03ebc13SStefano Zampini           }
575b03ebc13SStefano Zampini         }
576b03ebc13SStefano Zampini         if (!found) {
57763a3b9bcSJacob Faibussowitsch           if (print) PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " CLEARED\n", i);
5789566063dSJacob Faibussowitsch           PetscCall(PetscBTClear(btvcand, i));
579b03ebc13SStefano Zampini         } else {
58063a3b9bcSJacob Faibussowitsch           if (print) PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " ACCEPTED\n", i);
581b03ebc13SStefano Zampini         }
582b03ebc13SStefano Zampini       }
583b03ebc13SStefano Zampini     }
5849566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
585b03ebc13SStefano Zampini   }
5869566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGt, &vals));
5879566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGe));
589a13144ffSStefano Zampini 
590a13144ffSStefano Zampini   /* Get the local G^T explicitly */
5919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
5929566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
5939566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGt, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
594a13144ffSStefano Zampini 
5954e64d54eSstefano_zampini   /* Mark interior nodal dofs */
5969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
5979566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvi));
598a13144ffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
599*48a46eb9SPierre Jolivet     for (j = 0; j < n_shared[i]; j++) PetscCall(PetscBTSet(btvi, shared[i][j]));
600a13144ffSStefano Zampini   }
6019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
602a13144ffSStefano Zampini 
603a13144ffSStefano Zampini   /* communicate corners and splitpoints */
6049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nv, &vmarks));
6059566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvleaves, nv));
6069566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvroots, Lv));
6079371c9d4SSatish Balay   for (i = 0; i < nv; i++)
6089371c9d4SSatish Balay     if (PetscUnlikely(PetscBTLookup(btv, i))) sfvleaves[i] = 1;
609a13144ffSStefano Zampini 
610a13144ffSStefano Zampini   if (print) {
611a13144ffSStefano Zampini     IS tbz;
612a13144ffSStefano Zampini 
613a13144ffSStefano Zampini     cum = 0;
614a13144ffSStefano Zampini     for (i = 0; i < nv; i++)
6159371c9d4SSatish Balay       if (sfvleaves[i]) vmarks[cum++] = i;
616a13144ffSStefano Zampini 
6179566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6189566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_local"));
6199566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6209566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
621a13144ffSStefano Zampini   }
622a13144ffSStefano Zampini 
6239566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6249566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6259566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
6269566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
627a13144ffSStefano Zampini 
6284e64d54eSstefano_zampini   /* Zero rows of lGt corresponding to identified corners
6294e64d54eSstefano_zampini      and interior nodal dofs */
630a13144ffSStefano Zampini   cum = 0;
631a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
632a13144ffSStefano Zampini     if (sfvleaves[i]) {
633a13144ffSStefano Zampini       vmarks[cum++] = i;
6349566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
635a13144ffSStefano Zampini     }
6364e64d54eSstefano_zampini     if (!PetscBTLookup(btvi, i)) vmarks[cum++] = i;
637a13144ffSStefano Zampini   }
6389566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvi));
639a13144ffSStefano Zampini   if (print) {
640a13144ffSStefano Zampini     IS tbz;
641a13144ffSStefano Zampini 
6429566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6439566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_with_interior"));
6449566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6459566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
646a13144ffSStefano Zampini   }
6479566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGt, cum, vmarks, 0., NULL, NULL));
6489566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmarks));
6499566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfv));
6509566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sfvleaves, sfvroots));
651a13144ffSStefano Zampini 
652a13144ffSStefano Zampini   /* Recompute G */
6539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
6549566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGt, MAT_INITIAL_MATRIX, &lG));
655a13144ffSStefano Zampini   if (print) {
6569566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "used_lG"));
6579566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
6589566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "used_lGt"));
6599566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
660a13144ffSStefano Zampini   }
661a13144ffSStefano Zampini 
662a13144ffSStefano Zampini   /* Get primal dofs (if any) */
663a13144ffSStefano Zampini   cum = 0;
664a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
665a13144ffSStefano Zampini     if (PetscUnlikely(PetscBTLookup(bte, i))) marks[cum++] = i;
666a13144ffSStefano Zampini   }
6671baa6e33SBarry Smith   if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, marks, marks));
6689566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, cum, marks, PETSC_COPY_VALUES, &primals));
669a13144ffSStefano Zampini   if (print) {
6709566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "prescribed_primal_dofs"));
6719566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
672a13144ffSStefano Zampini   }
6739566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bte));
674c2151214SStefano Zampini   /* TODO: what if the user passed in some of them ?  */
6759566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
6769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&primals));
677a13144ffSStefano Zampini 
678a13144ffSStefano Zampini   /* Compute edge connectivity */
6799566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lG, "econn_"));
6804222ddf1SHong Zhang 
6814222ddf1SHong Zhang   /* Symbolic conn = lG*lGt */
6829566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(lG, lGt, NULL, &conn));
6839566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(conn, MATPRODUCT_AB));
6849566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(conn, "default"));
6859566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(conn, PETSC_DEFAULT));
6869566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)conn, "econn_"));
6879566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(conn));
6889566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(conn));
6894222ddf1SHong Zhang 
6909566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
691c2151214SStefano Zampini   if (fl2g) {
692c2151214SStefano Zampini     PetscBT   btf;
693c2151214SStefano Zampini     PetscInt *iia, *jja, *iiu, *jju;
694c2151214SStefano Zampini     PetscBool rest = PETSC_FALSE, free = PETSC_FALSE;
695c2151214SStefano Zampini 
696c2151214SStefano Zampini     /* create CSR for all local dofs */
6979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &iia));
698c2151214SStefano Zampini     if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
69963a3b9bcSJacob 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);
700c2151214SStefano Zampini       iiu = pcbddc->mat_graph->xadj;
701c2151214SStefano Zampini       jju = pcbddc->mat_graph->adjncy;
702c2151214SStefano Zampini     } else if (pcbddc->use_local_adj) {
703c2151214SStefano Zampini       rest = PETSC_TRUE;
7049566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
705c2151214SStefano Zampini     } else {
706c2151214SStefano Zampini       free = PETSC_TRUE;
7079566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n + 1, &iiu, n, &jju));
708c2151214SStefano Zampini       iiu[0] = 0;
709c2151214SStefano Zampini       for (i = 0; i < n; i++) {
710c2151214SStefano Zampini         iiu[i + 1] = i + 1;
711c2151214SStefano Zampini         jju[i]     = -1;
712d904f53bSStefano Zampini       }
713c2151214SStefano Zampini     }
714c2151214SStefano Zampini 
715c2151214SStefano Zampini     /* import sizes of CSR */
716c2151214SStefano Zampini     iia[0] = 0;
717c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] = iiu[i + 1] - iiu[i];
718c2151214SStefano Zampini 
719c2151214SStefano Zampini     /* overwrite entries corresponding to the Nedelec field */
7209566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(n, &btf));
7219566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
722c2151214SStefano Zampini     for (i = 0; i < ne; i++) {
7239566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btf, idxs[i]));
724c2151214SStefano Zampini       iia[idxs[i] + 1] = ii[i + 1] - ii[i];
725c2151214SStefano Zampini     }
726c2151214SStefano Zampini 
727c2151214SStefano Zampini     /* iia in CSR */
728c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] += iia[i];
729c2151214SStefano Zampini 
730c2151214SStefano Zampini     /* jja in CSR */
7319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(iia[n], &jja));
732c2151214SStefano Zampini     for (i = 0; i < n; i++)
733c2151214SStefano Zampini       if (!PetscBTLookup(btf, i))
7349371c9d4SSatish Balay         for (j = 0; j < iiu[i + 1] - iiu[i]; j++) jja[iia[i] + j] = jju[iiu[i] + j];
735c2151214SStefano Zampini 
736c2151214SStefano Zampini     /* map edge dofs connectivity */
7371e0482f5SStefano Zampini     if (jj) {
7389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, ii[ne], jj, (PetscInt *)jj));
739c2151214SStefano Zampini       for (i = 0; i < ne; i++) {
740c2151214SStefano Zampini         PetscInt e = idxs[i];
741c2151214SStefano Zampini         for (j = 0; j < ii[i + 1] - ii[i]; j++) jja[iia[e] + j] = jj[ii[i] + j];
742c2151214SStefano Zampini       }
7431e0482f5SStefano Zampini     }
7449566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
7459566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, iia, jja, PETSC_OWN_POINTER));
746*48a46eb9SPierre Jolivet     if (rest) PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
7471baa6e33SBarry Smith     if (free) PetscCall(PetscFree2(iiu, jju));
7489566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&btf));
749c2151214SStefano Zampini   } else {
7509566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, ii, jj, PETSC_USE_POINTER));
751c2151214SStefano Zampini   }
752c2151214SStefano Zampini 
753a13144ffSStefano Zampini   /* Analyze interface for edge dofs */
7549566063dSJacob Faibussowitsch   PetscCall(PCBDDCAnalyzeInterface(pc));
755213b8bfaSStefano Zampini   pcbddc->mat_graph->twodim = PETSC_FALSE;
756a13144ffSStefano Zampini 
757a13144ffSStefano Zampini   /* Get coarse edges in the edge space */
7589566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
7599566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
760a13144ffSStefano Zampini 
761c2151214SStefano Zampini   if (fl2g) {
7629566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
7639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee, &eedges));
764*48a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
765c2151214SStefano Zampini   } else {
766c2151214SStefano Zampini     eedges  = alleedges;
767c2151214SStefano Zampini     primals = allprimals;
768c2151214SStefano Zampini   }
769c2151214SStefano Zampini 
770a13144ffSStefano Zampini   /* Mark fine edge dofs with their coarse edge id */
7719566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(marks, ne));
7729566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
7739566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
774c2151214SStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = nee + 1;
7759566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
776c2151214SStefano Zampini   if (print) {
7779566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs"));
7789566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
779c2151214SStefano Zampini   }
780c2151214SStefano Zampini 
781c2151214SStefano Zampini   maxsize = 0;
782a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
783a13144ffSStefano Zampini     PetscInt size, mark = i + 1;
784a13144ffSStefano Zampini 
7859566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
7869566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
787a13144ffSStefano Zampini     for (j = 0; j < size; j++) marks[idxs[j]] = mark;
7889566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
789a13144ffSStefano Zampini     maxsize = PetscMax(maxsize, size);
790a13144ffSStefano Zampini   }
791a13144ffSStefano Zampini 
792a13144ffSStefano Zampini   /* Find coarse edge endpoints */
7939566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
7949566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
795a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
796a13144ffSStefano Zampini     PetscInt mark = i + 1, size;
797a13144ffSStefano Zampini 
7989566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
7991e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
80063a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8019566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
802a13144ffSStefano Zampini     if (print) {
80363a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINTS ANALYSIS EDGE %" PetscInt_FMT "\n", i));
8049566063dSJacob Faibussowitsch       PetscCall(ISView(eedges[i], NULL));
805a13144ffSStefano Zampini     }
806a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
807a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
80863a3b9bcSJacob Faibussowitsch       if (print) PetscPrintf(PETSC_COMM_SELF, "  idx %" PetscInt_FMT "\n", ee);
809a13144ffSStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
81063a3b9bcSJacob Faibussowitsch         if (print) PetscPrintf(PETSC_COMM_SELF, "    inspect %" PetscInt_FMT "\n", jj[k]);
811a13144ffSStefano Zampini         if (PetscBTLookup(btv, jj[k])) {
81263a3b9bcSJacob Faibussowitsch           if (print) PetscPrintf(PETSC_COMM_SELF, "      corner found (already set) %" PetscInt_FMT "\n", jj[k]);
813a13144ffSStefano Zampini         } else if (PetscBTLookup(btvcand, jj[k])) { /* is it ok? */
814a13144ffSStefano Zampini           PetscInt  k2;
815a13144ffSStefano Zampini           PetscBool corner = PETSC_FALSE;
816a13144ffSStefano Zampini           for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) {
81763a3b9bcSJacob Faibussowitsch             if (print) 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]));
818c2151214SStefano Zampini             /* it's a corner if either is connected with an edge dof belonging to a different cc or
819c2151214SStefano Zampini                if the edge dof lie on the natural part of the boundary */
820c2151214SStefano Zampini             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb, jjt[k2]))) {
821a13144ffSStefano Zampini               corner = PETSC_TRUE;
822a13144ffSStefano Zampini               break;
823a13144ffSStefano Zampini             }
824a13144ffSStefano Zampini           }
825a13144ffSStefano Zampini           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
82663a3b9bcSJacob Faibussowitsch             if (print) PetscPrintf(PETSC_COMM_SELF, "        corner found %" PetscInt_FMT "\n", jj[k]);
8279566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
828a13144ffSStefano Zampini           } else {
829a13144ffSStefano Zampini             if (print) PetscPrintf(PETSC_COMM_SELF, "        no corners found\n");
830a13144ffSStefano Zampini           }
831a13144ffSStefano Zampini         }
832a13144ffSStefano Zampini       }
833a13144ffSStefano Zampini     }
8349566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
835a13144ffSStefano Zampini   }
8369566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
8379566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8389566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btb));
839a13144ffSStefano Zampini 
840a13144ffSStefano Zampini   /* Reset marked primal dofs */
8419566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
8429566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
843a13144ffSStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = 0;
8449566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
845a13144ffSStefano Zampini 
8460569b399SStefano Zampini   /* Now use the initial lG */
8479566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
8489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
8490569b399SStefano Zampini   lG = lGinit;
8509566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
8510569b399SStefano Zampini 
852a13144ffSStefano Zampini   /* Compute extended cols indices */
8539566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvc));
8549566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nee, &bter));
8559566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8569566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lG, &i));
857a13144ffSStefano Zampini   i *= maxsize;
8589566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extcols));
8599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i, &extrow, i, &gidxs));
860a13144ffSStefano Zampini   eerr = PETSC_FALSE;
861a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
862b03ebc13SStefano Zampini     PetscInt size, found = 0;
863a13144ffSStefano Zampini 
864a13144ffSStefano Zampini     cum = 0;
8659566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
8661e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
86763a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
8699566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
870a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
871a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
872b03ebc13SStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
873b03ebc13SStefano Zampini         PetscInt vv = jj[k];
874b03ebc13SStefano Zampini         if (!PetscBTLookup(btv, vv)) extrow[cum++] = vv;
875b03ebc13SStefano Zampini         else if (!PetscBTLookupSet(btvc, vv)) found++;
876b03ebc13SStefano Zampini       }
877a13144ffSStefano Zampini     }
8789566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
8799566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
8809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
8819566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
8829566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
883a13144ffSStefano Zampini     /* it may happen that endpoints are not defined at this point
884a13144ffSStefano Zampini        if it is the case, mark this edge for a second pass */
885b03ebc13SStefano Zampini     if (cum != size - 1 || found != 2) {
8869566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(bter, i));
887a13144ffSStefano Zampini       if (print) {
8889566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge"));
8899566063dSJacob Faibussowitsch         PetscCall(ISView(eedges[i], NULL));
8909566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol"));
8919566063dSJacob Faibussowitsch         PetscCall(ISView(extcols[i], NULL));
892a13144ffSStefano Zampini       }
893a13144ffSStefano Zampini       eerr = PETSC_TRUE;
894a13144ffSStefano Zampini     }
895a13144ffSStefano Zampini   }
89628b400f6SJacob Faibussowitsch   /* PetscCheck(!eerr,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
8971c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&eerr, &done, 1, MPIU_BOOL, MPI_LOR, comm));
898a13144ffSStefano Zampini   if (done) {
899a13144ffSStefano Zampini     PetscInt *newprimals;
900a13144ffSStefano Zampini 
9019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &newprimals));
9029566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(primals, &cum));
9039566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(primals, &idxs));
9049566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(newprimals, idxs, cum));
9059566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(primals, &idxs));
9069566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
90763a3b9bcSJacob Faibussowitsch     if (print) PetscPrintf(PETSC_COMM_SELF, "DOING SECOND PASS (eerr %s)\n", PetscBools[eerr]);
908a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
909b03ebc13SStefano Zampini       PetscBool has_candidates = PETSC_FALSE;
910b03ebc13SStefano Zampini       if (PetscBTLookup(bter, i)) {
911a13144ffSStefano Zampini         PetscInt size, mark = i + 1;
912a13144ffSStefano Zampini 
9139566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(eedges[i], &size));
9149566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(eedges[i], &idxs));
915c2151214SStefano Zampini         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
916a13144ffSStefano Zampini         for (j = 0; j < size; j++) {
917a13144ffSStefano Zampini           PetscInt k, ee = idxs[j];
91863a3b9bcSJacob Faibussowitsch           if (print) PetscPrintf(PETSC_COMM_SELF, "Inspecting edge dof %" PetscInt_FMT " [%" PetscInt_FMT " %" PetscInt_FMT ")\n", ee, ii[ee], ii[ee + 1]);
919a13144ffSStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
920a13144ffSStefano Zampini             /* set all candidates located on the edge as corners */
921a13144ffSStefano Zampini             if (PetscBTLookup(btvcand, jj[k])) {
922a13144ffSStefano Zampini               PetscInt k2, vv = jj[k];
923b03ebc13SStefano Zampini               has_candidates = PETSC_TRUE;
92463a3b9bcSJacob Faibussowitsch               if (print) PetscPrintf(PETSC_COMM_SELF, "  Candidate set to vertex %" PetscInt_FMT "\n", vv);
9259566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(btv, vv));
926a13144ffSStefano Zampini               /* set all edge dofs connected to candidate as primals */
927a13144ffSStefano Zampini               for (k2 = iit[vv]; k2 < iit[vv + 1]; k2++) {
928a13144ffSStefano Zampini                 if (marks[jjt[k2]] == mark) {
929a13144ffSStefano Zampini                   PetscInt k3, ee2 = jjt[k2];
93063a3b9bcSJacob Faibussowitsch                   if (print) PetscPrintf(PETSC_COMM_SELF, "    Connected edge dof set to primal %" PetscInt_FMT "\n", ee2);
931a13144ffSStefano Zampini                   newprimals[cum++] = ee2;
932a13144ffSStefano Zampini                   /* finally set the new corners */
933a13144ffSStefano Zampini                   for (k3 = ii[ee2]; k3 < ii[ee2 + 1]; k3++) {
93463a3b9bcSJacob Faibussowitsch                     if (print) PetscPrintf(PETSC_COMM_SELF, "      Connected nodal dof set to vertex %" PetscInt_FMT "\n", jj[k3]);
9359566063dSJacob Faibussowitsch                     PetscCall(PetscBTSet(btv, jj[k3]));
936a13144ffSStefano Zampini                   }
937a13144ffSStefano Zampini                 }
938a13144ffSStefano Zampini               }
939b03ebc13SStefano Zampini             } else {
94063a3b9bcSJacob Faibussowitsch               if (print) PetscPrintf(PETSC_COMM_SELF, "  Not a candidate vertex %" PetscInt_FMT "\n", jj[k]);
941a13144ffSStefano Zampini             }
942a13144ffSStefano Zampini           }
943a13144ffSStefano Zampini         }
944b03ebc13SStefano Zampini         if (!has_candidates) { /* circular edge */
945b03ebc13SStefano Zampini           PetscInt k, ee = idxs[0], *tmarks;
946b03ebc13SStefano Zampini 
9479566063dSJacob Faibussowitsch           PetscCall(PetscCalloc1(ne, &tmarks));
94863a3b9bcSJacob Faibussowitsch           if (print) PetscPrintf(PETSC_COMM_SELF, "  Circular edge %" PetscInt_FMT "\n", i);
949b03ebc13SStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
950b03ebc13SStefano Zampini             PetscInt k2;
95163a3b9bcSJacob Faibussowitsch             if (print) PetscPrintf(PETSC_COMM_SELF, "    Set to corner %" PetscInt_FMT "\n", jj[k]);
9529566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
953b03ebc13SStefano Zampini             for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) tmarks[jjt[k2]]++;
954b03ebc13SStefano Zampini           }
955b03ebc13SStefano Zampini           for (j = 0; j < size; j++) {
956b03ebc13SStefano Zampini             if (tmarks[idxs[j]] > 1) {
95763a3b9bcSJacob Faibussowitsch               if (print) PetscPrintf(PETSC_COMM_SELF, "  Edge dof set to primal %" PetscInt_FMT "\n", idxs[j]);
958b03ebc13SStefano Zampini               newprimals[cum++] = idxs[j];
959b03ebc13SStefano Zampini             }
960b03ebc13SStefano Zampini           }
9619566063dSJacob Faibussowitsch           PetscCall(PetscFree(tmarks));
962b03ebc13SStefano Zampini         }
9639566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(eedges[i], &idxs));
964a13144ffSStefano Zampini       }
9659566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&extcols[i]));
966a13144ffSStefano Zampini     }
9679566063dSJacob Faibussowitsch     PetscCall(PetscFree(extcols));
9689566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9699566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, newprimals));
970c2151214SStefano Zampini     if (fl2g) {
9719566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, newprimals, newprimals));
9729566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&primals));
973*48a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
9749566063dSJacob Faibussowitsch       PetscCall(PetscFree(eedges));
975c2151214SStefano Zampini     }
9769566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
9779566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, newprimals, PETSC_COPY_VALUES, &primals));
9789566063dSJacob Faibussowitsch     PetscCall(PetscFree(newprimals));
9799566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
9809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
9819566063dSJacob Faibussowitsch     PetscCall(PCBDDCAnalyzeInterface(pc));
982213b8bfaSStefano Zampini     pcbddc->mat_graph->twodim = PETSC_FALSE;
9839566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
984c2151214SStefano Zampini     if (fl2g) {
9859566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
9869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nee, &eedges));
987*48a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
988c2151214SStefano Zampini     } else {
989c2151214SStefano Zampini       eedges  = alleedges;
990c2151214SStefano Zampini       primals = allprimals;
991c2151214SStefano Zampini     }
9929566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nee, &extcols));
993a13144ffSStefano Zampini 
994a13144ffSStefano Zampini     /* Mark again */
9959566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(marks, ne));
996a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
997a13144ffSStefano Zampini       PetscInt size, mark = i + 1;
998a13144ffSStefano Zampini 
9999566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10009566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1001a13144ffSStefano Zampini       for (j = 0; j < size; j++) marks[idxs[j]] = mark;
10029566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1003a13144ffSStefano Zampini     }
1004a13144ffSStefano Zampini     if (print) {
10059566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs_secondpass"));
10069566063dSJacob Faibussowitsch       PetscCall(ISView(primals, NULL));
1007a13144ffSStefano Zampini     }
1008a13144ffSStefano Zampini 
1009a13144ffSStefano Zampini     /* Recompute extended cols */
1010a13144ffSStefano Zampini     eerr = PETSC_FALSE;
1011a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1012a13144ffSStefano Zampini       PetscInt size;
1013a13144ffSStefano Zampini 
1014a13144ffSStefano Zampini       cum = 0;
10159566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10161e0482f5SStefano Zampini       if (!size && nedfieldlocal) continue;
101763a3b9bcSJacob Faibussowitsch       PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10189566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1019a13144ffSStefano Zampini       for (j = 0; j < size; j++) {
1020a13144ffSStefano Zampini         PetscInt k, ee = idxs[j];
10219371c9d4SSatish Balay         for (k = ii[ee]; k < ii[ee + 1]; k++)
10229371c9d4SSatish Balay           if (!PetscBTLookup(btv, jj[k])) extrow[cum++] = jj[k];
1023a13144ffSStefano Zampini       }
10249566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
10259566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
10269566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
10279566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
10289566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1029a13144ffSStefano Zampini       if (cum != size - 1) {
1030a13144ffSStefano Zampini         if (print) {
10319566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge_secondpass"));
10329566063dSJacob Faibussowitsch           PetscCall(ISView(eedges[i], NULL));
10339566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol_secondpass"));
10349566063dSJacob Faibussowitsch           PetscCall(ISView(extcols[i], NULL));
1035a13144ffSStefano Zampini         }
1036a13144ffSStefano Zampini         eerr = PETSC_TRUE;
1037a13144ffSStefano Zampini       }
1038a13144ffSStefano Zampini     }
1039a13144ffSStefano Zampini   }
10409566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10419566063dSJacob Faibussowitsch   PetscCall(PetscFree2(extrow, gidxs));
10429566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bter));
10439566063dSJacob Faibussowitsch   if (print) PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, 5, PETSC_VIEWER_STDOUT_SELF));
1044a13144ffSStefano Zampini   /* an error should not occur at this point */
104528b400f6SJacob Faibussowitsch   PetscCheck(!eerr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1046a13144ffSStefano Zampini 
10474e64d54eSstefano_zampini   /* Check the number of endpoints */
10489566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * nee, &corners));
10509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &cedges));
10514e64d54eSstefano_zampini   for (i = 0; i < nee; i++) {
1052b03ebc13SStefano Zampini     PetscInt size, found = 0, gc[2];
10534e64d54eSstefano_zampini 
1054b03ebc13SStefano Zampini     /* init with defaults */
1055b03ebc13SStefano Zampini     cedges[i] = corners[i * 2] = corners[i * 2 + 1] = -1;
10569566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
10571e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
105863a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10599566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
10609566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
10614e64d54eSstefano_zampini     for (j = 0; j < size; j++) {
10624e64d54eSstefano_zampini       PetscInt k, ee = idxs[j];
10634e64d54eSstefano_zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
10644e64d54eSstefano_zampini         PetscInt vv = jj[k];
10654e64d54eSstefano_zampini         if (PetscBTLookup(btv, vv) && !PetscBTLookupSet(btvc, vv)) {
106663a3b9bcSJacob Faibussowitsch           PetscCheck(found != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more then two corners for edge %" PetscInt_FMT, i);
1067b03ebc13SStefano Zampini           corners[i * 2 + found++] = vv;
10684e64d54eSstefano_zampini         }
10694e64d54eSstefano_zampini       }
10704e64d54eSstefano_zampini     }
1071b03ebc13SStefano Zampini     if (found != 2) {
1072b03ebc13SStefano Zampini       PetscInt e;
1073b03ebc13SStefano Zampini       if (fl2g) {
10749566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, 1, idxs, &e));
1075b03ebc13SStefano Zampini       } else {
1076b03ebc13SStefano Zampini         e = idxs[0];
1077b03ebc13SStefano Zampini       }
107863a3b9bcSJacob 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]);
1079b03ebc13SStefano Zampini     }
1080eee23b56SStefano Zampini 
1081eee23b56SStefano Zampini     /* get primal dof index on this coarse edge */
10829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, 2, corners + 2 * i, gc));
1083b03ebc13SStefano Zampini     if (gc[0] > gc[1]) {
1084b03ebc13SStefano Zampini       PetscInt swap      = corners[2 * i];
1085b03ebc13SStefano Zampini       corners[2 * i]     = corners[2 * i + 1];
1086b03ebc13SStefano Zampini       corners[2 * i + 1] = swap;
1087b03ebc13SStefano Zampini     }
1088eee23b56SStefano Zampini     cedges[i] = idxs[size - 1];
10899566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
109063a3b9bcSJacob Faibussowitsch     if (print) 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]);
10914e64d54eSstefano_zampini   }
10929566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10939566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvc));
10944e64d54eSstefano_zampini 
109576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
1096a13144ffSStefano Zampini     /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1097a13144ffSStefano Zampini      not interfere with neighbouring coarse edges */
10989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee + 1, &emarks));
10999566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
1100a13144ffSStefano Zampini     for (i = 0; i < nv; i++) {
1101a13144ffSStefano Zampini       PetscInt emax = 0, eemax = 0;
1102a13144ffSStefano Zampini 
1103a13144ffSStefano Zampini       if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
11049566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(emarks, nee + 1));
1105a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) emarks[marks[jj[j]]]++;
1106a13144ffSStefano Zampini       for (j = 1; j < nee + 1; j++) {
1107a13144ffSStefano Zampini         if (emax < emarks[j]) {
1108a13144ffSStefano Zampini           emax  = emarks[j];
1109a13144ffSStefano Zampini           eemax = j;
1110a13144ffSStefano Zampini         }
1111a13144ffSStefano Zampini       }
1112a13144ffSStefano Zampini       /* not relevant for edges */
1113a13144ffSStefano Zampini       if (!eemax) continue;
1114a13144ffSStefano Zampini 
1115a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
11167a46b595SBarry 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]);
1117a13144ffSStefano Zampini       }
1118a13144ffSStefano Zampini     }
11199566063dSJacob Faibussowitsch     PetscCall(PetscFree(emarks));
11209566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
112176bd3646SJed Brown   }
1122a13144ffSStefano Zampini 
1123a13144ffSStefano Zampini   /* Compute extended rows indices for edge blocks of the change of basis */
11249566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11259566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lGt, &extmem));
1126a13144ffSStefano Zampini   extmem *= maxsize;
11279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(extmem * nee, &extrow));
11289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &extrows));
11299566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extrowcum));
1130a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
1131a13144ffSStefano Zampini     PetscInt mark = 0, size, start;
1132213b8bfaSStefano Zampini 
1133a13144ffSStefano Zampini     if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
1134a13144ffSStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++)
11359371c9d4SSatish Balay       if (marks[jj[j]] && !mark) mark = marks[jj[j]];
1136a13144ffSStefano Zampini 
1137a13144ffSStefano Zampini     /* not relevant */
1138a13144ffSStefano Zampini     if (!mark) continue;
1139a13144ffSStefano Zampini 
1140a13144ffSStefano Zampini     /* import extended row */
1141a13144ffSStefano Zampini     mark--;
1142a13144ffSStefano Zampini     start = mark * extmem + extrowcum[mark];
1143a13144ffSStefano Zampini     size  = ii[i + 1] - ii[i];
114463a3b9bcSJacob Faibussowitsch     PetscCheck(extrowcum[mark] + size <= extmem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not enough memory allocated %" PetscInt_FMT " > %" PetscInt_FMT, extrowcum[mark] + size, extmem);
11459566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(extrow + start, jj + ii[i], size));
1146a13144ffSStefano Zampini     extrowcum[mark] += size;
1147a13144ffSStefano Zampini   }
11489566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
11509566063dSJacob Faibussowitsch   PetscCall(PetscFree(marks));
1151213b8bfaSStefano Zampini 
1152213b8bfaSStefano Zampini   /* Compress extrows */
1153a13144ffSStefano Zampini   cum = 0;
1154a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1155a13144ffSStefano Zampini     PetscInt size = extrowcum[i], *start = extrow + i * extmem;
11569566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&size, start));
11579566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, start, PETSC_USE_POINTER, &extrows[i]));
1158a13144ffSStefano Zampini     cum = PetscMax(cum, size);
1159a13144ffSStefano Zampini   }
11609566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrowcum));
11619566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btv));
11629566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvcand));
1163a13144ffSStefano Zampini 
1164a13144ffSStefano Zampini   /* Workspace for lapack inner calls and VecSetValues */
11659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2((5 + cum + maxsize) * maxsize, &work, maxsize, &rwork));
1166a13144ffSStefano Zampini 
1167a13144ffSStefano Zampini   /* Create change of basis matrix (preallocation can be improved) */
11689566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
1169d0609cedSBarry Smith   PetscCall(MatSetSizes(T, pc->pmat->rmap->n, pc->pmat->rmap->n, pc->pmat->rmap->N, pc->pmat->rmap->N));
11709566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
11719566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(T, 10, NULL));
11729566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(T, 10, NULL, 10, NULL));
11739566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
11749566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
11759566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
11769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1177a13144ffSStefano Zampini 
1178a13144ffSStefano Zampini   /* Defaults to identity */
11799566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &tvec, NULL));
11809566063dSJacob Faibussowitsch   PetscCall(VecSet(tvec, 1.0));
11819566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(T, tvec, INSERT_VALUES));
11829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&tvec));
1183a13144ffSStefano Zampini 
11841e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
11859566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
11869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
11871e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
11881e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
11891e0482f5SStefano Zampini     IS                     wis, gwis;
11901e0482f5SStefano Zampini     PetscInt               cnv, cne;
11911e0482f5SStefano Zampini 
11929566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
11931e0482f5SStefano Zampini     if (fl2g) {
11949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
11951e0482f5SStefano Zampini     } else {
11969566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
11971e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
11981e0482f5SStefano Zampini     }
11999566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
12009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12019566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
12029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
12039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12051e0482f5SStefano Zampini 
12069566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
12079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
12089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12099566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
12109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
12119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12129566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12131e0482f5SStefano Zampini 
12149566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
12159566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
12169566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
12179566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
12189566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
12199566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
12209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
12219566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
12221e0482f5SStefano Zampini   }
12239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
12241e0482f5SStefano Zampini 
12251e0482f5SStefano Zampini #if defined(PRINT_GDET)
12261e0482f5SStefano Zampini   inc = 0;
12271e0482f5SStefano Zampini   lev = pcbddc->current_level;
12281e0482f5SStefano Zampini #endif
1229213b8bfaSStefano Zampini 
1230213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1231a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1232a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
12331e0482f5SStefano Zampini     IS          cornersis = NULL;
12341e0482f5SStefano Zampini     PetscScalar cvals[2];
1235a13144ffSStefano Zampini 
1236*48a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
12379566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1238a13144ffSStefano Zampini     if (Gins && GKins) {
12391683a169SBarry Smith       const PetscScalar *data;
1240a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1241a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1242a13144ffSStefano Zampini 
12439566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1244a13144ffSStefano Zampini       /* H1 */
12459566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
12469566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
12479566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
12489566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
12499566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
12509566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1251a13144ffSStefano Zampini       /* complement */
12529566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
125363a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
125463a3b9bcSJacob 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);
125563a3b9bcSJacob 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);
12569566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
12579566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
12589566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
12591e0482f5SStefano Zampini 
12601e0482f5SStefano Zampini       /* coarse discrete gradient */
12611e0482f5SStefano Zampini       if (pcbddc->nedcG) {
12621e0482f5SStefano Zampini         PetscInt cols[2];
12631e0482f5SStefano Zampini 
12641e0482f5SStefano Zampini         cols[0] = 2 * i;
12651e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
12669566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
12671e0482f5SStefano Zampini       }
12689566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1269a13144ffSStefano Zampini     }
12709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
12719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
12729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
12739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
12749566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1275a13144ffSStefano Zampini   }
12769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1277a13144ffSStefano Zampini 
1278a13144ffSStefano Zampini   /* Start assembling */
12799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
12801baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1281a13144ffSStefano Zampini 
1282a13144ffSStefano Zampini   /* Free */
1283c2151214SStefano Zampini   if (fl2g) {
12849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
1285*48a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
12869566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1287c2151214SStefano Zampini   }
1288eee23b56SStefano Zampini 
1289eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1290eee23b56SStefano Zampini   {
1291eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1292eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1293eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1294eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1295eee23b56SStefano Zampini 
1296eee23b56SStefano Zampini     /* find first primal edge */
1297eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
12989566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1299eee23b56SStefano Zampini     } else {
13001baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1301eee23b56SStefano Zampini       idxs = cedges;
1302eee23b56SStefano Zampini     }
1303eee23b56SStefano Zampini     cum = 0;
1304eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1305eee23b56SStefano Zampini 
1306eee23b56SStefano Zampini     /* adapt connected components */
13079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1308eee23b56SStefano Zampini     graph->cptr[0] = 0;
1309eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1310eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1311eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1312eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1313eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1314eee23b56SStefano Zampini         ncc++;
1315eee23b56SStefano Zampini         lc--;
1316eee23b56SStefano Zampini         cum++;
1317eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1318eee23b56SStefano Zampini       }
1319eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1320eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1321eee23b56SStefano Zampini       ncc++;
1322eee23b56SStefano Zampini     }
1323eee23b56SStefano Zampini     graph->ncc = ncc;
1324*48a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
13259566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1326eee23b56SStefano Zampini   }
13279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
13289566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
13299566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
13309566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
1331eee23b56SStefano Zampini 
13329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
13339566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
13349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
13359566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
13369566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
13379566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
13389566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
13399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1340a13144ffSStefano Zampini 
1341a13144ffSStefano Zampini   /* Complete assembling */
13429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
13431e0482f5SStefano Zampini   if (pcbddc->nedcG) {
13449566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
13451e0482f5SStefano Zampini #if 0
13469566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->nedcG,"coarse_G"));
13479566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->nedcG,NULL));
13481e0482f5SStefano Zampini #endif
13491e0482f5SStefano Zampini   }
1350a13144ffSStefano Zampini 
1351a13144ffSStefano Zampini   /* set change of basis */
13529566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, singular));
13539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
1354a13144ffSStefano Zampini 
1355a13144ffSStefano Zampini   PetscFunctionReturn(0);
1356a13144ffSStefano Zampini }
1357a13144ffSStefano Zampini 
1358d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1359d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1360d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
13619371c9d4SSatish Balay PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp) {
1362d8203eabSStefano Zampini   PetscInt i;
1363d8203eabSStefano Zampini 
1364d8203eabSStefano Zampini   PetscFunctionBegin;
1365d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1366d8203eabSStefano Zampini     PetscInt first, last;
1367d8203eabSStefano Zampini 
13689566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
13697827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1370d8203eabSStefano Zampini     if (i >= first && i < last) {
1371d8203eabSStefano Zampini       PetscScalar *data;
13729566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1373d8203eabSStefano Zampini       if (!has_const) {
1374d8203eabSStefano Zampini         data[i - first] = 1.;
1375d8203eabSStefano Zampini       } else {
137686fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
137786fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1378d8203eabSStefano Zampini       }
13799566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1380d8203eabSStefano Zampini     }
13819566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1382d8203eabSStefano Zampini   }
13839566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1384d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1385d8203eabSStefano Zampini     PetscInt first, last;
13869566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
13879566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1388d8203eabSStefano Zampini     if (i >= first && i < last) {
1389d8203eabSStefano Zampini       PetscScalar *data;
13909566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1391d8203eabSStefano Zampini       if (!has_const) {
1392d8203eabSStefano Zampini         data[i - first] = 0.;
1393d8203eabSStefano Zampini       } else {
139486fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
139586fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1396d8203eabSStefano Zampini       }
13979566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1398d8203eabSStefano Zampini     }
13999566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
14009566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1401d8203eabSStefano Zampini   }
1402d8203eabSStefano Zampini   PetscFunctionReturn(0);
1403d8203eabSStefano Zampini }
1404d8203eabSStefano Zampini 
14059371c9d4SSatish Balay PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp) {
1406a198735bSStefano Zampini   Mat                    loc_divudotp;
1407fa23a32eSStefano Zampini   Vec                    p, v, vins, quad_vec, *quad_vecs;
14088ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
1409669cc0f4SStefano Zampini   PetscScalar           *vals;
1410669cc0f4SStefano Zampini   const PetscScalar     *array;
14110f04eeffSStefano Zampini   PetscInt               i, maxneighs = 0, maxsize, *gidxs;
1412a040e873SStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
14131ae86dd6SStefano Zampini   PetscMPIInt            rank;
1414669cc0f4SStefano Zampini 
1415669cc0f4SStefano Zampini   PetscFunctionBegin;
14169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14170f04eeffSStefano Zampini   for (i = 0; i < n_neigh; i++) maxneighs = PetscMax(graph->count[shared[i][0]] + 1, maxneighs);
14181c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &maxneighs, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)A)));
14198037d520SStefano Zampini   if (!maxneighs) {
14209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14218037d520SStefano Zampini     *nnsp = NULL;
14228037d520SStefano Zampini     PetscFunctionReturn(0);
1423669cc0f4SStefano Zampini   }
1424669cc0f4SStefano Zampini   maxsize = 0;
1425a040e873SStefano Zampini   for (i = 0; i < n_neigh; i++) maxsize = PetscMax(n_shared[i], maxsize);
14269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxsize, &gidxs, maxsize, &vals));
1427669cc0f4SStefano Zampini   /* create vectors to hold quadrature weights */
14289566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
14298ae0ca82SStefano Zampini   if (!transpose) {
14309566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
14318ae0ca82SStefano Zampini   } else {
14329566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
14338ae0ca82SStefano Zampini   }
14349566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(quad_vec, maxneighs, &quad_vecs));
14359566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&quad_vec));
14369566063dSJacob Faibussowitsch   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, maxneighs, quad_vecs, nnsp));
1437*48a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecLockReadPop(quad_vecs[i]));
1438d8203eabSStefano Zampini 
1439669cc0f4SStefano Zampini   /* compute local quad vec */
14409566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
14418ae0ca82SStefano Zampini   if (!transpose) {
14429566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
14438ae0ca82SStefano Zampini   } else {
14449566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
14458ae0ca82SStefano Zampini   }
14469566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
14478ae0ca82SStefano Zampini   if (!transpose) {
14489566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
14498ae0ca82SStefano Zampini   } else {
14509566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
14518ae0ca82SStefano Zampini   }
1452fa23a32eSStefano Zampini   if (vl2l) {
1453187c917aSStefano Zampini     Mat        lA;
1454187c917aSStefano Zampini     VecScatter sc;
1455187c917aSStefano Zampini 
14569566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
14579566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
14589566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
14599566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14609566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14619566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
1462fa23a32eSStefano Zampini   } else {
1463fa23a32eSStefano Zampini     vins = v;
1464fa23a32eSStefano Zampini   }
14659566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(vins, &array));
14669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&p));
14679a962809SStefano Zampini 
14681ae86dd6SStefano Zampini   /* insert in global quadrature vecs */
14699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
14700f04eeffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
1471669cc0f4SStefano Zampini     const PetscInt *idxs;
1472669cc0f4SStefano Zampini     PetscInt        idx, nn, j;
1473669cc0f4SStefano Zampini 
1474a040e873SStefano Zampini     idxs = shared[i];
1475a040e873SStefano Zampini     nn   = n_shared[i];
1476669cc0f4SStefano Zampini     for (j = 0; j < nn; j++) vals[j] = array[idxs[j]];
14779566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(rank, graph->count[idxs[0]], graph->neighbours_set[idxs[0]], &idx));
1478669cc0f4SStefano Zampini     idx = -(idx + 1);
147963a3b9bcSJacob Faibussowitsch     PetscCheck(idx >= 0 && idx < maxneighs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid index %" PetscInt_FMT " not in [0,%" PetscInt_FMT ")", idx, maxneighs);
14809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(map, nn, idxs, gidxs));
14819566063dSJacob Faibussowitsch     PetscCall(VecSetValues(quad_vecs[idx], nn, gidxs, vals, INSERT_VALUES));
1482669cc0f4SStefano Zampini   }
14839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14849566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(vins, &array));
1485*48a46eb9SPierre Jolivet   if (vl2l) PetscCall(VecDestroy(&vins));
14869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
14879566063dSJacob Faibussowitsch   PetscCall(PetscFree2(gidxs, vals));
1488669cc0f4SStefano Zampini 
1489669cc0f4SStefano Zampini   /* assemble near null space */
1490*48a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecAssemblyBegin(quad_vecs[i]));
1491669cc0f4SStefano Zampini   for (i = 0; i < maxneighs; i++) {
14929566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(quad_vecs[i]));
14939566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(quad_vecs[i], NULL, "-pc_bddc_quad_vecs_view"));
14949566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1495669cc0f4SStefano Zampini   }
14969566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(maxneighs, &quad_vecs));
1497669cc0f4SStefano Zampini   PetscFunctionReturn(0);
1498669cc0f4SStefano Zampini }
1499669cc0f4SStefano Zampini 
15009371c9d4SSatish Balay PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv) {
15017620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
15027620a527SStefano Zampini 
15037620a527SStefano Zampini   PetscFunctionBegin;
15047620a527SStefano Zampini   if (primalv) {
15057620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
15067620a527SStefano Zampini       IS list[2], newp;
15077620a527SStefano Zampini 
15087620a527SStefano Zampini       list[0] = primalv;
15097620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
15109566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
15119566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
15129566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
15137620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
15147620a527SStefano Zampini     } else {
15159566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
15167620a527SStefano Zampini     }
15177620a527SStefano Zampini   }
15187620a527SStefano Zampini   PetscFunctionReturn(0);
15197620a527SStefano Zampini }
1520669cc0f4SStefano Zampini 
15219371c9d4SSatish Balay static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx) {
15221c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
15231c7a958bSStefano Zampini 
15241c7a958bSStefano Zampini   PetscFunctionBegin;
15251c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
15261c7a958bSStefano Zampini   PetscFunctionReturn(0);
15271c7a958bSStefano Zampini }
1528674ae819SStefano Zampini 
15299371c9d4SSatish Balay PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc) {
15301f4df5f7SStefano Zampini   Vec       local, global;
15311f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
15321f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
15335c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
15341f4df5f7SStefano Zampini 
15351f4df5f7SStefano Zampini   PetscFunctionBegin;
1536d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
15379566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1538d0609cedSBarry Smith   PetscOptionsEnd();
15391f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
15409566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
15419566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
15429566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
15439566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
15446a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
1545*48a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
15466a8fc67bSStefano Zampini     goto boundary;
15476a8fc67bSStefano Zampini   }
15485c5e10d6SStefano Zampini 
15491f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
15501f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
15511f4df5f7SStefano Zampini       PetscInt i;
15520c85b387SStefano Zampini 
15539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
15541f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
15550c85b387SStefano Zampini         PetscInt bs;
15560c85b387SStefano Zampini 
15579566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
15589566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
15599566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15609566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
15611f4df5f7SStefano Zampini       }
15621f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
15631f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
15649566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
15651f4df5f7SStefano Zampini     }
15661f4df5f7SStefano Zampini   } else {
156721ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
156821ef3d20SStefano Zampini       DM dm;
156921ef3d20SStefano Zampini 
15709566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
1571*48a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
157221ef3d20SStefano Zampini       if (dm) {
157321ef3d20SStefano Zampini         IS      *fields;
157421ef3d20SStefano Zampini         PetscInt nf, i;
15750c85b387SStefano Zampini 
15769566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
15779566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
157821ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
15790c85b387SStefano Zampini           PetscInt bs;
15800c85b387SStefano Zampini 
15819566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
15829566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
15839566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15849566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
158521ef3d20SStefano Zampini         }
15869566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
158721ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
158821ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
158921ef3d20SStefano Zampini         PetscContainer c;
159021ef3d20SStefano Zampini 
15919566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
159221ef3d20SStefano Zampini         if (c) {
159321ef3d20SStefano Zampini           MatISLocalFields lf;
15949566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
15959566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
159621ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
15971f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
15989566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
159921ef3d20SStefano Zampini           if (i > 1) {
1600986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
16019566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
1602*48a46eb9SPierre 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]));
16031f4df5f7SStefano Zampini           }
160421ef3d20SStefano Zampini         }
160521ef3d20SStefano Zampini       }
16067a0e7b2cSstefano_zampini     } else {
16077a0e7b2cSstefano_zampini       PetscInt i;
1608*48a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
16091f4df5f7SStefano Zampini     }
1610986cdee1SStefano Zampini   }
16111f4df5f7SStefano Zampini 
16125c5e10d6SStefano Zampini boundary:
16131f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
16149566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
16157a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
16169566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
16171f4df5f7SStefano Zampini   }
16181f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
16199566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
16207a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
16219566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
16221f4df5f7SStefano Zampini   }
1623*48a46eb9SPierre 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));
16249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
16259566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
16267620a527SStefano Zampini   /* detect local disconnected subdomains if requested (use matis->A) */
16277620a527SStefano Zampini   if (pcbddc->detect_disconnected) {
16287620a527SStefano Zampini     IS        primalv = NULL;
16297620a527SStefano Zampini     PetscInt  i;
16308361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
16317a0e7b2cSstefano_zampini 
1632*48a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
16339566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
16349566063dSJacob Faibussowitsch     PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
16359566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
16369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
16377620a527SStefano Zampini   }
16387620a527SStefano Zampini   /* early stage corner detection */
16397620a527SStefano Zampini   {
16407620a527SStefano Zampini     DM dm;
16417620a527SStefano Zampini 
16429566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
1643*48a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
16447620a527SStefano Zampini     if (dm) {
16457620a527SStefano Zampini       PetscBool isda;
16467620a527SStefano Zampini 
16479566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
16487620a527SStefano Zampini       if (isda) {
16497620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
16507620a527SStefano Zampini         IS                     corners;
16517620a527SStefano Zampini         Mat                    lA;
16524f819b78SStefano Zampini         PetscBool              gl, lo;
16537620a527SStefano Zampini 
16544f819b78SStefano Zampini         {
16554f819b78SStefano Zampini           Vec                cvec;
16564f819b78SStefano Zampini           const PetscScalar *coords;
16574f819b78SStefano Zampini           PetscInt           dof, n, cdim;
16584f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
16594f819b78SStefano Zampini 
16609566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
16619566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
16629566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
16639566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
16644f819b78SStefano Zampini           n /= cdim;
16659566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
16669566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
16679566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
16684f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
16694f819b78SStefano Zampini           memc = PETSC_FALSE;
16704f819b78SStefano Zampini #endif
16714f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
16724f819b78SStefano Zampini           if (memc) {
16739566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
16744f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
16754f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
16764f819b78SStefano Zampini             PetscInt   i, b, d;
16774f819b78SStefano Zampini 
16784f819b78SStefano Zampini             for (i = 0; i < n; i++) {
16794f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
16809371c9d4SSatish Balay                 for (d = 0; d < cdim; d++) { bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]); }
16814f819b78SStefano Zampini               }
16824f819b78SStefano Zampini             }
16834f819b78SStefano Zampini           }
16849566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
16854f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
16864f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
16874f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
16884f819b78SStefano Zampini         }
16899566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
16909566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
16919566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
16929566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
16934f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
16941c2dc1cbSBarry Smith         PetscCall(MPIU_Allreduce(&lo, &gl, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
16954f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
16967620a527SStefano Zampini           const PetscInt *idx;
169772ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
16987620a527SStefano Zampini 
16999566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
17009566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
17019566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
17029566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
170372ed36d8SStefano Zampini           if (bs == dof) {
17049566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
17059566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
170672ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
170772ed36d8SStefano Zampini             PetscInt i, d;
170872ed36d8SStefano Zampini 
17099566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
17109371c9d4SSatish Balay             for (i = 0; i < n; i++)
17119371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
17129566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
171372ed36d8SStefano Zampini 
171472ed36d8SStefano Zampini             bs = 1;
171572ed36d8SStefano Zampini             n *= dof;
171672ed36d8SStefano Zampini           }
17179566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
17189566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17199566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
17209566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
17219566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
17221c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
17234f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
17244f819b78SStefano Zampini         }
1725*48a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17267620a527SStefano Zampini       }
17277620a527SStefano Zampini     }
17287620a527SStefano Zampini   }
17291c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
17301c7a958bSStefano Zampini     DM dm;
17311c7a958bSStefano Zampini 
17329566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
1733*48a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
17344f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
17351c7a958bSStefano Zampini       Vec          vcoords;
17361c7a958bSStefano Zampini       PetscSection section;
17371c7a958bSStefano Zampini       PetscReal   *coords;
17381c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
17391c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
174051ab8ad6SStefano Zampini       /* debug coordinates */
174151ab8ad6SStefano Zampini       PetscViewer       viewer;
174251ab8ad6SStefano Zampini       PetscBool         flg;
174351ab8ad6SStefano Zampini       PetscViewerFormat format;
174451ab8ad6SStefano Zampini       const char       *prefix;
17451c7a958bSStefano Zampini 
17469566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
17479566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
17489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
17499566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
17509566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
17519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
17529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
17539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
17541c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
17551c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
175651ab8ad6SStefano Zampini 
175751ab8ad6SStefano Zampini       /* debug coordinates */
175851ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
175951ab8ad6SStefano Zampini       PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
176051ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
17611c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
17621c7a958bSStefano Zampini         PetscInt           i;
17631c7a958bSStefano Zampini         const PetscScalar *v;
176451ab8ad6SStefano Zampini         char               name[16];
17651c7a958bSStefano Zampini 
17661c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
176751ab8ad6SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%d", (int)d));
176851ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
17699566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
177051ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
17719566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
17721c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
17739566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
17741c7a958bSStefano Zampini       }
17759566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
17769566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
17779566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
17789566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
17799566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
178051ab8ad6SStefano Zampini       if (flg) {
178151ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
178251ab8ad6SStefano Zampini         PetscCall(PetscViewerDestroy(&viewer));
178351ab8ad6SStefano Zampini       }
17841c7a958bSStefano Zampini     }
17851c7a958bSStefano Zampini   }
17867a0e7b2cSstefano_zampini   PetscFunctionReturn(0);
17877a0e7b2cSstefano_zampini }
17887a0e7b2cSstefano_zampini 
17899371c9d4SSatish Balay PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is) {
17907a0e7b2cSstefano_zampini   Mat_IS         *matis = (Mat_IS *)(pc->pmat->data);
17917a0e7b2cSstefano_zampini   IS              nis;
17927a0e7b2cSstefano_zampini   const PetscInt *idxs;
17937a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
17947a0e7b2cSstefano_zampini 
17957a0e7b2cSstefano_zampini   PetscFunctionBegin;
17967827d75bSBarry Smith   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)(pc)), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
17977a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
17987a0e7b2cSstefano_zampini     /* init rootdata with true */
17991bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
18007a0e7b2cSstefano_zampini   } else {
18019566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
18027a0e7b2cSstefano_zampini   }
18039566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
18049566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
18059566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
18067a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
18079371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
18089566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
18099566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18109566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18119566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18129566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18137a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
18149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
18157a0e7b2cSstefano_zampini   } else {
18169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
18177a0e7b2cSstefano_zampini   }
18187a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
18199371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
18209566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(*is)), nnd, nidxs, PETSC_OWN_POINTER, &nis));
18219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
18227a0e7b2cSstefano_zampini   *is = nis;
18231f4df5f7SStefano Zampini   PetscFunctionReturn(0);
18241f4df5f7SStefano Zampini }
18251f4df5f7SStefano Zampini 
18269371c9d4SSatish Balay PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z) {
18273e589ea0SStefano Zampini   PC_IS   *pcis   = (PC_IS *)(pc->data);
18283e589ea0SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)(pc->data);
18293e589ea0SStefano Zampini 
18303e589ea0SStefano Zampini   PetscFunctionBegin;
18319371c9d4SSatish Balay   if (!pcbddc->benign_have_null) { PetscFunctionReturn(0); }
18323e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
18333e589ea0SStefano Zampini     Vec swap;
18343e589ea0SStefano Zampini 
18359566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
18363e589ea0SStefano Zampini     swap                = pcbddc->work_change;
18373e589ea0SStefano Zampini     pcbddc->work_change = r;
18383e589ea0SStefano Zampini     r                   = swap;
18393e589ea0SStefano Zampini   }
18409566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18419566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18439566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
18449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18459566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
18469566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
18479566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18489566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18493e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
1850f913dca9SStefano Zampini     pcbddc->work_change = r;
18519566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
18529566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
18533e589ea0SStefano Zampini   }
18543e589ea0SStefano Zampini   PetscFunctionReturn(0);
18553e589ea0SStefano Zampini }
18563e589ea0SStefano Zampini 
18579371c9d4SSatish Balay PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose) {
1858a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1859a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
1860a3df083aSStefano Zampini 
1861a3df083aSStefano Zampini   PetscFunctionBegin;
18629566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
1863a3df083aSStefano Zampini   if (transpose) {
1864a3df083aSStefano Zampini     apply_right = ctx->apply_left;
1865a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
1866a3df083aSStefano Zampini   } else {
1867a3df083aSStefano Zampini     apply_right = ctx->apply_right;
1868a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
1869a3df083aSStefano Zampini   }
1870a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
1871a3df083aSStefano Zampini   if (apply_right) {
1872a3df083aSStefano Zampini     const PetscScalar *ax;
1873a3df083aSStefano Zampini     PetscInt           nl, i;
1874a3df083aSStefano Zampini 
18759566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
18769566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
18779566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
18789566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
1879a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1880a3df083aSStefano Zampini       PetscScalar     sum, val;
1881a3df083aSStefano Zampini       const PetscInt *idxs;
1882a3df083aSStefano Zampini       PetscInt        nz, j;
18839566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
18849566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1885a3df083aSStefano Zampini       sum = 0.;
1886a3df083aSStefano Zampini       if (ctx->apply_p0) {
1887a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
1888a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1889a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
1890a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
1891a3df083aSStefano Zampini         }
1892a3df083aSStefano Zampini       } else {
18939371c9d4SSatish Balay         for (j = 0; j < nz - 1; j++) { sum += ctx->work[idxs[j]]; }
1894a3df083aSStefano Zampini       }
1895a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
18969566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1897a3df083aSStefano Zampini     }
18989566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
1899a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
1900a3df083aSStefano Zampini   }
1901a3df083aSStefano Zampini   if (transpose) {
19029566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
1903a3df083aSStefano Zampini   } else {
19049566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
1905a3df083aSStefano Zampini   }
19061baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
1907a3df083aSStefano Zampini   if (apply_left) {
1908a3df083aSStefano Zampini     PetscScalar *ay;
1909a3df083aSStefano Zampini     PetscInt     i;
1910a3df083aSStefano Zampini 
19119566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
1912a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1913a3df083aSStefano Zampini       PetscScalar     sum, val;
1914a3df083aSStefano Zampini       const PetscInt *idxs;
1915a3df083aSStefano Zampini       PetscInt        nz, j;
19169566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
19179566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1918a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
1919a3df083aSStefano Zampini       if (ctx->apply_p0) {
1920a3df083aSStefano Zampini         sum = 0.;
1921a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1922a3df083aSStefano Zampini           sum += ay[idxs[j]];
1923a3df083aSStefano Zampini           ay[idxs[j]] += val;
1924a3df083aSStefano Zampini         }
1925a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
1926a3df083aSStefano Zampini       } else {
19279371c9d4SSatish Balay         for (j = 0; j < nz - 1; j++) { ay[idxs[j]] += val; }
1928a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
1929a3df083aSStefano Zampini       }
19309566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1931a3df083aSStefano Zampini     }
19329566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
1933a3df083aSStefano Zampini   }
1934a3df083aSStefano Zampini   PetscFunctionReturn(0);
1935a3df083aSStefano Zampini }
1936a3df083aSStefano Zampini 
19379371c9d4SSatish Balay PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y) {
1938a3df083aSStefano Zampini   PetscFunctionBegin;
19399566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
1940a3df083aSStefano Zampini   PetscFunctionReturn(0);
1941a3df083aSStefano Zampini }
1942a3df083aSStefano Zampini 
19439371c9d4SSatish Balay PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y) {
1944a3df083aSStefano Zampini   PetscFunctionBegin;
19459566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
1946a3df083aSStefano Zampini   PetscFunctionReturn(0);
1947a3df083aSStefano Zampini }
1948a3df083aSStefano Zampini 
19499371c9d4SSatish Balay PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore) {
1950a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
1951a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
1952a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1953a3df083aSStefano Zampini 
1954a3df083aSStefano Zampini   PetscFunctionBegin;
1955a3df083aSStefano Zampini   if (!restore) {
19561dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
1957a3df083aSStefano Zampini     PetscScalar       *work;
1958b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
1959a3df083aSStefano Zampini 
196028b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
19619a962809SStefano Zampini     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(0);
19629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
19639566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
19649566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
19659566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
19669566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (void (*)(void))PCBDDCBenignMatMult_Private));
19679566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (void (*)(void))PCBDDCBenignMatMultTranspose_Private));
19689566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
19699566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
1970a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
1971a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
1972a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
1973a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
1974059032f7SStefano Zampini     if (reuse) {
1975a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
19761dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
1977059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
1978059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
1979059032f7SStefano Zampini       PetscInt               i;
1980059032f7SStefano Zampini 
19819566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
19829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
1983*48a46eb9SPierre 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]));
19849566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
19851dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
1986059032f7SStefano Zampini     }
1987a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
1988a3df083aSStefano Zampini     ctx->work = work;
19899566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
19909566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
19919566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
1992a3df083aSStefano Zampini     pcis->A_IB = A_IB;
1993a3df083aSStefano Zampini 
1994a3df083aSStefano Zampini     /* A_BI as A_IB^T */
19959566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
1996a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
1997a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
1998a3df083aSStefano Zampini   } else {
19999371c9d4SSatish Balay     if (!pcbddc->benign_original_mat) { PetscFunctionReturn(0); }
20009566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
20019566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2002a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
20031dd7afcfSStefano Zampini     ctx->A     = NULL;
20049566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
20051dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
20061dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
20071dd7afcfSStefano Zampini     if (ctx->free) {
2008059032f7SStefano Zampini       PetscInt i;
2009*48a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
20109566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2011059032f7SStefano Zampini     }
20129566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
20139566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2014a3df083aSStefano Zampini   }
2015a3df083aSStefano Zampini   PetscFunctionReturn(0);
2016a3df083aSStefano Zampini }
2017a3df083aSStefano Zampini 
2018a3df083aSStefano Zampini /* used just in bddc debug mode */
20199371c9d4SSatish Balay PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B) {
2020a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2021a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2022a3df083aSStefano Zampini   Mat      An;
2023a3df083aSStefano Zampini 
2024a3df083aSStefano Zampini   PetscFunctionBegin;
20259566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
20269566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2027a3df083aSStefano Zampini   if (is1) {
20289566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
20299566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2030a3df083aSStefano Zampini   } else {
2031a3df083aSStefano Zampini     *B = An;
2032a3df083aSStefano Zampini   }
2033a3df083aSStefano Zampini   PetscFunctionReturn(0);
2034a3df083aSStefano Zampini }
2035a3df083aSStefano Zampini 
20361cf9b237SStefano Zampini /* TODO: add reuse flag */
20379371c9d4SSatish Balay PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B) {
20381cf9b237SStefano Zampini   Mat             Bt;
20391cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
20401cf9b237SStefano Zampini   const PetscInt *ii, *ij;
20411cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
20421cf9b237SStefano Zampini   PetscBool       flg_row;
20431cf9b237SStefano Zampini 
20441cf9b237SStefano Zampini   PetscFunctionBegin;
20459566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
20469566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20479566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
20481cf9b237SStefano Zampini   nnz = n;
20491cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
20501cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
20511cf9b237SStefano Zampini   }
20529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
20539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
20549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
20551cf9b237SStefano Zampini   nnz    = 0;
20561cf9b237SStefano Zampini   bii[0] = 0;
20571cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
20581cf9b237SStefano Zampini     PetscInt j;
20591cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
20601cf9b237SStefano Zampini       PetscScalar entry = a[j];
20613272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
20621cf9b237SStefano Zampini         bij[nnz]   = ij[j];
20631cf9b237SStefano Zampini         bdata[nnz] = entry;
20641cf9b237SStefano Zampini         nnz++;
20651cf9b237SStefano Zampini       }
20661cf9b237SStefano Zampini     }
20671cf9b237SStefano Zampini     bii[i + 1] = nnz;
20681cf9b237SStefano Zampini   }
20699566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
20709566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
20719566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20721cf9b237SStefano Zampini   {
20731cf9b237SStefano Zampini     Mat_SeqAIJ *b = (Mat_SeqAIJ *)(Bt->data);
20741cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
20751cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
20761cf9b237SStefano Zampini   }
2077*48a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
20781cf9b237SStefano Zampini   *B = Bt;
20791cf9b237SStefano Zampini   PetscFunctionReturn(0);
20801cf9b237SStefano Zampini }
20811cf9b237SStefano Zampini 
20829371c9d4SSatish Balay PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv) {
2083c80a6c00SStefano Zampini   Mat                    B = NULL;
2084c80a6c00SStefano Zampini   DM                     dm;
20854f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
20864f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
20874f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2088c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
20894f1b2e48SStefano Zampini   PetscInt               i, n;
20904f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2091c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
20924f1b2e48SStefano Zampini 
20934f1b2e48SStefano Zampini   PetscFunctionBegin;
2094a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2095a2eca866SStefano Zampini   if (cc) *cc = NULL;
2096a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
20979566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
20989566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
2099*48a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
2100*48a46eb9SPierre Jolivet   if (dm) PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isplex));
21018361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
21028361f951SStefano Zampini 
2103c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2104c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2105c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2106c80a6c00SStefano Zampini     IS              cellNumbering;
2107c80a6c00SStefano Zampini     const PetscInt *cellNum;
2108c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2109c80a6c00SStefano Zampini     PetscSection    section;
2110c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2111c80a6c00SStefano Zampini     PetscSF         sfPoint;
2112c80a6c00SStefano Zampini 
21139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
21149566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
21159566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2116c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
21179566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
21189566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
21199566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2120c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
21219566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
21229566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
21239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
21249566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2125c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2126c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
21279371c9d4SSatish Balay       if (nroots > 0) {
21289371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21299371c9d4SSatish Balay       }
2130c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
21319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2132c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2133c80a6c00SStefano Zampini         const PetscInt point = adj[a];
21345cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2135c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
21369566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
21379566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2138c80a6c00SStefano Zampini           *pBuf = point;
2139c80a6c00SStefano Zampini         }
2140c80a6c00SStefano Zampini       }
2141c80a6c00SStefano Zampini       n++;
2142c80a6c00SStefano Zampini     }
21439566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2144c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
21459566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
21469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
21479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2148c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
21499371c9d4SSatish Balay       if (nroots > 0) {
21509371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21519371c9d4SSatish Balay       }
21529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &(xadj[idx++])));
2153c80a6c00SStefano Zampini     }
2154c80a6c00SStefano Zampini     xadj[n] = size;
21559566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2156c80a6c00SStefano Zampini     /* Clean up */
21579566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
21589566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
21599566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2160c80a6c00SStefano Zampini     graph->xadj   = xadj;
2161c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2162c80a6c00SStefano Zampini   } else {
2163c80a6c00SStefano Zampini     Mat       A;
21648361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2165c80a6c00SStefano Zampini 
21669566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
216763c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
21689566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
216963c961adSStefano Zampini       PetscFunctionReturn(0);
217063c961adSStefano Zampini     }
21719566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
21724f1b2e48SStefano Zampini     if (!isseqaij && filter) {
21731cf9b237SStefano Zampini       PetscBool isseqdense;
21741cf9b237SStefano Zampini 
21759566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
21761cf9b237SStefano Zampini       if (!isseqdense) {
21779566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
21781cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
21791cf9b237SStefano Zampini         PetscScalar *array;
21801cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
21811cf9b237SStefano Zampini 
21829566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
21839566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
21849566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
21851cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
21861cf9b237SStefano Zampini           PetscInt j;
21871cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
21881cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
21891cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
21901cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
21911cf9b237SStefano Zampini           }
21921cf9b237SStefano Zampini         }
21939566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
21949566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
21951cf9b237SStefano Zampini       }
21964f1b2e48SStefano Zampini     } else {
21979566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
21984f1b2e48SStefano Zampini       B = A;
21994f1b2e48SStefano Zampini     }
22009566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22014f1b2e48SStefano Zampini 
22024f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
22034f1b2e48SStefano Zampini     if (filter) {
22044f1b2e48SStefano Zampini       PetscScalar *data;
22054f1b2e48SStefano Zampini       PetscInt     j, cum;
22064f1b2e48SStefano Zampini 
22079566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
22089566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
22094f1b2e48SStefano Zampini       cum = 0;
22104f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
22114f1b2e48SStefano Zampini         PetscInt t;
22124f1b2e48SStefano Zampini 
22134f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
22149371c9d4SSatish Balay           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) { continue; }
22154f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
22164f1b2e48SStefano Zampini         }
22174f1b2e48SStefano Zampini         t                = xadj_filtered[i];
22184f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
22194f1b2e48SStefano Zampini         cum += t;
22204f1b2e48SStefano Zampini       }
22219566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
22224f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
22234f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
22244f1b2e48SStefano Zampini     } else {
22254f1b2e48SStefano Zampini       graph->xadj   = xadj;
22264f1b2e48SStefano Zampini       graph->adjncy = adjncy;
22274f1b2e48SStefano Zampini     }
2228c80a6c00SStefano Zampini   }
2229c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
22309566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
22319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
22329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
22339566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_MAX_INT));
22349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
22359566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
22369566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2237c80a6c00SStefano Zampini 
22384f1b2e48SStefano Zampini   /* partial clean up */
22399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2240c80a6c00SStefano Zampini   if (B) {
2241c80a6c00SStefano Zampini     PetscBool flg_row;
22429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
22444f1b2e48SStefano Zampini   }
2245c80a6c00SStefano Zampini   if (isplex) {
22469566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
22479566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2248c80a6c00SStefano Zampini   }
22494f1b2e48SStefano Zampini 
22504f1b2e48SStefano Zampini   /* get back data */
2251c80a6c00SStefano Zampini   if (isplex) {
2252c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2253c80a6c00SStefano Zampini     if (cc || primalv) {
2254c80a6c00SStefano Zampini       Mat          A;
2255c80a6c00SStefano Zampini       PetscBT      btv, btvt;
2256c80a6c00SStefano Zampini       PetscSection subSection;
2257c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2258c80a6c00SStefano Zampini 
22599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
22609566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
22619566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
22629566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
22639566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2264c80a6c00SStefano Zampini 
2265c80a6c00SStefano Zampini       cids[0] = 0;
2266c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2267c80a6c00SStefano Zampini         PetscInt j;
2268c80a6c00SStefano Zampini 
22699566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2270c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2271c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2272c80a6c00SStefano Zampini 
22739566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2274c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
227520c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2276c80a6c00SStefano Zampini 
22779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
22789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
22799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2280c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2281c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2282e432b41dSStefano Zampini               if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2283e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2284c80a6c00SStefano Zampini             }
22859566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
228620c3699dSStefano Zampini             if (pp != p) {
22879566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
22889566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
22899566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
229020c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
229120c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2292e432b41dSStefano Zampini                 if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2293e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
229420c3699dSStefano Zampini               }
229520c3699dSStefano Zampini             }
2296c80a6c00SStefano Zampini           }
22979566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2298c80a6c00SStefano Zampini         }
2299c80a6c00SStefano Zampini         cids[i + 1] = cum;
2300c80a6c00SStefano Zampini         /* mark dofs as already assigned */
2301*48a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2302c80a6c00SStefano Zampini       }
2303c80a6c00SStefano Zampini       if (cc) {
23049566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
2305*48a46eb9SPierre 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]));
2306c80a6c00SStefano Zampini         *cc = cc_n;
2307c80a6c00SStefano Zampini       }
23081baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
23099566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
23109566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
23119566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2312c80a6c00SStefano Zampini     }
2313c80a6c00SStefano Zampini   } else {
23141cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
23151cf9b237SStefano Zampini     if (cc) {
23169566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
2317*48a46eb9SPierre 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]));
23184f1b2e48SStefano Zampini       *cc = cc_n;
23191cf9b237SStefano Zampini     }
2320c80a6c00SStefano Zampini   }
23214f1b2e48SStefano Zampini   /* clean up graph */
23220a545947SLisandro Dalcin   graph->xadj   = NULL;
23230a545947SLisandro Dalcin   graph->adjncy = NULL;
23249566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
23254f1b2e48SStefano Zampini   PetscFunctionReturn(0);
23264f1b2e48SStefano Zampini }
23274f1b2e48SStefano Zampini 
23289371c9d4SSatish Balay PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag) {
23295408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
23305408967cSStefano Zampini   PC_IS   *pcis   = (PC_IS *)(pc->data);
2331dee84bffSStefano Zampini   IS       dirIS  = NULL;
23324f1b2e48SStefano Zampini   PetscInt i;
23335408967cSStefano Zampini 
23345408967cSStefano Zampini   PetscFunctionBegin;
23359566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
23365408967cSStefano Zampini   if (zerodiag) {
23375408967cSStefano Zampini     Mat             A;
23385408967cSStefano Zampini     Vec             vec3_N;
23395408967cSStefano Zampini     PetscScalar    *vals;
23405408967cSStefano Zampini     const PetscInt *idxs;
2341d12d3064SStefano Zampini     PetscInt        nz, *count;
23425408967cSStefano Zampini 
23435408967cSStefano Zampini     /* p0 */
23449566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
23459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
23469566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
23479566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
23484f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
23499566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
23509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
23519566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
23525408967cSStefano Zampini     /* v_I */
23539566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
23545408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
23559566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
23569566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
23579566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
23585408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
23599566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
23609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
23615408967cSStefano Zampini     if (dirIS) {
23625408967cSStefano Zampini       PetscInt n;
23635408967cSStefano Zampini 
23649566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
23659566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
23665408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
23679566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
23689566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
23695408967cSStefano Zampini     }
23709566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
23719566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
23729566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
23739566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
23749566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
23759566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
23769566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
23777827d75bSBarry 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]));
23789566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
23799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2380d12d3064SStefano Zampini 
2381d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
23829566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
23839566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2384d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
23859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
23869566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
238763a3b9bcSJacob 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]);
23889566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
23899566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
23905408967cSStefano Zampini   }
23919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
23925408967cSStefano Zampini 
23935408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
23949566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
23954f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
23969566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
23974f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
23989566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2399f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2400f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
240163a3b9bcSJacob 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));
2402f2a566d8SStefano Zampini   }
24035408967cSStefano Zampini   PetscFunctionReturn(0);
24045408967cSStefano Zampini }
24055408967cSStefano Zampini 
24069371c9d4SSatish Balay PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal) {
2407339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2408e432b41dSStefano Zampini   Mat_IS   *matis     = (Mat_IS *)(pc->pmat->data);
24093b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
24103b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
24114edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
24124edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2413339f8db1SStefano Zampini 
2414339f8db1SStefano Zampini   PetscFunctionBegin;
24153b03f7bbSStefano Zampini   if (reuse) goto project_b0;
24169566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
24179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
2418*48a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
24199566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
24203b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
24213b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
24223b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
24233b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
24244f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
24254f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
24261ae86dd6SStefano Zampini      since the local Schur complements are already SPD
24274f1b2e48SStefano Zampini   */
242840fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
24297fbe2174Sstefano_zampini     IS        iP = NULL;
24303b03f7bbSStefano Zampini     PetscInt  p, *pp;
24313b03f7bbSStefano Zampini     PetscBool flg;
24324f1b2e48SStefano Zampini 
24339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
24343b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2435d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
24369566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
2437d0609cedSBarry Smith     PetscOptionsEnd();
24383b03f7bbSStefano Zampini     if (!flg) {
24393b03f7bbSStefano Zampini       n     = 1;
24403b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
24413b03f7bbSStefano Zampini     }
24423b03f7bbSStefano Zampini 
24433b03f7bbSStefano Zampini     bsp = 0;
24443b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
24453b03f7bbSStefano Zampini       PetscInt bs;
24463b03f7bbSStefano Zampini 
244763a3b9bcSJacob 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]);
24489566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
24493b03f7bbSStefano Zampini       bsp += bs;
24503b03f7bbSStefano Zampini     }
24519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
24523b03f7bbSStefano Zampini     bsp = 0;
24533b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
24543b03f7bbSStefano Zampini       const PetscInt *idxs;
24553b03f7bbSStefano Zampini       PetscInt        b, bs, npl, *bidxs;
24563b03f7bbSStefano Zampini 
24579566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
24589566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
24599566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
24609566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
24613b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
24623b03f7bbSStefano Zampini         PetscInt i;
24633b03f7bbSStefano Zampini 
24643b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
24659566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
24663b03f7bbSStefano Zampini         bsp++;
24673b03f7bbSStefano Zampini       }
24689566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
24699566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
24703b03f7bbSStefano Zampini     }
24719566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
24723b03f7bbSStefano Zampini 
24737fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
24749566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
24757fbe2174Sstefano_zampini     if (iP) {
24767fbe2174Sstefano_zampini       IS newpressures;
24777fbe2174Sstefano_zampini 
24789566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
24799566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
24807fbe2174Sstefano_zampini       pressures = newpressures;
24817fbe2174Sstefano_zampini     }
24829566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
2483*48a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
24849566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
248540fa8d13SStefano Zampini   }
24863b03f7bbSStefano Zampini 
248797d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
24889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
248927b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
24909566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
24919566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
2492*48a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
24939566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
24944edc6404Sstefano_zampini   zerodiag_save = zerodiag;
24959566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
24964f1b2e48SStefano Zampini   if (!nz) {
24974f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
24984f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
24999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
250040fa8d13SStefano Zampini   }
25014f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
25023b03f7bbSStefano Zampini 
25034f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
25044f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
25053b03f7bbSStefano Zampini   benign_n        = 0;
25061f4df5f7SStefano Zampini   n_interior_dofs = 0;
25071f4df5f7SStefano Zampini   interior_dofs   = NULL;
25084edc6404Sstefano_zampini   nneu            = 0;
2509*48a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
25103369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
25114edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
25121f4df5f7SStefano Zampini     PetscInt  n, i, j;
25131f4df5f7SStefano Zampini     PetscInt  n_neigh, *neigh, *n_shared, **shared;
25141f4df5f7SStefano Zampini     PetscInt *iwork;
25151f4df5f7SStefano Zampini 
25169566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &n));
25179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
25189566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &iwork));
25199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
252090648384SStefano Zampini     for (i = 1; i < n_neigh; i++)
25219371c9d4SSatish Balay       for (j = 0; j < n_shared[i]; j++) iwork[shared[i][j]] += 1;
25221f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
25239371c9d4SSatish Balay       if (!iwork[i]) interior_dofs[n_interior_dofs++] = i;
25249566063dSJacob Faibussowitsch     PetscCall(PetscFree(iwork));
25259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
25261f4df5f7SStefano Zampini   }
25274f1b2e48SStefano Zampini   if (has_null_pressures) {
25284f1b2e48SStefano Zampini     IS             *subs;
25294edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
25301f4df5f7SStefano Zampini     const PetscInt *idxs;
25311f4df5f7SStefano Zampini     PetscScalar    *array;
25321f4df5f7SStefano Zampini     Vec            *work;
25334f1b2e48SStefano Zampini 
25344f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
25354f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
25361f4df5f7SStefano 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) */
25374edc6404Sstefano_zampini     if (checkb) {
25389566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
25399566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
25409566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
25411f4df5f7SStefano Zampini       /* work[0] = 1_p */
25429566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
25439566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
25441f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
25459566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
25461f4df5f7SStefano Zampini       /* work[0] = 1_v */
25479566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
25489566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
25491f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
25509566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
25519566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
25521f4df5f7SStefano Zampini     }
25533b03f7bbSStefano Zampini 
25543b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
25553b03f7bbSStefano Zampini       IS      *is;
25563b03f7bbSStefano Zampini       PetscInt b, totb;
25573b03f7bbSStefano Zampini 
25583b03f7bbSStefano Zampini       totb  = bsp;
25593b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
25603b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
25619566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
25623b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
25634f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
25644f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
25654f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
25664f1b2e48SStefano Zampini           PetscInt               nl;
25674f1b2e48SStefano Zampini 
25683b03f7bbSStefano Zampini           if (subs) {
25699566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
25703b03f7bbSStefano Zampini           } else {
25713b03f7bbSStefano Zampini             IS tis;
25723b03f7bbSStefano Zampini 
25739566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
25749566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
25759566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
25769566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
25773b03f7bbSStefano Zampini           }
25789566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
25799566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
25804f1b2e48SStefano Zampini           if (nl) {
25814f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
25824f1b2e48SStefano Zampini 
25834edc6404Sstefano_zampini             if (checkb) {
25849566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
25859566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
25869566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
25879566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
25881f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
25899566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
25909566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
25919566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
25929566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
25939566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
25949566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
25951f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
25961f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
25971f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
25981f4df5f7SStefano Zampini                   break;
25991f4df5f7SStefano Zampini                 }
26001f4df5f7SStefano Zampini               }
26019566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
26021f4df5f7SStefano Zampini             }
26036632bad2Sstefano_zampini             if (valid && nneu) {
26046632bad2Sstefano_zampini               const PetscInt *idxs;
26051f4df5f7SStefano Zampini               PetscInt        nzb;
26061f4df5f7SStefano Zampini 
26079566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26089566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
26099566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26101f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
26111f4df5f7SStefano Zampini             }
26121f4df5f7SStefano Zampini             if (valid && pressures) {
26133b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
26143b03f7bbSStefano Zampini               PetscInt i1, i2;
26153b03f7bbSStefano Zampini 
26169566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
26179566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
26189566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
26199566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
26203b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
26219566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
26229566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
26234f1b2e48SStefano Zampini             }
26244f1b2e48SStefano Zampini             if (valid) {
26259566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
26263b03f7bbSStefano Zampini               benign_n++;
26273b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
26284f1b2e48SStefano Zampini           }
26299566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
26309566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
26314f1b2e48SStefano Zampini         }
26323b03f7bbSStefano Zampini       }
26334f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
26344f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
26351f4df5f7SStefano Zampini 
26366632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
2637*48a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
26384edc6404Sstefano_zampini       if (valid && checkb) {
26399566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
26409566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
26419566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
26421f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
26431f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
26441f4df5f7SStefano Zampini             valid = PETSC_FALSE;
26451f4df5f7SStefano Zampini             break;
26461f4df5f7SStefano Zampini           }
26471f4df5f7SStefano Zampini         }
26489566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
26491f4df5f7SStefano Zampini       }
26504f1b2e48SStefano Zampini       if (valid) {
26513b03f7bbSStefano Zampini         benign_n = 1;
26529566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
26539566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
26544f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
26554f1b2e48SStefano Zampini       }
26564f1b2e48SStefano Zampini     }
2657*48a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
26581f4df5f7SStefano Zampini   }
26599566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
26604f1b2e48SStefano Zampini 
26613b03f7bbSStefano Zampini   if (!benign_n) {
2662b9b0e38cSStefano Zampini     PetscInt n;
2663b9b0e38cSStefano Zampini 
26649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
26654f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
26669566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
266776a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
2668b9b0e38cSStefano Zampini   }
26694f1b2e48SStefano Zampini 
26704f1b2e48SStefano Zampini   /* final check for null pressures */
2671*48a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
26724f1b2e48SStefano Zampini 
26734f1b2e48SStefano Zampini   if (recompute_zerodiag) {
26749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
26753b03f7bbSStefano Zampini     if (benign_n == 1) {
26769566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
26774f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
26784f1b2e48SStefano Zampini     } else {
26794f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
26804f1b2e48SStefano Zampini 
26814f1b2e48SStefano Zampini       nzn = 0;
26823b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
26834f1b2e48SStefano Zampini         PetscInt ns;
26849566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
26854f1b2e48SStefano Zampini         nzn += ns;
26864f1b2e48SStefano Zampini       }
26879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
26884f1b2e48SStefano Zampini       nzn = 0;
26893b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
26904f1b2e48SStefano Zampini         PetscInt ns, *idxs;
26919566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
26929566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
26939566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
26949566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
26954f1b2e48SStefano Zampini         nzn += ns;
26964f1b2e48SStefano Zampini       }
26979566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
26989566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
26994f1b2e48SStefano Zampini     }
27004f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
27014f1b2e48SStefano Zampini   }
27024f1b2e48SStefano Zampini 
27033b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
27041c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
27053b03f7bbSStefano Zampini 
2706669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
2707a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2708a198735bSStefano Zampini     Mat                    A, loc_divudotp;
2709a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
2710a198735bSStefano Zampini     IS                     row, col, isused = NULL;
2711a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
2712a198735bSStefano Zampini 
27131f4df5f7SStefano Zampini     if (pressures) {
27141f4df5f7SStefano Zampini       isused = pressures;
27151f4df5f7SStefano Zampini     } else {
27164edc6404Sstefano_zampini       isused = zerodiag_save;
27171f4df5f7SStefano Zampini     }
27189566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
27199566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
27209566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
27217827d75bSBarry 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");
2722a198735bSStefano Zampini     n_isused = 0;
2723*48a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
27249566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
2725a198735bSStefano Zampini     st = st - n_isused;
27261ae86dd6SStefano Zampini     if (n) {
2727a198735bSStefano Zampini       const PetscInt *gidxs;
2728a198735bSStefano Zampini 
27299566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
27309566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
2731a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
27329566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
27339566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
27349566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
27351ae86dd6SStefano Zampini     } else {
27369566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
27379566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
27389566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
2739a198735bSStefano Zampini     }
27409566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
27419566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
27429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
27439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
27449566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
27459566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
27469566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
27479566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
27489566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
27499566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
27509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
27529566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
27539566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
27549566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
27559566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
27561ae86dd6SStefano Zampini   }
27579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
27589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
27593b03f7bbSStefano Zampini   if (bzerodiag) {
27603b03f7bbSStefano Zampini     PetscInt i;
2761b3afcdbeSStefano Zampini 
2762*48a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
27639566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
27643b03f7bbSStefano Zampini   }
27653b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
27663b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
27673b03f7bbSStefano Zampini 
27683b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
27693b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
27701c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
27713b03f7bbSStefano Zampini 
27723b03f7bbSStefano Zampini project_b0:
27739566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
2774b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
27753b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
27764f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
27774f1b2e48SStefano Zampini 
2778339f8db1SStefano Zampini     /* local change of basis for pressures */
27799566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
27809566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
27819566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
27829566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
27839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
2784aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
27854f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
2786aa0d93e9SStefano Zampini       const PetscInt *idxs;
27874f1b2e48SStefano Zampini       PetscInt        nzs, j;
27884f1b2e48SStefano Zampini 
27899566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
27909566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
27914f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
27924f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
27939566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
27944f1b2e48SStefano Zampini     }
27959566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
27969566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
27979566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
2798aa0d93e9SStefano Zampini     /* set identity by default */
2799*48a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
28009566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
28019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
2802339f8db1SStefano Zampini     /* set change on pressures */
28034f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
28044f1b2e48SStefano Zampini       PetscScalar    *array;
2805aa0d93e9SStefano Zampini       const PetscInt *idxs;
28064f1b2e48SStefano Zampini       PetscInt        nzs;
28074f1b2e48SStefano Zampini 
28089566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
28099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
28104f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
2811339f8db1SStefano Zampini         PetscScalar vals[2];
2812339f8db1SStefano Zampini         PetscInt    cols[2];
2813339f8db1SStefano Zampini 
2814339f8db1SStefano Zampini         cols[0] = idxs[i];
28154f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
2816339f8db1SStefano Zampini         vals[0] = 1.;
2817b0f5fe93SStefano Zampini         vals[1] = 1.;
28189566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
2819339f8db1SStefano Zampini       }
28209566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
28214f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
28224f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
28239566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
28244f1b2e48SStefano Zampini       /* store local idxs for p0 */
28254f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
28269566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
28279566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
28284f1b2e48SStefano Zampini     }
28299566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
28309566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
28313b03f7bbSStefano Zampini 
2832a3df083aSStefano Zampini     /* project if needed */
2833a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
28341dd7afcfSStefano Zampini       Mat M;
28351dd7afcfSStefano Zampini 
28369566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
28379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
28389566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
28399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
2840a3df083aSStefano Zampini     }
28414f1b2e48SStefano Zampini     /* store global idxs for p0 */
28429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
2843339f8db1SStefano Zampini   }
2844339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
2845339f8db1SStefano Zampini   PetscFunctionReturn(0);
2846339f8db1SStefano Zampini }
2847339f8db1SStefano Zampini 
28489371c9d4SSatish Balay PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get) {
2849efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
2850de9d7bd0SStefano Zampini   PetscScalar *array;
2851efc2fbd9SStefano Zampini 
2852efc2fbd9SStefano Zampini   PetscFunctionBegin;
2853efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
28549566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
28559566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
2856efc2fbd9SStefano Zampini   }
2857de9d7bd0SStefano Zampini   if (get) {
28589566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
28599566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
28609566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
28619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
2862de9d7bd0SStefano Zampini   } else {
28639566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
28649566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
28659566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
28669566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
2867efc2fbd9SStefano Zampini   }
2868efc2fbd9SStefano Zampini   PetscFunctionReturn(0);
2869efc2fbd9SStefano Zampini }
2870efc2fbd9SStefano Zampini 
28719371c9d4SSatish Balay PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop) {
2872c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2873c263805aSStefano Zampini 
2874c263805aSStefano Zampini   PetscFunctionBegin;
2875c263805aSStefano Zampini   /* TODO: add error checking
2876c263805aSStefano Zampini     - avoid nested pop (or push) calls.
2877c263805aSStefano Zampini     - cannot push before pop.
28781c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
2879c263805aSStefano Zampini   */
28809371c9d4SSatish Balay   if (!pcbddc->benign_n) { PetscFunctionReturn(0); }
2881c263805aSStefano Zampini   if (pop) {
2882a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
28834f1b2e48SStefano Zampini       IS       is_p0;
28844f1b2e48SStefano Zampini       MatReuse reuse;
2885c263805aSStefano Zampini 
2886c263805aSStefano Zampini       /* extract B_0 */
28874f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
28889371c9d4SSatish Balay       if (pcbddc->benign_B0) { reuse = MAT_REUSE_MATRIX; }
28899566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
28909566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
2891c263805aSStefano Zampini       /* remove rows and cols from local problem */
28929566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
28939566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
28949566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
28959566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
2896a3df083aSStefano Zampini     } else {
2897a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
2898a3df083aSStefano Zampini       PetscScalar *vals;
2899a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
2900a3df083aSStefano Zampini 
29019566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
29029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
2903a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
29040b5adadeSStefano Zampini         PetscInt *nnz;
29059566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
29069566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
29079566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
29089566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
2909331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
29109566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
2911331e053bSStefano Zampini           nnz[i] = n - nnz[i];
2912331e053bSStefano Zampini         }
29139566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
29149566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
29159566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
2916331e053bSStefano Zampini       }
2917a3df083aSStefano Zampini 
2918a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
2919a3df083aSStefano Zampini         PetscScalar *array;
2920a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
2921a3df083aSStefano Zampini 
29229566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
29239566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
29249566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
2925a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
29269566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
29279566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
29289566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
29299566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
29309566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
29319566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
2932a3df083aSStefano Zampini         cum = 0;
2933a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
293422db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
2935a3df083aSStefano Zampini             vals[cum]     = array[j];
2936a3df083aSStefano Zampini             idxs_ins[cum] = j;
2937a3df083aSStefano Zampini             cum++;
2938a3df083aSStefano Zampini           }
2939a3df083aSStefano Zampini         }
29409566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
29419566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
29429566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
2943a3df083aSStefano Zampini       }
29449566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
29459566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
29469566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
2947a3df083aSStefano Zampini     }
2948c263805aSStefano Zampini   } else { /* push */
2949a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
29504f1b2e48SStefano Zampini       PetscInt i;
29514f1b2e48SStefano Zampini 
29524f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
29534f1b2e48SStefano Zampini         PetscScalar *B0_vals;
29544f1b2e48SStefano Zampini         PetscInt    *B0_cols, B0_ncol;
29554f1b2e48SStefano Zampini 
29569566063dSJacob Faibussowitsch         PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
29579566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
29589566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
29599566063dSJacob Faibussowitsch         PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
29609566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
29614f1b2e48SStefano Zampini       }
29629566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
29639566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
29646080607fSStefano Zampini     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
2965c263805aSStefano Zampini   }
2966c263805aSStefano Zampini   PetscFunctionReturn(0);
2967c263805aSStefano Zampini }
2968c263805aSStefano Zampini 
29699371c9d4SSatish Balay PetscErrorCode PCBDDCAdaptiveSelection(PC pc) {
2970b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
297108122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
297208122e43SStefano Zampini   PetscBLASInt    B_dummyint, B_neigs, B_ierr, B_lwork;
297308122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
297408122e43SStefano Zampini   PetscScalar    *work, lwork;
297508122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
297608122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
2977bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
29781b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
297932fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
298008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
298108122e43SStefano Zampini   PetscReal *rwork;
298208122e43SStefano Zampini #endif
2983b1b3d7a2SStefano Zampini 
2984b1b3d7a2SStefano Zampini   PetscFunctionBegin;
298532fe681dSStefano Zampini   if (!pcbddc->adaptive_selection) PetscFunctionReturn(0);
298628b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
298732fe681dSStefano 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");
29889371c9d4SSatish 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,
29899371c9d4SSatish Balay              sub_schurs->is_posdef);
29909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
299106a4e24aSStefano Zampini 
2992fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
299332fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
29949566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
29959566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
29969566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
29979566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
2998fd14bc51SStefano Zampini   }
2999fd14bc51SStefano Zampini 
3000*48a46eb9SPierre 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));
3001e496cd5dSStefano Zampini 
300208122e43SStefano Zampini   /* max size of subsets */
300308122e43SStefano Zampini   mss = 0;
300408122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
300508122e43SStefano Zampini     PetscInt subset_size;
3006862806e4SStefano Zampini 
30079566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
300808122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
300908122e43SStefano Zampini   }
301008122e43SStefano Zampini 
301108122e43SStefano Zampini   /* min/max and threshold */
301208122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3013f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
301408122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3015f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3016bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3017f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3018f6f667cfSStefano Zampini   }
301908122e43SStefano Zampini 
302008122e43SStefano Zampini   /* allocate lapack workspace */
302108122e43SStefano Zampini   cum = cum2 = 0;
302208122e43SStefano Zampini   maxneigs   = 0;
302308122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
302408122e43SStefano Zampini     PetscInt n, subset_size;
3025f6f667cfSStefano Zampini 
30269566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
302708122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
30289162d606SStefano Zampini     cum += subset_size;
30299162d606SStefano Zampini     cum2 += subset_size * n;
303008122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
303108122e43SStefano Zampini   }
30327ebab0bbSStefano Zampini   lwork = 0;
303308122e43SStefano Zampini   if (mss) {
3034bd2a564bSStefano Zampini     if (sub_schurs->is_symmetric) {
30357ebab0bbSStefano Zampini       PetscScalar  sdummy  = 0.;
303608122e43SStefano Zampini       PetscBLASInt B_itype = 1;
30377ebab0bbSStefano Zampini       PetscBLASInt B_N = mss, idummy = 0;
30387ebab0bbSStefano Zampini       PetscReal    rdummy = 0., zero = 0.0;
30394c6709b3SStefano Zampini       PetscReal    eps = 0.0; /* dlamch? */
304008122e43SStefano Zampini 
304108122e43SStefano Zampini       B_lwork = -1;
30427ebab0bbSStefano Zampini       /* some implementations may complain about NULL pointers, even if we are querying */
30437ebab0bbSStefano Zampini       S       = &sdummy;
30447ebab0bbSStefano Zampini       St      = &sdummy;
30457ebab0bbSStefano Zampini       eigs    = &rdummy;
30467ebab0bbSStefano Zampini       eigv    = &sdummy;
30477ebab0bbSStefano Zampini       B_iwork = &idummy;
30487ebab0bbSStefano Zampini       B_ifail = &idummy;
3049d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
30507ebab0bbSStefano Zampini       rwork = &rdummy;
3051d1710679SStefano Zampini #endif
30528bec7fa6SStefano Zampini       thresh = 1.0;
30539566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
305408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3055792fecdfSBarry Smith       PetscCallBLAS("LAPACKsygvx", LAPACKsygvx_(&B_itype, "V", "V", "L", &B_N, St, &B_N, S, &B_N, &zero, &thresh, &B_dummyint, &B_dummyint, &eps, &B_neigs, eigs, eigv, &B_N, &lwork, &B_lwork, rwork, B_iwork, B_ifail, &B_ierr));
305608122e43SStefano Zampini #else
3057792fecdfSBarry Smith       PetscCallBLAS("LAPACKsygvx", LAPACKsygvx_(&B_itype, "V", "V", "L", &B_N, St, &B_N, S, &B_N, &zero, &thresh, &B_dummyint, &B_dummyint, &eps, &B_neigs, eigs, eigv, &B_N, &lwork, &B_lwork, B_iwork, B_ifail, &B_ierr));
305808122e43SStefano Zampini #endif
305908401ef6SPierre Jolivet       PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %d", (int)B_ierr);
30609566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
3061bd2a564bSStefano Zampini     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
306208122e43SStefano Zampini   }
306308122e43SStefano Zampini 
306408122e43SStefano Zampini   nv = 0;
3065d62866d3SStefano 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) */
30669566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
306708122e43SStefano Zampini   }
30689566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
3069*48a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
30709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
307108122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
30729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
307308122e43SStefano Zampini #endif
30749371c9d4SSatish 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,
30759371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
30769566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
307708122e43SStefano Zampini 
307808122e43SStefano Zampini   maxneigs = 0;
307972b8c272SStefano Zampini   cum = cumarray                           = 0;
30809162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
30819162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3082d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
308308122e43SStefano Zampini     const PetscInt *idxs;
308408122e43SStefano Zampini 
30859566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
308608122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
308708122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
308808122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
308908122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
30909162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
30919162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
309208122e43SStefano Zampini     }
30939566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
309408122e43SStefano Zampini   }
309508122e43SStefano Zampini 
309608122e43SStefano Zampini   if (mss) { /* multilevel */
309732fe681dSStefano Zampini     if (sub_schurs->gdsw) {
309832fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
309932fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
310032fe681dSStefano Zampini     } else {
31019566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
31029566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
310308122e43SStefano Zampini     }
310432fe681dSStefano Zampini   }
310508122e43SStefano Zampini 
3106bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3107bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
310832fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
310908122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
311008122e43SStefano Zampini     const PetscInt *idxs;
31119d54b7f4SStefano Zampini     PetscReal       upper, lower;
3112862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
311308122e43SStefano Zampini     PetscBLASInt    B_N;
3114aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3115bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
311608122e43SStefano Zampini 
311732fe681dSStefano Zampini     if (upart) {
31189d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3119bd2a564bSStefano Zampini       lower = uthresh;
31209d54b7f4SStefano Zampini     } else {
312132fe681dSStefano Zampini       if (sub_schurs->gdsw) {
312232fe681dSStefano Zampini         upper = uthresh;
312332fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
312432fe681dSStefano Zampini       } else {
312528b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3126bd2a564bSStefano Zampini         upper = 1. / uthresh;
31279d54b7f4SStefano Zampini         lower = 0.;
31289d54b7f4SStefano Zampini       }
312932fe681dSStefano Zampini     }
31309566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
31319566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
31329566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3133bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3134bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3135bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3136bd2a564bSStefano Zampini       Mat T;
3137bd2a564bSStefano Zampini 
3138bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3139bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
31409566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
31419566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
31429566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
31439566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
31449566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
31459566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3146bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3147bd2a564bSStefano Zampini             PetscInt        nz, k;
3148bd2a564bSStefano Zampini             const PetscInt *idxs;
3149bd2a564bSStefano Zampini 
31509566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
31519566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3152bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3153bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3154bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3155bd2a564bSStefano Zampini             }
31569566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3157bd2a564bSStefano Zampini           }
3158bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3159bd2a564bSStefano Zampini           break;
3160bd2a564bSStefano Zampini         }
3161bd2a564bSStefano Zampini       }
3162bd2a564bSStefano Zampini     }
3163bd2a564bSStefano Zampini 
3164f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3165bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3166aff50787SStefano Zampini         PetscInt j, k;
3167580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
31689566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
31699566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
317008122e43SStefano Zampini         }
317108122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3172aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3173aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3174aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3175aff50787SStefano Zampini           }
317608122e43SStefano Zampini         }
317708122e43SStefano Zampini       } else {
31789566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
31799566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
318008122e43SStefano Zampini       }
31818bec7fa6SStefano Zampini     } else {
3182f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3183f6f667cfSStefano Zampini       St = Starray + cumarray;
31848bec7fa6SStefano Zampini     }
3185aff50787SStefano Zampini     /* see if we can save some work */
3186*48a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3187aff50787SStefano Zampini 
3188b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3189aff50787SStefano Zampini       B_neigs = 0;
3190aff50787SStefano Zampini     } else {
3191bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
319208122e43SStefano Zampini         PetscBLASInt B_itype = 1;
3193f6f667cfSStefano Zampini         PetscBLASInt B_IL, B_IU;
31944c6709b3SStefano Zampini         PetscReal    eps = -1.0; /* dlamch? */
31959552c7c7SStefano Zampini         PetscInt     nmin_s;
3196bd2a564bSStefano Zampini         PetscBool    compute_range;
3197bd2a564bSStefano Zampini 
31989036ceccSStefano Zampini         B_neigs       = 0;
3199bd2a564bSStefano Zampini         compute_range = (PetscBool)!same_data;
3200bd2a564bSStefano Zampini         if (nmin >= subset_size) compute_range = PETSC_FALSE;
320108122e43SStefano Zampini 
3202fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
32039036ceccSStefano Zampini           PetscInt nc = 0;
3204d16cbb6bSStefano Zampini 
3205*48a46eb9SPierre Jolivet           if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
32069371c9d4SSatish Balay           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Computing for sub %" PetscInt_FMT "/%" PetscInt_FMT " size %" PetscInt_FMT " count %" PetscInt_FMT " fid %" PetscInt_FMT " (range %d) (change %" PetscInt_FMT ").\n", i,
32079371c9d4SSatish Balay                                                        sub_schurs->n_subs, subset_size, pcbddc->mat_graph->count[idxs[0]] + 1, pcbddc->mat_graph->which_dof[idxs[0]], compute_range, nc));
3208b7ab4a40SStefano Zampini         }
3209b7ab4a40SStefano Zampini 
32109566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3211b7ab4a40SStefano Zampini         if (compute_range) {
3212d16cbb6bSStefano Zampini           /* ask for eigenvalues larger than thresh */
3213bd2a564bSStefano Zampini           if (sub_schurs->is_posdef) {
321408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3215792fecdfSBarry 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));
321608122e43SStefano Zampini #else
3217792fecdfSBarry 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));
321808122e43SStefano Zampini #endif
32199566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3220bd2a564bSStefano Zampini           } else { /* no theory so far, but it works nicely */
32219036ceccSStefano Zampini             PetscInt  recipe = 0, recipe_m = 1;
3222bd2a564bSStefano Zampini             PetscReal bb[2];
3223bd2a564bSStefano Zampini 
32249566063dSJacob Faibussowitsch             PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3225bd2a564bSStefano Zampini             switch (recipe) {
3226bd2a564bSStefano Zampini             case 0:
32279371c9d4SSatish Balay               if (scal) {
32289371c9d4SSatish Balay                 bb[0] = PETSC_MIN_REAL;
32299371c9d4SSatish Balay                 bb[1] = lthresh;
32309371c9d4SSatish Balay               } else {
32319371c9d4SSatish Balay                 bb[0] = uthresh;
32329371c9d4SSatish Balay                 bb[1] = PETSC_MAX_REAL;
32339371c9d4SSatish Balay               }
3234bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3235792fecdfSBarry 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));
3236bd2a564bSStefano Zampini #else
3237792fecdfSBarry 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));
3238bd2a564bSStefano Zampini #endif
32399566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3240bd2a564bSStefano Zampini               break;
32419371c9d4SSatish Balay             case 1: bb[0] = PETSC_MIN_REAL; bb[1] = lthresh * lthresh;
3242bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3243792fecdfSBarry 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));
3244bd2a564bSStefano Zampini #else
3245792fecdfSBarry 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));
3246bd2a564bSStefano Zampini #endif
32479566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3248bd2a564bSStefano Zampini               if (!scal) {
32499036ceccSStefano Zampini                 PetscBLASInt B_neigs2 = 0;
3250bd2a564bSStefano Zampini 
32519371c9d4SSatish Balay                 bb[0] = PetscMax(lthresh * lthresh, uthresh);
32529371c9d4SSatish Balay                 bb[1] = PETSC_MAX_REAL;
32539566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
32549566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3255bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3256792fecdfSBarry 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));
3257bd2a564bSStefano Zampini #else
3258792fecdfSBarry 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));
3259bd2a564bSStefano Zampini #endif
32609566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3261bd2a564bSStefano Zampini                 B_neigs += B_neigs2;
3262bd2a564bSStefano Zampini               }
3263bd2a564bSStefano Zampini               break;
32649036ceccSStefano Zampini             case 2:
32659036ceccSStefano Zampini               if (scal) {
32669036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
32679036ceccSStefano Zampini                 bb[1] = 0;
32689036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3269792fecdfSBarry 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));
32709036ceccSStefano Zampini #else
3271792fecdfSBarry 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));
32729036ceccSStefano Zampini #endif
32739566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
32749036ceccSStefano Zampini               } else {
32759036ceccSStefano Zampini                 PetscBLASInt B_neigs2 = 0;
32769036ceccSStefano Zampini                 PetscBool    import   = PETSC_FALSE;
32779036ceccSStefano Zampini 
32789036ceccSStefano Zampini                 lthresh = PetscMax(lthresh, 0.0);
32799036ceccSStefano Zampini                 if (lthresh > 0.0) {
32809036ceccSStefano Zampini                   bb[0] = PETSC_MIN_REAL;
32819036ceccSStefano Zampini                   bb[1] = lthresh * lthresh;
32829036ceccSStefano Zampini 
32839036ceccSStefano Zampini                   import = PETSC_TRUE;
32849036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3285792fecdfSBarry 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));
32869036ceccSStefano Zampini #else
3287792fecdfSBarry 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));
32889036ceccSStefano Zampini #endif
32899566063dSJacob Faibussowitsch                   PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
32909036ceccSStefano Zampini                 }
32919036ceccSStefano Zampini                 bb[0] = PetscMax(lthresh * lthresh, uthresh);
32929036ceccSStefano Zampini                 bb[1] = PETSC_MAX_REAL;
32939036ceccSStefano Zampini                 if (import) {
32949566063dSJacob Faibussowitsch                   PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
32959566063dSJacob Faibussowitsch                   PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
32969036ceccSStefano Zampini                 }
32979036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3298792fecdfSBarry 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));
32999036ceccSStefano Zampini #else
3300792fecdfSBarry 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));
33019036ceccSStefano Zampini #endif
33029566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33039036ceccSStefano Zampini                 B_neigs += B_neigs2;
33049036ceccSStefano Zampini               }
33059036ceccSStefano Zampini               break;
33069036ceccSStefano Zampini             case 3:
33079036ceccSStefano Zampini               if (scal) {
33089566063dSJacob Faibussowitsch                 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
33099036ceccSStefano Zampini               } else {
33109566063dSJacob Faibussowitsch                 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
33119036ceccSStefano Zampini               }
33129036ceccSStefano Zampini               if (!scal) {
33139036ceccSStefano Zampini                 bb[0] = uthresh;
33149036ceccSStefano Zampini                 bb[1] = PETSC_MAX_REAL;
33159036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3316792fecdfSBarry 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));
33179036ceccSStefano Zampini #else
3318792fecdfSBarry Smith                 PetscCallBLAS("LAPACKsygvx", LAPACKsygvx_(&B_itype, "V", "V", "L", &B_N, St, &B_N, S, &B_N, &bb[0], &bb[1], &B_IL, &B_IU, &eps, &B_neigs, eigs, eigv, &B_N, work, &B_lwork, B_iwork, B_ifail, &B_ierr));
33199036ceccSStefano Zampini #endif
33209566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33219036ceccSStefano Zampini               }
33229036ceccSStefano Zampini               if (recipe_m > 0 && B_N - B_neigs > 0) {
33239036ceccSStefano Zampini                 PetscBLASInt B_neigs2 = 0;
33249036ceccSStefano Zampini 
33259036ceccSStefano Zampini                 B_IL = 1;
33269566063dSJacob Faibussowitsch                 PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
33279566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33289566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
33299036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3330792fecdfSBarry 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));
33319036ceccSStefano Zampini #else
3332792fecdfSBarry 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));
33339036ceccSStefano Zampini #endif
33349566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33359036ceccSStefano Zampini                 B_neigs += B_neigs2;
33369036ceccSStefano Zampini               }
33379036ceccSStefano Zampini               break;
33389371c9d4SSatish Balay             case 4: bb[0] = PETSC_MIN_REAL; bb[1] = lthresh;
333948cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3340792fecdfSBarry 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));
334148cebe81SStefano Zampini #else
3342792fecdfSBarry 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));
334348cebe81SStefano Zampini #endif
33449566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
334548cebe81SStefano Zampini               {
334648cebe81SStefano Zampini                 PetscBLASInt B_neigs2 = 0;
334748cebe81SStefano Zampini 
33489371c9d4SSatish Balay                 bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
33499371c9d4SSatish Balay                 bb[1] = PETSC_MAX_REAL;
33509566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33519566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
335248cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3353792fecdfSBarry 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));
335448cebe81SStefano Zampini #else
3355792fecdfSBarry 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));
335648cebe81SStefano Zampini #endif
33579566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
335848cebe81SStefano Zampini                 B_neigs += B_neigs2;
335948cebe81SStefano Zampini               }
336048cebe81SStefano Zampini               break;
336180db8efeSStefano Zampini             case 5: /* same as before: first compute all eigenvalues, then filter */
336280db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3363792fecdfSBarry 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));
336480db8efeSStefano Zampini #else
3365792fecdfSBarry 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));
336680db8efeSStefano Zampini #endif
33679566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
336880db8efeSStefano Zampini               {
336980db8efeSStefano Zampini                 PetscInt e, k, ne;
337080db8efeSStefano Zampini                 for (e = 0, ne = 0; e < B_neigs; e++) {
337180db8efeSStefano Zampini                   if (eigs[e] < lthresh || eigs[e] > uthresh) {
337280db8efeSStefano Zampini                     for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
337380db8efeSStefano Zampini                     eigs[ne] = eigs[e];
337480db8efeSStefano Zampini                     ne++;
337580db8efeSStefano Zampini                   }
337680db8efeSStefano Zampini                 }
33779566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(eigv, S, B_N * ne));
337880db8efeSStefano Zampini                 B_neigs = ne;
337980db8efeSStefano Zampini               }
338080db8efeSStefano Zampini               break;
33819371c9d4SSatish Balay             default: SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3382bd2a564bSStefano Zampini             }
3383bd2a564bSStefano Zampini           }
3384bd2a564bSStefano Zampini         } else if (!same_data) { /* this is just to see all the eigenvalues */
3385d16cbb6bSStefano Zampini           B_IU = PetscMax(1, PetscMin(B_N, nmax));
3386d16cbb6bSStefano Zampini           B_IL = 1;
3387d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3388792fecdfSBarry 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));
3389d16cbb6bSStefano Zampini #else
3390792fecdfSBarry 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));
3391d16cbb6bSStefano Zampini #endif
33929566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3393b03ebc13SStefano Zampini         } else { /* same_data is true, so just get the adaptive functional requested by the user */
3394b7ab4a40SStefano Zampini           PetscInt k;
339528b400f6SJacob Faibussowitsch           PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
33969566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
33979566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3398b7ab4a40SStefano Zampini           nmin = nmax;
33999566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3400b7ab4a40SStefano Zampini           for (k = 0; k < nmax; k++) {
3401b7ab4a40SStefano Zampini             eigs[k]                     = 1. / PETSC_SMALL;
3402b7ab4a40SStefano Zampini             eigv[k * (subset_size + 1)] = 1.0;
3403b7ab4a40SStefano Zampini           }
3404d16cbb6bSStefano Zampini         }
34059566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
340608122e43SStefano Zampini         if (B_ierr) {
340763a3b9bcSJacob Faibussowitsch           PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
340863a3b9bcSJacob 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);
340963a3b9bcSJacob 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);
341008122e43SStefano Zampini         }
341108122e43SStefano Zampini 
341208122e43SStefano Zampini         if (B_neigs > nmax) {
3413*48a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
341432fe681dSStefano Zampini           if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
341508122e43SStefano Zampini           B_neigs = nmax;
341608122e43SStefano Zampini         }
341708122e43SStefano Zampini 
34189552c7c7SStefano Zampini         nmin_s = PetscMin(nmin, B_N);
34199552c7c7SStefano Zampini         if (B_neigs < nmin_s) {
34209036ceccSStefano Zampini           PetscBLASInt B_neigs2 = 0;
342108122e43SStefano Zampini 
342232fe681dSStefano Zampini           if (upart) {
3423bd2a564bSStefano Zampini             if (scal) {
3424bd2a564bSStefano Zampini               B_IU = nmin_s;
3425bd2a564bSStefano Zampini               B_IL = B_neigs + 1;
3426bd2a564bSStefano Zampini             } else {
3427f6f667cfSStefano Zampini               B_IL = B_N - nmin_s + 1;
34289d54b7f4SStefano Zampini               B_IU = B_N - B_neigs;
3429bd2a564bSStefano Zampini             }
34309d54b7f4SStefano Zampini           } else {
34319d54b7f4SStefano Zampini             B_IL = B_neigs + 1;
34329d54b7f4SStefano Zampini             B_IU = nmin_s;
34339d54b7f4SStefano Zampini           }
3434fd14bc51SStefano Zampini           if (pcbddc->dbg_flag) {
343563a3b9bcSJacob 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));
3436fd14bc51SStefano Zampini           }
3437bd2a564bSStefano Zampini           if (sub_schurs->is_symmetric) {
34381ae86dd6SStefano Zampini             PetscInt j, k;
343908122e43SStefano Zampini             for (j = 0; j < subset_size; j++) {
34401ae86dd6SStefano Zampini               for (k = j; k < subset_size; k++) {
34411ae86dd6SStefano Zampini                 S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
34421ae86dd6SStefano Zampini                 St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
344308122e43SStefano Zampini               }
344408122e43SStefano Zampini             }
344508122e43SStefano Zampini           } else {
34469566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34479566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
344808122e43SStefano Zampini           }
34499566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
345008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3451792fecdfSBarry 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));
345208122e43SStefano Zampini #else
3453792fecdfSBarry 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));
345408122e43SStefano Zampini #endif
34559566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34569566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
345708122e43SStefano Zampini           B_neigs += B_neigs2;
345808122e43SStefano Zampini         }
345908122e43SStefano Zampini         if (B_ierr) {
346063a3b9bcSJacob Faibussowitsch           PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
346163a3b9bcSJacob 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);
346263a3b9bcSJacob 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);
346308122e43SStefano Zampini         }
3464fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
346563a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
346608122e43SStefano Zampini           for (j = 0; j < B_neigs; j++) {
346732fe681dSStefano Zampini             if (!sub_schurs->gdsw) {
346808122e43SStefano Zampini               if (eigs[j] == 0.0) {
34699566063dSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
347008122e43SStefano Zampini               } else {
347132fe681dSStefano Zampini                 if (upart) {
347263a3b9bcSJacob Faibussowitsch                   PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
34739d54b7f4SStefano Zampini                 } else {
347463a3b9bcSJacob Faibussowitsch                   PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1. / eigs[j + eigs_start])));
34759d54b7f4SStefano Zampini                 }
3476fd14bc51SStefano Zampini               }
347732fe681dSStefano Zampini             } else {
347832fe681dSStefano Zampini               double pg = (double)eigs[j + eigs_start];
347932fe681dSStefano Zampini               if (pg < 2 * PETSC_SMALL) pg = 0.0;
348032fe681dSStefano Zampini               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
348132fe681dSStefano Zampini             }
348208122e43SStefano Zampini           }
348308122e43SStefano Zampini         }
3484bd2a564bSStefano Zampini       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
3485aff50787SStefano Zampini     }
34866c3e6151SStefano Zampini     /* change the basis back to the original one */
34876c3e6151SStefano Zampini     if (sub_schurs->change) {
348872b8c272SStefano Zampini       Mat change, phi, phit;
34896c3e6151SStefano Zampini 
349003dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
34916c3e6151SStefano Zampini         PetscInt ii;
34926c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
349363a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
34946c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3495684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3496684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3497684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
349863a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3499684229deSStefano Zampini #else
350063a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3501684229deSStefano Zampini #endif
35026c3e6151SStefano Zampini           }
35036c3e6151SStefano Zampini         }
35046c3e6151SStefano Zampini       }
35059566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
35069566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
35079566063dSJacob Faibussowitsch       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &phi));
35089566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
35099566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
35109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
35116c3e6151SStefano Zampini     }
35128bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
35138bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
35149162d606SStefano Zampini     if (B_neigs) {
35159566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3516fd14bc51SStefano Zampini 
3517fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
35189552c7c7SStefano Zampini         PetscInt ii;
35199552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
352063a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
35219552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3522ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3523ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3524ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
352563a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3526ac47001eSStefano Zampini #else
352763a3b9bcSJacob 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]])));
3528ac47001eSStefano Zampini #endif
35299552c7c7SStefano Zampini           }
35309552c7c7SStefano Zampini         }
3531fd14bc51SStefano Zampini       }
35329566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
35339162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
35349162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
35359162d606SStefano Zampini       cum++;
353608122e43SStefano Zampini     }
35379566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
353808122e43SStefano Zampini     /* shift for next computation */
353908122e43SStefano Zampini     cumarray += subset_size * subset_size;
354008122e43SStefano Zampini   }
35411baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
354208122e43SStefano Zampini 
354308122e43SStefano Zampini   if (mss) {
354432fe681dSStefano Zampini     if (sub_schurs->gdsw) {
354532fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
354632fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
354732fe681dSStefano Zampini     } else {
35489566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
35499566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3550f6f667cfSStefano Zampini       /* destroy matrices (junk) */
35519566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
35529566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
355308122e43SStefano Zampini     }
355432fe681dSStefano Zampini   }
35551baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
35569566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
355708122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
35589566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
355908122e43SStefano Zampini #endif
356008122e43SStefano Zampini   if (pcbddc->dbg_flag) {
35611b968477SStefano Zampini     PetscInt maxneigs_r;
35621c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
356363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
356408122e43SStefano Zampini   }
35659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
356608122e43SStefano Zampini   PetscFunctionReturn(0);
356708122e43SStefano Zampini }
3568b1b3d7a2SStefano Zampini 
35699371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpSolvers(PC pc) {
35708629588bSStefano Zampini   PetscScalar *coarse_submat_vals;
3571c8587f34SStefano Zampini 
3572c8587f34SStefano Zampini   PetscFunctionBegin;
3573f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
35745e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
35759566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3576c8587f34SStefano Zampini 
3577684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
35780fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
35799566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3580c8587f34SStefano Zampini 
35818629588bSStefano Zampini   /*
35828629588bSStefano Zampini      Setup local correction and local part of coarse basis.
35838629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
35848629588bSStefano Zampini   */
35859566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat_vals));
35868629588bSStefano Zampini 
35878629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
35889566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat_vals));
35898629588bSStefano Zampini 
35908629588bSStefano Zampini   /* free */
35919566063dSJacob Faibussowitsch   PetscCall(PetscFree(coarse_submat_vals));
3592c8587f34SStefano Zampini   PetscFunctionReturn(0);
3593c8587f34SStefano Zampini }
3594c8587f34SStefano Zampini 
35959371c9d4SSatish Balay PetscErrorCode PCBDDCResetCustomization(PC pc) {
3596674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3597674ae819SStefano Zampini 
3598674ae819SStefano Zampini   PetscFunctionBegin;
35999566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
36009566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
36019566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
36029566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
36039566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
36049566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
36059566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
36069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
36079566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
36089566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
3609674ae819SStefano Zampini   PetscFunctionReturn(0);
3610674ae819SStefano Zampini }
3611674ae819SStefano Zampini 
36129371c9d4SSatish Balay PetscErrorCode PCBDDCResetTopography(PC pc) {
3613674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
36144f1b2e48SStefano Zampini   PetscInt i;
3615674ae819SStefano Zampini 
3616674ae819SStefano Zampini   PetscFunctionBegin;
36179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
36189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
36199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
36209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
36219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
36229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
36239566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
36249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
36259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
36269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
36279566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
3628*48a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
3629e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
36309566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
36319566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
3632c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
36338af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
36341c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
3635674ae819SStefano Zampini   PetscFunctionReturn(0);
3636674ae819SStefano Zampini }
3637674ae819SStefano Zampini 
36389371c9d4SSatish Balay PetscErrorCode PCBDDCResetSolvers(PC pc) {
3639674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3640674ae819SStefano Zampini 
3641674ae819SStefano Zampini   PetscFunctionBegin;
36429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
364358da7f69SStefano Zampini   if (pcbddc->coarse_phi_B) {
3644ca92afb2SStefano Zampini     PetscScalar *array;
36459566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &array));
36469566063dSJacob Faibussowitsch     PetscCall(PetscFree(array));
364758da7f69SStefano Zampini   }
36489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
36499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
36509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
36519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
36529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
36539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
36549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
36559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
36569566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
36579566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
36589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
36599566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
36609566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
36619566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
36629566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
36639566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
36649566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
36659566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
36669566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
36679566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
36689566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
36699566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
36709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
36719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
36729566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
36739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
36749566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
3675ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
3676ca92afb2SStefano Zampini     PetscInt i;
3677*48a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
36789566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
3679ca92afb2SStefano Zampini   }
36809566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
3681674ae819SStefano Zampini   PetscFunctionReturn(0);
3682674ae819SStefano Zampini }
3683674ae819SStefano Zampini 
36849371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc) {
36856bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
36866bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
36876bfb1811SStefano Zampini   VecType  impVecType;
36884f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
36896bfb1811SStefano Zampini 
36906bfb1811SStefano Zampini   PetscFunctionBegin;
36914f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3692b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
36939566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
3694e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
3695e7b262bdSStefano Zampini   /* R nodes */
3696e7b262bdSStefano Zampini   old_size = -1;
3697*48a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
3698e7b262bdSStefano Zampini   if (n_R != old_size) {
36999566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
37009566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
37019566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
37029566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
37039566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
37049566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
3705e7b262bdSStefano Zampini   }
3706e7b262bdSStefano Zampini   /* local primal dofs */
3707e7b262bdSStefano Zampini   old_size = -1;
3708*48a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
3709e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
37109566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
37119566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
37129566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
37139566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
3714e7b262bdSStefano Zampini   }
3715e7b262bdSStefano Zampini   /* local explicit constraints */
3716e7b262bdSStefano Zampini   old_size = -1;
3717*48a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
3718e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
37199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
37209566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
37219566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
37229566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
372383b7ccabSStefano Zampini   }
37246bfb1811SStefano Zampini   PetscFunctionReturn(0);
37256bfb1811SStefano Zampini }
37266bfb1811SStefano Zampini 
37279371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpCorrection(PC pc, PetscScalar **coarse_submat_vals_n) {
372825084f0cSStefano Zampini   /* pointers to pcis and pcbddc */
372988ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
373088ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
3731d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
373225084f0cSStefano Zampini   /* submatrices of local problem */
373380677318SStefano Zampini   Mat             A_RV, A_VR, A_VV, local_auxmat2_R;
373406656605SStefano Zampini   /* submatrices of local coarse problem */
373506656605SStefano Zampini   Mat             S_VV, S_CV, S_VC, S_CC;
373625084f0cSStefano Zampini   /* working matrices */
373706656605SStefano Zampini   Mat             C_CR;
373825084f0cSStefano Zampini   /* additional working stuff */
373906656605SStefano Zampini   PC              pc_R;
3740c58f9fdbSStefano Zampini   Mat             F, Brhs = NULL;
37415cbda25cSStefano Zampini   Vec             dummy_vec;
37427ebab0bbSStefano Zampini   PetscBool       isLU, isCHOL, need_benign_correction, sparserhs;
374325084f0cSStefano Zampini   PetscScalar    *coarse_submat_vals; /* TODO: use a PETSc matrix */
374406656605SStefano Zampini   PetscScalar    *work;
374506656605SStefano Zampini   PetscInt       *idx_V_B;
3746ffd830a3SStefano Zampini   PetscInt        lda_rhs, n, n_vertices, n_constraints, *p0_lidx_I;
374706656605SStefano Zampini   PetscInt        i, n_R, n_D, n_B;
374806656605SStefano Zampini   PetscScalar     one = 1.0, m_one = -1.0;
374988ebb749SStefano Zampini 
375088ebb749SStefano Zampini   PetscFunctionBegin;
37517827d75bSBarry 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");
37529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
3753ffd830a3SStefano Zampini 
3754ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
3755b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
37564f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
3757b371cd4fSStefano Zampini   n_B           = pcis->n_B;
3758b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
375988ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
376088ebb749SStefano Zampini 
376188ebb749SStefano Zampini   /* vertices in boundary numbering */
37629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
37639566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
376463a3b9bcSJacob 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);
376588ebb749SStefano Zampini 
376606656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
37679566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pcbddc->local_primal_size * pcbddc->local_primal_size, &coarse_submat_vals));
37689566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_vertices, coarse_submat_vals, &S_VV));
37699566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VV, pcbddc->local_primal_size));
37709566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_vertices, coarse_submat_vals + n_vertices, &S_CV));
37719566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CV, pcbddc->local_primal_size));
37729566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_constraints, coarse_submat_vals + pcbddc->local_primal_size * n_vertices, &S_VC));
37739566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VC, pcbddc->local_primal_size));
37749566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_constraints, coarse_submat_vals + (pcbddc->local_primal_size + 1) * n_vertices, &S_CC));
37759566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CC, pcbddc->local_primal_size));
377606656605SStefano Zampini 
377706656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
37789566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
37799566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
37809566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
37819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
3782ffd830a3SStefano Zampini   lda_rhs                = n_R;
3783a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
37847ebab0bbSStefano Zampini   if (isLU || isCHOL) {
37859566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
3786b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
3787df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3788d62866d3SStefano Zampini     MatFactorType      type;
3789d62866d3SStefano Zampini 
3790df4d28bfSStefano Zampini     F = reuse_solver->F;
37919566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
3792d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
37937ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
37949566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
379522db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
37967ebab0bbSStefano Zampini   } else F = NULL;
379706656605SStefano Zampini 
3798c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
3799c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
3800c58f9fdbSStefano Zampini   if (F) {
3801ea799195SBarry Smith     MatSolverType solver;
3802c58f9fdbSStefano Zampini 
38039566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
38049566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
3805c58f9fdbSStefano Zampini   }
3806c58f9fdbSStefano Zampini 
3807ffd830a3SStefano Zampini   /* allocate workspace */
3808ffd830a3SStefano Zampini   n = 0;
38099371c9d4SSatish Balay   if (n_constraints) { n += lda_rhs * n_constraints; }
3810ffd830a3SStefano Zampini   if (n_vertices) {
3811ffd830a3SStefano Zampini     n = PetscMax(2 * lda_rhs * n_vertices, n);
3812ffd830a3SStefano Zampini     n = PetscMax((lda_rhs + n_B) * n_vertices, n);
3813ffd830a3SStefano Zampini   }
38149371c9d4SSatish Balay   if (!pcbddc->symmetric_primal) { n = PetscMax(2 * lda_rhs * pcbddc->local_primal_size, n); }
38159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &work));
3816ffd830a3SStefano Zampini 
38175cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
38185cbda25cSStefano Zampini   dummy_vec = NULL;
38195cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
38209566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
38219566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
38229566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
38235cbda25cSStefano Zampini   }
38245cbda25cSStefano Zampini 
38259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
38269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
38277ebab0bbSStefano Zampini 
382888ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
382988ebb749SStefano Zampini   if (n_constraints) {
3830837cedc9SStefano Zampini     Mat M3, C_B;
383106656605SStefano Zampini     IS  is_aux;
383206656605SStefano Zampini 
383325084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
38349566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_aux));
38359566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
38369566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
383788ebb749SStefano Zampini 
383880677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
383980677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
3840c58f9fdbSStefano Zampini     if (!sparserhs) {
38419566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(work, lda_rhs * n_constraints));
384288ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
384306656605SStefano Zampini         const PetscScalar *row_cmat_values;
384406656605SStefano Zampini         const PetscInt    *row_cmat_indices;
384506656605SStefano Zampini         PetscInt           size_of_constraint, j;
384688ebb749SStefano Zampini 
38479566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
38489371c9d4SSatish Balay         for (j = 0; j < size_of_constraint; j++) { work[row_cmat_indices[j] + i * lda_rhs] = -row_cmat_values[j]; }
38499566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
385006656605SStefano Zampini       }
38519566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &Brhs));
3852c58f9fdbSStefano Zampini     } else {
3853c58f9fdbSStefano Zampini       Mat tC_CR;
3854c58f9fdbSStefano Zampini 
38559566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
3856c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
3857c58f9fdbSStefano Zampini         PetscScalar *aa;
3858c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
3859c58f9fdbSStefano Zampini         PetscBool    done;
3860c58f9fdbSStefano Zampini 
38619566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
386228b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
38639566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
38649566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
38659566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
386628b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
3867c58f9fdbSStefano Zampini       } else {
38689566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
3869c58f9fdbSStefano Zampini         tC_CR = C_CR;
3870c58f9fdbSStefano Zampini       }
38719566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
38729566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
3873c58f9fdbSStefano Zampini     }
38749566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, NULL, &local_auxmat2_R));
387506656605SStefano Zampini     if (F) {
3876a3df083aSStefano Zampini       if (need_benign_correction) {
3877df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3878a3df083aSStefano Zampini 
387972b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
38809566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
3881a3df083aSStefano Zampini       }
38829566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
3883a3df083aSStefano Zampini       if (need_benign_correction) {
3884a3df083aSStefano Zampini         PetscScalar       *marr;
3885df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3886a3df083aSStefano Zampini 
38879566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
38885cbda25cSStefano Zampini         if (lda_rhs != n_R) {
38895cbda25cSStefano Zampini           for (i = 0; i < n_constraints; i++) {
38909566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
38919566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
38929566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
38935cbda25cSStefano Zampini           }
38945cbda25cSStefano Zampini         } else {
3895a3df083aSStefano Zampini           for (i = 0; i < n_constraints; i++) {
38969566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
38979566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
38989566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
3899a3df083aSStefano Zampini           }
39005cbda25cSStefano Zampini         }
39019566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
3902a3df083aSStefano Zampini       }
390306656605SStefano Zampini     } else {
390480677318SStefano Zampini       PetscScalar *marr;
390580677318SStefano Zampini 
39069566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
390706656605SStefano Zampini       for (i = 0; i < n_constraints; i++) {
39089566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
39099566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
39109566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
39119566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
39129566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
39139566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
391406656605SStefano Zampini       }
39159566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
391606656605SStefano Zampini     }
39171baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
39189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
391980677318SStefano Zampini     if (!pcbddc->switch_static) {
39209566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_constraints, NULL, &pcbddc->local_auxmat2));
392180677318SStefano Zampini       for (i = 0; i < n_constraints; i++) {
3922ab2d12f3SJunchao Zhang         Vec r, b;
39239566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
39249566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
39259566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
39269566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
39279566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
39289566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
392980677318SStefano Zampini       }
39309566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
393180677318SStefano Zampini     } else {
3932ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
3933ffd830a3SStefano Zampini         IS dummy;
3934ffd830a3SStefano Zampini 
39359566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &dummy));
39369566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(local_auxmat2_R, dummy, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
39379566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
3938ffd830a3SStefano Zampini       } else {
39399566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
394080677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
3941ffd830a3SStefano Zampini       }
39429566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
394380677318SStefano Zampini     }
39449566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
394580677318SStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
39469566063dSJacob Faibussowitsch     PetscCall(MatScale(M3, m_one));
394780677318SStefano Zampini     if (isCHOL) {
39489566063dSJacob Faibussowitsch       PetscCall(MatCholeskyFactor(M3, NULL, NULL));
394980677318SStefano Zampini     } else {
39509566063dSJacob Faibussowitsch       PetscCall(MatLUFactor(M3, NULL, NULL, NULL));
395180677318SStefano Zampini     }
39529566063dSJacob Faibussowitsch     PetscCall(MatSeqDenseInvertFactors_Private(M3));
395380677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
39549566063dSJacob Faibussowitsch     PetscCall(MatMatMult(M3, C_B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->local_auxmat1));
39559566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
39569566063dSJacob Faibussowitsch     PetscCall(MatCopy(M3, S_CC, SAME_NONZERO_PATTERN)); /* S_CC can have a different LDA, MatMatSolve doesn't support it */
39579566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M3));
3958f4ddd8eeSStefano Zampini   }
3959fc227af8SStefano Zampini 
3960fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
396188ebb749SStefano Zampini   if (n_vertices) {
39627ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
39637ebab0bbSStefano Zampini     PetscBool oldpin;
39647ebab0bbSStefano Zampini #endif
39657ebab0bbSStefano Zampini     PetscBool isaij;
396606656605SStefano Zampini     IS        is_aux;
39673a50541eSStefano Zampini 
3968b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
39696816873aSStefano Zampini       IS tis;
39706816873aSStefano Zampini 
39719566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
39729566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
39739566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
39749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
39756816873aSStefano Zampini     } else {
39769566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
39776816873aSStefano Zampini     }
39787ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
3979b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
39807ebab0bbSStefano Zampini #endif
39819566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
39829566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
39839566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
39849566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A_VR, MATSEQAIJ, &isaij));
39857ebab0bbSStefano Zampini     if (!isaij) { /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
39869566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
39877ebab0bbSStefano Zampini     }
39889566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
39897ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
39909566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
39917ebab0bbSStefano Zampini #endif
39929566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
399388ebb749SStefano Zampini   }
399488ebb749SStefano Zampini 
399588ebb749SStefano Zampini   /* Matrix of coarse basis functions (local) */
3996f4ddd8eeSStefano Zampini   if (pcbddc->coarse_phi_B) {
399706656605SStefano Zampini     PetscInt on_B, on_primal, on_D = n_D;
3998*48a46eb9SPierre Jolivet     if (pcbddc->coarse_phi_D) PetscCall(MatGetSize(pcbddc->coarse_phi_D, &on_D, NULL));
39999566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pcbddc->coarse_phi_B, &on_B, &on_primal));
400006656605SStefano Zampini     if (on_B != n_B || on_primal != pcbddc->local_primal_size || on_D != n_D) {
400106656605SStefano Zampini       PetscScalar *marray;
400206656605SStefano Zampini 
40039566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &marray));
40049566063dSJacob Faibussowitsch       PetscCall(PetscFree(marray));
40059566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
40069566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
40079566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
40089566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
4009f4ddd8eeSStefano Zampini     }
4010f4ddd8eeSStefano Zampini   }
401106656605SStefano Zampini 
4012f4ddd8eeSStefano Zampini   if (!pcbddc->coarse_phi_B) {
4013a6e023c1Sstefano_zampini     PetscScalar *marr;
401488ebb749SStefano Zampini 
4015a6e023c1Sstefano_zampini     /* memory size */
401606656605SStefano Zampini     n = n_B * pcbddc->local_primal_size;
4017a6e023c1Sstefano_zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) n += n_D * pcbddc->local_primal_size;
4018a6e023c1Sstefano_zampini     if (!pcbddc->symmetric_primal) n *= 2;
40199566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &marr));
40209566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_B));
4021a6e023c1Sstefano_zampini     marr += n_B * pcbddc->local_primal_size;
40228eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
40239566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_D));
4024a6e023c1Sstefano_zampini       marr += n_D * pcbddc->local_primal_size;
402588ebb749SStefano Zampini     }
40263301b35fSStefano Zampini     if (!pcbddc->symmetric_primal) {
40279566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_B));
4028a6e023c1Sstefano_zampini       marr += n_B * pcbddc->local_primal_size;
4029*48a46eb9SPierre Jolivet       if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_D));
403088ebb749SStefano Zampini     } else {
40319566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
4032c0553b1fSStefano Zampini       pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
40331b968477SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
40349566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
4035c0553b1fSStefano Zampini         pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
4036c0553b1fSStefano Zampini       }
403788ebb749SStefano Zampini     }
403806656605SStefano Zampini   }
4039019a44ceSStefano Zampini 
404006656605SStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
40414f1b2e48SStefano Zampini   p0_lidx_I = NULL;
40424f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4043d12edf2fSStefano Zampini     const PetscInt *idxs;
4044d12edf2fSStefano Zampini 
40459566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
40469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
4047*48a46eb9SPierre 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]));
40489566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4049d12edf2fSStefano Zampini   }
4050d16cbb6bSStefano Zampini 
405106656605SStefano Zampini   /* vertices */
405206656605SStefano Zampini   if (n_vertices) {
4053c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
405416f15bc4SStefano Zampini 
40559566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VV, MATDENSE, MAT_INPLACE_MATRIX, &A_VV));
405604708bb6SStefano Zampini 
405716f15bc4SStefano Zampini     if (n_R) {
405814393ed6SStefano Zampini       Mat                A_RRmA_RV, A_RV_bcorr = NULL, S_VVt; /* S_VVt with LDA=N */
405906656605SStefano Zampini       PetscBLASInt       B_N, B_one            = 1;
40601683a169SBarry Smith       const PetscScalar *x;
40611683a169SBarry Smith       PetscScalar       *y;
406206656605SStefano Zampini 
40639566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
406414393ed6SStefano Zampini       if (need_benign_correction) {
406514393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
406614393ed6SStefano Zampini         IS                     is_p0;
406714393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
406814393ed6SStefano Zampini 
40699566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
40709566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
40719566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
407263a3b9bcSJacob 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);
40739566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
40749566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
40759566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
40769566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
407714393ed6SStefano Zampini       }
407814393ed6SStefano Zampini 
40799566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work, &A_RRmA_RV));
4080c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
4081ffd830a3SStefano Zampini         if (lda_rhs == n_R) {
40829566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4083ffd830a3SStefano Zampini         } else {
4084ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4085ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4086ca92afb2SStefano Zampini           PetscInt        n;
4087ca92afb2SStefano Zampini           PetscBool       flg_row;
4088ffd830a3SStefano Zampini 
4089ca92afb2SStefano Zampini           array = work + lda_rhs * n_vertices;
40909566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(array, lda_rhs * n_vertices));
40919566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
40929566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
40939566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4094ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4095ca92afb2SStefano Zampini             PetscInt j;
4096ca92afb2SStefano Zampini             for (j = xadj[i]; j < xadj[i + 1]; j++) array[lda_rhs * adjncy[j] + i] = av[j];
4097ffd830a3SStefano Zampini           }
40989566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
40999566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
41009566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, array, &A_RV));
4101ffd830a3SStefano Zampini         }
4102a3df083aSStefano Zampini         if (need_benign_correction) {
4103df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4104a3df083aSStefano Zampini           PetscScalar       *marr;
4105a3df083aSStefano Zampini 
41069566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
410714393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
410814393ed6SStefano Zampini 
410914393ed6SStefano Zampini                  | 0 0  0 | (V)
411014393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
411114393ed6SStefano Zampini                  | 0 0 -1 | (p0)
411214393ed6SStefano Zampini 
411314393ed6SStefano Zampini           */
4114df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
411514393ed6SStefano Zampini             const PetscScalar *vals;
411614393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
411714393ed6SStefano Zampini             PetscInt           n, j, nz;
411814393ed6SStefano Zampini 
41199566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
41209566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
41219566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
412214393ed6SStefano Zampini             for (j = 0; j < n; j++) {
412314393ed6SStefano Zampini               PetscScalar val = vals[j];
412414393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
412514393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
412614393ed6SStefano Zampini             }
41279566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
41289566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
412914393ed6SStefano Zampini           }
41309566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
413172b8c272SStefano Zampini         }
41329566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4133c58f9fdbSStefano Zampini         Brhs = A_RV;
4134c58f9fdbSStefano Zampini       } else {
4135c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4136c58f9fdbSStefano Zampini 
4137c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4138fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
41399566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4140c58f9fdbSStefano Zampini         } else {
4141c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
41429566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
41439566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4144c58f9fdbSStefano Zampini           A_RVT = A_VR;
4145c58f9fdbSStefano Zampini         }
4146c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4147c58f9fdbSStefano Zampini           PetscScalar *aa;
4148c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4149c58f9fdbSStefano Zampini           PetscBool    done;
4150c58f9fdbSStefano Zampini 
41519566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
415228b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
41539566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
41549566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
41559566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
415628b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4157c58f9fdbSStefano Zampini         } else {
41589566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4159c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4160c58f9fdbSStefano Zampini         }
41619566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
41629566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
41639566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4164c58f9fdbSStefano Zampini       }
416572b8c272SStefano Zampini       if (F) {
416614393ed6SStefano Zampini         /* need to correct the rhs */
416772b8c272SStefano Zampini         if (need_benign_correction) {
416872b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
416972b8c272SStefano Zampini           PetscScalar       *marr;
417072b8c272SStefano Zampini 
41719566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
41725cbda25cSStefano Zampini           if (lda_rhs != n_R) {
41735cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
41749566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
41759566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
41769566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
41775cbda25cSStefano Zampini             }
41785cbda25cSStefano Zampini           } else {
4179a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
41809566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
41819566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
41829566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4183a3df083aSStefano Zampini             }
41845cbda25cSStefano Zampini           }
41859566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4186a3df083aSStefano Zampini         }
41879566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
41881baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
418914393ed6SStefano Zampini         /* need to correct the solution */
4190a3df083aSStefano Zampini         if (need_benign_correction) {
4191df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4192a3df083aSStefano Zampini           PetscScalar       *marr;
4193a3df083aSStefano Zampini 
41949566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
41955cbda25cSStefano Zampini           if (lda_rhs != n_R) {
41965cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
41979566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
41989566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
41999566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
42005cbda25cSStefano Zampini             }
42015cbda25cSStefano Zampini           } else {
4202a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42039566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
42049566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
42059566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4206a3df083aSStefano Zampini             }
42075cbda25cSStefano Zampini           }
42089566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4209a3df083aSStefano Zampini         }
421006656605SStefano Zampini       } else {
42119566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(Brhs, &y));
421206656605SStefano Zampini         for (i = 0; i < n_vertices; i++) {
42139566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, y + i * lda_rhs));
42149566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * lda_rhs));
42159566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
42169566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
42179566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
42189566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
421906656605SStefano Zampini         }
42209566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(Brhs, &y));
422106656605SStefano Zampini       }
42229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
42239566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4224ffd830a3SStefano Zampini       /* S_VV and S_CV */
422506656605SStefano Zampini       if (n_constraints) {
422606656605SStefano Zampini         Mat B;
422780677318SStefano Zampini 
42289566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(work + lda_rhs * n_vertices, n_B * n_vertices));
422980677318SStefano Zampini         for (i = 0; i < n_vertices; i++) {
42309566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
42319566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcis->vec1_B, work + lda_rhs * n_vertices + i * n_B));
42329566063dSJacob Faibussowitsch           PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
42339566063dSJacob Faibussowitsch           PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
42349566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcis->vec1_B));
42359566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
423680677318SStefano Zampini         }
42379566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_vertices, work + lda_rhs * n_vertices, &B));
42384222ddf1SHong Zhang         /* Reuse dense S_C = pcbddc->local_auxmat1 * B */
42399566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(pcbddc->local_auxmat1, B, NULL, S_CV));
42409566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
42419566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
42429566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
42439566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
42449566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
42454222ddf1SHong Zhang 
42469566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
42479566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work + lda_rhs * n_vertices, &B));
42484222ddf1SHong Zhang         /* Reuse B = local_auxmat2_R * S_CV */
42499566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CV, NULL, B));
42509566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
42519566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
42529566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
42539566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
42544222ddf1SHong Zhang 
42559566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
42569566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(lda_rhs * n_vertices, &B_N));
4257792fecdfSBarry Smith         PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, work + lda_rhs * n_vertices, &B_one, work, &B_one));
42589566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
425906656605SStefano Zampini       }
4260ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
42619566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RRmA_RV));
42629566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, work, &A_RRmA_RV));
42639566063dSJacob Faibussowitsch         PetscCall(MatDenseSetLDA(A_RRmA_RV, lda_rhs));
4264ffd830a3SStefano Zampini       }
42659566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VVt));
426614393ed6SStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
426714393ed6SStefano Zampini       if (need_benign_correction) {
4268df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
426914393ed6SStefano Zampini         PetscScalar       *marr, *sums;
427014393ed6SStefano Zampini 
42719566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
42729566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(S_VVt, &marr));
4273df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
427414393ed6SStefano Zampini           const PetscScalar *vals;
427514393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
427614393ed6SStefano Zampini           PetscInt           n, j, nz;
427714393ed6SStefano Zampini 
42789566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
42799566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
428014393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
428114393ed6SStefano Zampini             PetscInt k;
428214393ed6SStefano Zampini             sums[j] = 0.;
428314393ed6SStefano Zampini             for (k = 0; k < nz; k++) sums[j] += work[idxs_zero[k] + j * lda_rhs];
428414393ed6SStefano Zampini           }
42859566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
428614393ed6SStefano Zampini           for (j = 0; j < n; j++) {
428714393ed6SStefano Zampini             PetscScalar val = vals[j];
428814393ed6SStefano Zampini             PetscInt    k;
42899371c9d4SSatish Balay             for (k = 0; k < n_vertices; k++) { marr[idxs[j] + k * n_vertices] += val * sums[k]; }
429014393ed6SStefano Zampini           }
42919566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
42929566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
429314393ed6SStefano Zampini         }
42949566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
42959566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(S_VVt, &marr));
42969566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
429714393ed6SStefano Zampini       }
42989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RRmA_RV));
42999566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(n_vertices * n_vertices, &B_N));
43009566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(A_VV, &x));
43019566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(S_VVt, &y));
4302792fecdfSBarry Smith       PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, x, &B_one, y, &B_one));
43039566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(A_VV, &x));
43049566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(S_VVt, &y));
43059566063dSJacob Faibussowitsch       PetscCall(MatCopy(S_VVt, S_VV, SAME_NONZERO_PATTERN));
43069566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_VVt));
4307019a44ceSStefano Zampini     } else {
43089566063dSJacob Faibussowitsch       PetscCall(MatCopy(A_VV, S_VV, SAME_NONZERO_PATTERN));
4309d16cbb6bSStefano Zampini     }
43109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_VV));
4311d16cbb6bSStefano Zampini 
431206656605SStefano Zampini     /* coarse basis functions */
431306656605SStefano Zampini     for (i = 0; i < n_vertices; i++) {
4314ab2d12f3SJunchao Zhang       Vec         v;
4315ab2d12f3SJunchao Zhang       PetscScalar one = 1.0, zero = 0.0;
431616f15bc4SStefano Zampini 
43179566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
43189566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i, &v));
43199566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43209566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4321ab2d12f3SJunchao Zhang       if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4322ab2d12f3SJunchao Zhang         PetscMPIInt rank;
43239566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), &rank));
432408401ef6SPierre Jolivet         PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4325ab2d12f3SJunchao Zhang       }
43269566063dSJacob Faibussowitsch       PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
43279566063dSJacob Faibussowitsch       PetscCall(VecAssemblyBegin(v)); /* If v is on device, hope VecSetValues() eventually implemented by a host to device memcopy */
43289566063dSJacob Faibussowitsch       PetscCall(VecAssemblyEnd(v));
43299566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i, &v));
433006656605SStefano Zampini 
433106656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
43324f1b2e48SStefano Zampini         PetscInt j;
43334f1b2e48SStefano Zampini 
43349566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i, &v));
43359566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43369566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4337ab2d12f3SJunchao Zhang         if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4338ab2d12f3SJunchao Zhang           PetscMPIInt rank;
43399566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), &rank));
434008401ef6SPierre Jolivet           PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4341ab2d12f3SJunchao Zhang         }
43429566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
43439566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
43449566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
43459566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i, &v));
434606656605SStefano Zampini       }
43479566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
434806656605SStefano Zampini     }
434904708bb6SStefano Zampini     /* if n_R == 0 the object is not destroyed */
43509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_RV));
435106656605SStefano Zampini   }
43529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
435306656605SStefano Zampini 
435406656605SStefano Zampini   if (n_constraints) {
435506656605SStefano Zampini     Mat B;
435606656605SStefano Zampini 
43579566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &B));
43589566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
43599566063dSJacob Faibussowitsch     PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CC, NULL, B));
43609566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
43619566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
43629566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
43639566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
4364a961b312SStefano Zampini 
43659566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
436606656605SStefano Zampini     if (n_vertices) {
436703dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
43687fb60732SBarry Smith         PetscCall(MatTransposeSetPrecursor(S_CV, S_VC));
43699566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_CV, MAT_REUSE_MATRIX, &S_VC));
437080677318SStefano Zampini       } else {
437180677318SStefano Zampini         Mat S_VCt;
437280677318SStefano Zampini 
4373ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
43749566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&B));
43759566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_constraints, work, &B));
43769566063dSJacob Faibussowitsch           PetscCall(MatDenseSetLDA(B, lda_rhs));
4377ffd830a3SStefano Zampini         }
43789566063dSJacob Faibussowitsch         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VCt));
43799566063dSJacob Faibussowitsch         PetscCall(MatCopy(S_VCt, S_VC, SAME_NONZERO_PATTERN));
43809566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCt));
438180677318SStefano Zampini       }
438206656605SStefano Zampini     }
43839566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
438406656605SStefano Zampini     /* coarse basis functions */
438506656605SStefano Zampini     for (i = 0; i < n_constraints; i++) {
4386ab2d12f3SJunchao Zhang       Vec v;
438706656605SStefano Zampini 
43889566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
43899566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
43909566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43919566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43929566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
439306656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
43944f1b2e48SStefano Zampini         PetscInt    j;
4395ab2d12f3SJunchao Zhang         PetscScalar zero = 0.0;
43969566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
43979566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43989566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43999566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
44009566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
44019566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
44029566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
440306656605SStefano Zampini       }
44049566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
440506656605SStefano Zampini     }
440606656605SStefano Zampini   }
4407*48a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&local_auxmat2_R));
44089566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
440972b8c272SStefano Zampini 
441072b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
441172b8c272SStefano Zampini   if (pcbddc->benign_n) {
441272b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
441372b8c272SStefano Zampini     IS                 is_dummy;
44141683a169SBarry Smith     const PetscScalar *data;
441572b8c272SStefano Zampini     PetscInt           j;
441672b8c272SStefano Zampini 
44179566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
44189566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
44199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
44209566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
44219566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
44229566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
442372b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
442472b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
442572b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
442672b8c272SStefano Zampini         coarse_submat_vals[primal_idx * pcbddc->local_primal_size + i] = data[i * pcbddc->benign_n + j];
442772b8c272SStefano Zampini         coarse_submat_vals[i * pcbddc->local_primal_size + primal_idx] = data[i * pcbddc->benign_n + j];
442872b8c272SStefano Zampini       }
442972b8c272SStefano Zampini     }
44309566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
44319566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
44329566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
443372b8c272SStefano Zampini   }
4434019a44ceSStefano Zampini 
443506656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
44363301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
4437ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
4438ffd830a3SStefano Zampini     PetscScalar *marray;
443906656605SStefano Zampini 
444006656605SStefano Zampini     if (n_constraints) {
4441ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
444206656605SStefano Zampini 
44439566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
44449566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
44459566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_C));
44469566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
444706656605SStefano Zampini       if (n_vertices) {
4448ffd830a3SStefano Zampini         Mat S_VCT;
444906656605SStefano Zampini 
44509566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
44519566063dSJacob Faibussowitsch         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_V));
44529566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
445306656605SStefano Zampini       }
44549566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
44555b782168SStefano Zampini     } else {
44569566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
445706656605SStefano Zampini     }
445816f15bc4SStefano Zampini     if (n_vertices && n_R) {
4459ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
4460ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
4461ffd830a3SStefano Zampini       PetscInt        n;
4462ffd830a3SStefano Zampini       PetscBool       flg_row;
446306656605SStefano Zampini 
4464ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
44659566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
44669566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
44679566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
44689566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4469ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
4470ffd830a3SStefano Zampini         PetscInt j;
4471ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
4472ffd830a3SStefano Zampini       }
44739566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
44749566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
44759566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
447606656605SStefano Zampini     }
447706656605SStefano Zampini 
4478ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
4479abc8f43dSstefano_zampini     if (n_vertices) {
44809566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4481ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
44829566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
44839566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
44849566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
44859566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
44869566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
44879566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
448806656605SStefano Zampini       }
44899566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
4490abc8f43dSstefano_zampini     }
44915b782168SStefano Zampini     if (B_C) {
44929566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
4493ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
44949566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
44959566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
44969566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
44979566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
44989566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
44999566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
450006656605SStefano Zampini       }
45019566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
45025b782168SStefano Zampini     }
450306656605SStefano Zampini     /* coarse basis functions */
450406656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
4505ab2d12f3SJunchao Zhang       Vec v;
450606656605SStefano Zampini 
45079566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
45089566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
45099566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45109566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
451106656605SStefano Zampini       if (i < n_vertices) {
4512ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
45139566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
45149566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
45159566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
451606656605SStefano Zampini       }
45179566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
451806656605SStefano Zampini 
451906656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
45209566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
45219566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45229566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45239566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
452406656605SStefano Zampini       }
45259566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
452606656605SStefano Zampini     }
45279566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
45289566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
452906656605SStefano Zampini   }
4530a6e023c1Sstefano_zampini 
4531d62866d3SStefano Zampini   /* free memory */
45329566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
45339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VV));
45349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
45359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
45369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
45379566063dSJacob Faibussowitsch   PetscCall(PetscFree(work));
4538*48a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
4539*48a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
45409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
45418ead10e4SStefano Zampini 
454288ebb749SStefano Zampini   /* Checking coarse_sub_mat and coarse basis functios */
454388ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
454488ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
4545d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
454688ebb749SStefano Zampini     Mat       coarse_sub_mat;
454725084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
454888ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
454988ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
455088ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
45518bec7fa6SStefano Zampini     Mat       C_B, CPHI;
45528bec7fa6SStefano Zampini     IS        is_dummy;
45538bec7fa6SStefano Zampini     Vec       mones;
455488ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
455588ebb749SStefano Zampini     PetscReal real_value;
455688ebb749SStefano Zampini 
4557a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
4558a3df083aSStefano Zampini       Mat A;
45599566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
45609566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
45619566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
45629566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
45639566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
45649566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
4565a3df083aSStefano Zampini     } else {
45669566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
45679566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
45689566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
45699566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
4570a3df083aSStefano Zampini     }
45719566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
45729566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
4573ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
45749566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
45759566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
457688ebb749SStefano Zampini     }
45779566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_sub_mat));
457888ebb749SStefano Zampini 
45799566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
45809566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
45819566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
4582ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
45839566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
45849566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
45859566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
45869566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
45879566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
45889566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
45899566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
45909566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
45919566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
45929566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
45939566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
45949566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
459588ebb749SStefano Zampini     } else {
45969566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
45979566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
45989566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
45999566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
46009566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46019566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46029566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
46039566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
460488ebb749SStefano Zampini     }
46059566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
46069566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
46079566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
46089566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
46094f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
4610fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
46111683a169SBarry Smith       const PetscScalar *data2;
46121683a169SBarry Smith       PetscScalar       *data;
46134f1b2e48SStefano Zampini       PetscInt           j;
4614d12edf2fSStefano Zampini 
46159566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
46169566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
46179566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
46189566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
46199566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
46209566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
46214f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
46224f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
4623d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
46244f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
46254f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
46264f1b2e48SStefano Zampini         }
4627d12edf2fSStefano Zampini       }
46289566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
46299566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
46309566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
46319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
46329566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
4633d12edf2fSStefano Zampini     }
4634d12edf2fSStefano Zampini #if 0
4635d12edf2fSStefano Zampini   {
4636d12edf2fSStefano Zampini     PetscViewer viewer;
4637d12edf2fSStefano Zampini     char filename[256];
4638ffd830a3SStefano Zampini     sprintf(filename,"details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level);
46399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
46409566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
46419566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coarse_sub_mat,"computed"));
46429566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_sub_mat,viewer));
46439566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)TM1,"projected"));
46449566063dSJacob Faibussowitsch     PetscCall(MatView(TM1,viewer));
4645a7414863SStefano Zampini     if (pcbddc->coarse_phi_B) {
46469566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
46479566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
464872b8c272SStefano Zampini     }
4649ffd830a3SStefano Zampini     if (pcbddc->coarse_phi_D) {
46509566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
46519566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
4652ffd830a3SStefano Zampini     }
4653ffd830a3SStefano Zampini     if (pcbddc->coarse_psi_B) {
46549566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
46559566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
4656ffd830a3SStefano Zampini     }
465772b8c272SStefano Zampini     if (pcbddc->coarse_psi_D) {
46589566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
46599566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
4660ffd830a3SStefano Zampini     }
46619566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
46629566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->local_mat,viewer));
46639566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
46649566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
46659566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
46669566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_I_local,viewer));
46679566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
46689566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_B_local,viewer));
46699566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
46709566063dSJacob Faibussowitsch     PetscCall(ISView(pcbddc->is_R_local,viewer));
46719566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
4672d12edf2fSStefano Zampini   }
4673d12edf2fSStefano Zampini #endif
46749566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, m_one, coarse_sub_mat, DIFFERENT_NONZERO_PATTERN));
46759566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
46769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
467763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
46788bec7fa6SStefano Zampini 
46798bec7fa6SStefano Zampini     /* check constraints */
46809566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
46819566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
46824f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
46839566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
4684a00504b5SStefano Zampini     } else {
4685a00504b5SStefano Zampini       PetscScalar *data;
4686a00504b5SStefano Zampini       Mat          tmat;
46879566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
46889566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
46899566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
46909566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
46919566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
4692a00504b5SStefano Zampini     }
46939566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
46949566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
46959566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
46969566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
469763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
4698ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
46999566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
47009566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
47019566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
47029566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
470363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
470488ebb749SStefano Zampini     }
47059566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
47069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
47079566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
47089566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
47099566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
47109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
47119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
47129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
47139566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
47149566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
47159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
47169566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
47179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
47189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
47199566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
4720ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
47219566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
47229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
472388ebb749SStefano Zampini     }
47249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_sub_mat));
472588ebb749SStefano Zampini   }
47267ebab0bbSStefano Zampini   /* FINAL CUDA support (we cannot currently mix viennacl and cuda vectors */
47277ebab0bbSStefano Zampini   {
47287ebab0bbSStefano Zampini     PetscBool gpu;
47297ebab0bbSStefano Zampini 
47309566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcis->vec1_N, VECSEQCUDA, &gpu));
47317ebab0bbSStefano Zampini     if (gpu) {
4732*48a46eb9SPierre Jolivet       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
4733*48a46eb9SPierre Jolivet       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
4734*48a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
4735*48a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
4736*48a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
4737*48a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
47387ebab0bbSStefano Zampini     }
47397ebab0bbSStefano Zampini   }
47408629588bSStefano Zampini   /* get back data */
47418629588bSStefano Zampini   *coarse_submat_vals_n = coarse_submat_vals;
474288ebb749SStefano Zampini   PetscFunctionReturn(0);
474388ebb749SStefano Zampini }
474488ebb749SStefano Zampini 
47459371c9d4SSatish Balay PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B) {
4746d65f70fdSStefano Zampini   Mat      *work_mat;
4747d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
4748d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
4749c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
4750aa0d41d4SStefano Zampini 
4751aa0d41d4SStefano Zampini   PetscFunctionBegin;
47529566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
47539566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
47549566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
47559566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
4756aa0d41d4SStefano Zampini 
4757d65f70fdSStefano Zampini   if (!rsorted) {
4758906d46d4SStefano Zampini     const PetscInt *idxs;
4759906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
4760aa0d41d4SStefano Zampini 
47619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
47629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
47639371c9d4SSatish Balay     for (i = 0; i < rsize; i++) { idxs_perm_r[i] = i; }
47649566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
47659566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
47669371c9d4SSatish Balay     for (i = 0; i < rsize; i++) { idxs_sorted[i] = idxs[idxs_perm_r[i]]; }
47679566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
47689566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
4769d65f70fdSStefano Zampini   } else {
47709566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
4771d65f70fdSStefano Zampini     isrow_s = isrow;
4772aa0d41d4SStefano Zampini   }
4773906d46d4SStefano Zampini 
4774d65f70fdSStefano Zampini   if (!csorted) {
4775d65f70fdSStefano Zampini     if (isrow == iscol) {
47769566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
4777d65f70fdSStefano Zampini       iscol_s = isrow_s;
4778d65f70fdSStefano Zampini     } else {
4779d65f70fdSStefano Zampini       const PetscInt *idxs;
4780d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
4781906d46d4SStefano Zampini 
47829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
47839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
47849371c9d4SSatish Balay       for (i = 0; i < csize; i++) { idxs_perm_c[i] = i; }
47859566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
47869566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
47879371c9d4SSatish Balay       for (i = 0; i < csize; i++) { idxs_sorted[i] = idxs[idxs_perm_c[i]]; }
47889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
47899566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
4790d65f70fdSStefano Zampini     }
4791d65f70fdSStefano Zampini   } else {
47929566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
4793d65f70fdSStefano Zampini     iscol_s = iscol;
4794d65f70fdSStefano Zampini   }
4795d65f70fdSStefano Zampini 
47969566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
4797d65f70fdSStefano Zampini 
4798d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
4799906d46d4SStefano Zampini     Mat new_mat;
4800d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
4801906d46d4SStefano Zampini 
4802d65f70fdSStefano Zampini     if (!rsorted) {
4803d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
48049566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
48059371c9d4SSatish Balay       for (i = 0; i < rsize; i++) { idxs_r[idxs_perm_r[i]] = i; }
48069566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
48079566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
4808d65f70fdSStefano Zampini     } else {
48099566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
4810906d46d4SStefano Zampini     }
48119566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
4812d65f70fdSStefano Zampini 
4813d65f70fdSStefano Zampini     if (!csorted) {
4814d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
48159566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
4816d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
4817d65f70fdSStefano Zampini       } else {
4818d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
481928b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
48209566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
48219371c9d4SSatish Balay         for (i = 0; i < csize; i++) { idxs_c[idxs_perm_c[i]] = i; }
48229566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
48239566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
4824d65f70fdSStefano Zampini       }
4825d65f70fdSStefano Zampini     } else {
48269566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
4827d65f70fdSStefano Zampini     }
48289566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
4829d65f70fdSStefano Zampini 
48309566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
48319566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
4832d65f70fdSStefano Zampini     work_mat[0] = new_mat;
48339566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
48349566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
4835d65f70fdSStefano Zampini   }
4836d65f70fdSStefano Zampini 
48379566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
4838d65f70fdSStefano Zampini   *B = work_mat[0];
48399566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
48409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
48419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
4842d65f70fdSStefano Zampini   PetscFunctionReturn(0);
4843d65f70fdSStefano Zampini }
4844d65f70fdSStefano Zampini 
48459371c9d4SSatish Balay PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix) {
4846aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
48475e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
4848022d8d2bSstefano_zampini   Mat       new_mat, lA;
48495e8657edSStefano Zampini   IS        is_local, is_global;
4850d65f70fdSStefano Zampini   PetscInt  local_size;
4851b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
4852aa0d41d4SStefano Zampini 
4853aa0d41d4SStefano Zampini   PetscFunctionBegin;
48549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
48559566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
48569566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
48579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
48589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_local));
48599566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
48609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_global));
4861906d46d4SStefano Zampini 
4862906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
4863906d46d4SStefano Zampini     Vec       x, x_change;
4864906d46d4SStefano Zampini     PetscReal error;
4865906d46d4SStefano Zampini 
48669566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
48679566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
48689566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
48699566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
48709566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
48719566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
487288428137SStefano Zampini     if (!pcbddc->change_interior) {
487388428137SStefano Zampini       const PetscScalar *x, *y, *v;
487488428137SStefano Zampini       PetscReal          lerror = 0.;
487588428137SStefano Zampini       PetscInt           i;
487688428137SStefano Zampini 
48779566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
48789566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
48799566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
488088428137SStefano Zampini       for (i = 0; i < local_size; i++)
48819371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
48829566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
48839566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
48849566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
48851c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
4886637e8532SStefano Zampini       if (error > PETSC_SMALL) {
4887637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
488863a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
4889637e8532SStefano Zampini         } else {
489063a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
4891637e8532SStefano Zampini         }
4892637e8532SStefano Zampini       }
489388428137SStefano Zampini     }
48949566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
48959566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
48969566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
48979566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
4898637e8532SStefano Zampini     if (error > PETSC_SMALL) {
4899637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
490063a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
4901637e8532SStefano Zampini       } else {
490263a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
4903637e8532SStefano Zampini       }
4904637e8532SStefano Zampini     }
49059566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
49069566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
4907906d46d4SStefano Zampini   }
4908906d46d4SStefano Zampini 
4909022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
49109566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
4911022d8d2bSstefano_zampini 
491222d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
49139566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
491422d5777bSStefano Zampini   if (isseqaij) {
49159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
49169566063dSJacob Faibussowitsch     PetscCall(MatPtAP(matis->A, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
4917022d8d2bSstefano_zampini     if (lA) {
4918022d8d2bSstefano_zampini       Mat work;
49199566063dSJacob Faibussowitsch       PetscCall(MatPtAP(lA, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
49209566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
49219566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
4922022d8d2bSstefano_zampini     }
4923aa0d41d4SStefano Zampini   } else {
4924a00504b5SStefano Zampini     Mat work_mat;
49251cf9b237SStefano Zampini 
49269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
49279566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
49289566063dSJacob Faibussowitsch     PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
49299566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
4930022d8d2bSstefano_zampini     if (lA) {
4931022d8d2bSstefano_zampini       Mat work;
49329566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
49339566063dSJacob Faibussowitsch       PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
49349566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
49359566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
4936022d8d2bSstefano_zampini     }
4937aa0d41d4SStefano Zampini   }
4938b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
4939b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
49409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
4941aa0d41d4SStefano Zampini   PetscFunctionReturn(0);
4942aa0d41d4SStefano Zampini }
4943aa0d41d4SStefano Zampini 
49449371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpLocalScatters(PC pc) {
4945a64d13efSStefano Zampini   PC_IS          *pcis        = (PC_IS *)(pc->data);
4946a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
4947d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
494853892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
49493a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
49503a50541eSStefano Zampini   PetscInt        vbs, bs;
49516816873aSStefano Zampini   PetscBT         bitmask = NULL;
4952a64d13efSStefano Zampini 
4953a64d13efSStefano Zampini   PetscFunctionBegin;
4954b23d619eSStefano Zampini   /*
4955b23d619eSStefano Zampini     No need to setup local scatters if
4956b23d619eSStefano Zampini       - primal space is unchanged
4957b23d619eSStefano Zampini         AND
4958b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
4959b23d619eSStefano Zampini         AND
4960b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
4961b23d619eSStefano Zampini   */
49629371c9d4SSatish Balay   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) { PetscFunctionReturn(0); }
4963f4ddd8eeSStefano Zampini   /* destroy old objects */
49649566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
49659566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
49669566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
4967a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
4968b371cd4fSStefano Zampini   n_B        = pcis->n_B;
4969b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
4970b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
49713a50541eSStefano Zampini 
4972a64d13efSStefano Zampini   /* Dohrmann's notation: dofs splitted in R (Remaining: all dofs but the vertices) and V (Vertices) */
49736816873aSStefano Zampini 
497453892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
4975b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
49769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
49779566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
4978*48a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
4979a64d13efSStefano Zampini 
4980a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
49819371c9d4SSatish Balay       if (!PetscBTLookup(bitmask, i)) { idx_R_local[n_R++] = i; }
4982a64d13efSStefano Zampini     }
4983df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
4984df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
49856816873aSStefano Zampini 
49869566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
49879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
49886816873aSStefano Zampini   }
49893a50541eSStefano Zampini 
49903a50541eSStefano Zampini   /* Block code */
49913a50541eSStefano Zampini   vbs = 1;
49929566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
49933a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
49943a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
49953a50541eSStefano Zampini     PetscInt *vary;
4996b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
49979566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
49989566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
4999d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5000d3df7717SStefano 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 */
50010e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5002d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
50033a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
50043a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
50053a50541eSStefano Zampini           break;
50063a50541eSStefano Zampini         }
50073a50541eSStefano Zampini       }
50089566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5009d3df7717SStefano Zampini     } else {
5010d3df7717SStefano Zampini       /* Verify directly the R set */
5011d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5012d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5013d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5014d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5015d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5016d3df7717SStefano Zampini             break;
5017d3df7717SStefano Zampini           }
5018d3df7717SStefano Zampini         }
5019d3df7717SStefano Zampini       }
5020d3df7717SStefano Zampini     }
50213a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
50223a50541eSStefano Zampini       vbs = bs;
50239371c9d4SSatish Balay       for (i = 0; i < n_R / vbs; i++) { idx_R_local[i] = idx_R_local[vbs * i] / vbs; }
50243a50541eSStefano Zampini     }
50253a50541eSStefano Zampini   }
50269566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5027b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5028df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
502953892102SStefano Zampini 
50309566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
50319566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
50329566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5033df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
503453892102SStefano Zampini   } else {
50359566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
503653892102SStefano Zampini   }
5037a64d13efSStefano Zampini 
5038a64d13efSStefano Zampini   /* print some info if requested */
5039a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
50409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
50419566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
50429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
50439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
504463a3b9bcSJacob 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));
50459371c9d4SSatish 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,
50469371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
50479566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5048a64d13efSStefano Zampini   }
5049a64d13efSStefano Zampini 
5050a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5051b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
50526816873aSStefano Zampini     IS        is_aux1, is_aux2;
50536816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
50546816873aSStefano Zampini 
50559566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
50569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
50579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
50589566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5059*48a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
50609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5061a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
50629371c9d4SSatish Balay       if (!PetscBTLookup(bitmask, idx_R_local[i])) { aux_array1[j++] = i; }
5063a64d13efSStefano Zampini     }
50649566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
50659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5066a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
50679371c9d4SSatish Balay       if (!PetscBTLookup(bitmask, is_indices[i])) { aux_array2[j++] = i; }
5068a64d13efSStefano Zampini     }
50699566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
50709566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
50719566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
50729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
50739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5074a64d13efSStefano Zampini 
50758eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
50769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5077a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
50789371c9d4SSatish Balay         if (PetscBTLookup(bitmask, idx_R_local[i])) { aux_array1[j++] = i; }
5079a64d13efSStefano Zampini       }
50809566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
50819566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
50829566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5083a64d13efSStefano Zampini     }
50849566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
50859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5086d62866d3SStefano Zampini   } else {
5087df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
50886816873aSStefano Zampini     IS                 tis;
50896816873aSStefano Zampini     PetscInt           schur_size;
50906816873aSStefano Zampini 
50919566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
50929566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
50939566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
50949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
50956816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
50969566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
50979566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
50989566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5099d62866d3SStefano Zampini     }
5100d62866d3SStefano Zampini   }
5101a64d13efSStefano Zampini   PetscFunctionReturn(0);
5102a64d13efSStefano Zampini }
5103a64d13efSStefano Zampini 
51049371c9d4SSatish Balay static PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B) {
510592cccca0SStefano Zampini   MatNullSpace   NullSpace;
510692cccca0SStefano Zampini   Mat            dmat;
510792cccca0SStefano Zampini   const Vec     *nullvecs;
510892cccca0SStefano Zampini   Vec            v, v2, *nullvecs2;
51096d9e27e4SStefano Zampini   VecScatter     sct = NULL;
5110eb06acf8SStefano Zampini   PetscContainer c;
5111eb06acf8SStefano Zampini   PetscScalar   *ddata;
5112295df10fSStefano Zampini   PetscInt       k, nnsp_size, bsiz, bsiz2, n, N, bs;
511392cccca0SStefano Zampini   PetscBool      nnsp_has_cnst;
511492cccca0SStefano Zampini 
511592cccca0SStefano Zampini   PetscFunctionBegin;
51166d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
51176d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
51186d9e27e4SStefano Zampini 
5119*48a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
51206d9e27e4SStefano Zampini     sct = matis->cctx;
51219566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
51226d9e27e4SStefano Zampini   } else {
51239566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
5124*48a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
512592cccca0SStefano Zampini     if (NullSpace) PetscFunctionReturn(0);
51266d9e27e4SStefano Zampini   }
51279566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
5128*48a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
512992cccca0SStefano Zampini   if (!NullSpace) PetscFunctionReturn(0);
51306d9e27e4SStefano Zampini 
51319566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
51329566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
5133*48a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
51349566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, (const Vec **)&nullvecs));
5135295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
51369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
51379566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
51389566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
51399566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
51409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
514192cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
51429566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
51439566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
51449566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
514592cccca0SStefano Zampini   }
514692cccca0SStefano Zampini   if (nnsp_has_cnst) {
51479566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
51489566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
514992cccca0SStefano Zampini   }
51509566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
51519566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5152295df10fSStefano Zampini 
51539566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
51549566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)B), &c));
51559566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ddata));
51569566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
51579566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", (PetscObject)c));
51589566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
51599566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
51609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5161eb06acf8SStefano Zampini 
5162*48a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
51639566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
51649566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
51659566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
51669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
51679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
51689566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
516992cccca0SStefano Zampini   PetscFunctionReturn(0);
517092cccca0SStefano Zampini }
5171304d26faSStefano Zampini 
51729371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann) {
5173304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5174304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5175304d26faSStefano Zampini   PC           pc_temp;
5176304d26faSStefano Zampini   Mat          A_RR;
517792cccca0SStefano Zampini   MatNullSpace nnsp;
5178f4ddd8eeSStefano Zampini   MatReuse     reuse;
5179304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5180304d26faSStefano Zampini   PetscReal    value;
518104708bb6SStefano Zampini   PetscInt     n_D, n_R;
5182b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
51830a545947SLisandro Dalcin   void (*f)(void) = NULL;
5184312be037SStefano Zampini   char   dir_prefix[256], neu_prefix[256], str_level[16];
5185e604994aSStefano Zampini   size_t len;
5186304d26faSStefano Zampini 
5187304d26faSStefano Zampini   PetscFunctionBegin;
51889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
51896d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
51906d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
51916d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
51926d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
51936d9e27e4SStefano Zampini 
51949566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
51959566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
51969566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
51976d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
51981c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lhas, &ghas, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
5199*48a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
52006d9e27e4SStefano Zampini   }
52016d9e27e4SStefano Zampini 
5202e604994aSStefano Zampini   /* compute prefixes */
52039566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(dir_prefix, ""));
52049566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(neu_prefix, ""));
5205e604994aSStefano Zampini   if (!pcbddc->current_level) {
52069566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
52079566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
52089566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
52099566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5210e604994aSStefano Zampini   } else {
52119566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)(pcbddc->current_level)));
52129566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
5213e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
5214312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
5215312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
5216a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
52179566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
52189566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
52199566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
52209566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
52219566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
52229566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
5223e604994aSStefano Zampini   }
5224e604994aSStefano Zampini 
5225304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
5226684f6988SStefano Zampini   if (dirichlet) {
5227d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5228450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
52297827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
5230450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
5231a3df083aSStefano Zampini         Mat A_IIn;
5232a3df083aSStefano Zampini 
52339566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
52349566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
5235a3df083aSStefano Zampini         pcis->A_II = A_IIn;
5236a3df083aSStefano Zampini       }
5237450f8f5eSStefano Zampini     }
5238b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5239b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
5240b94d7dedSBarry Smith 
5241ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
5242964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
524392cccca0SStefano Zampini     opts = PETSC_FALSE;
5244304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
524592cccca0SStefano Zampini       opts = PETSC_TRUE;
52469566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
52479566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
5248304d26faSStefano Zampini       /* default */
52499566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
52509566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
52519566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
52529566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
52539577ea80SStefano Zampini       if (issbaij) {
52549566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
52559577ea80SStefano Zampini       } else {
52569566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
52579577ea80SStefano Zampini       }
52589566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
525992cccca0SStefano Zampini     }
52609566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
52619566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
5262304d26faSStefano Zampini     /* Allow user's customization */
52631baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
52649566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
52656d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
52669566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
526792cccca0SStefano Zampini     }
52689566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
52699566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
52709566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
527192cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5272cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5273cd18cfedSStefano Zampini       const PetscInt *idxs;
5274cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5275cd18cfedSStefano Zampini 
52769566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
52779566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
52789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5279cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
52809371c9d4SSatish Balay         for (d = 0; d < cdim; d++) { scoords[i * cdim + d] = coords[idxs[i] * cdim + d]; }
5281cd18cfedSStefano Zampini       }
52829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
52839566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
52849566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5285cd18cfedSStefano Zampini     }
5286b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
5287df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5288d62866d3SStefano Zampini 
52899566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
5290d5574798SStefano Zampini     }
529192cccca0SStefano Zampini 
5292304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5293304d26faSStefano Zampini     if (!n_D) {
52949566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
52959566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5296304d26faSStefano Zampini     }
52979566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
5298304d26faSStefano Zampini     /* set ksp_D into pcis data */
52999566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
53009566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
5301304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
5302684f6988SStefano Zampini   }
5303304d26faSStefano Zampini 
5304304d26faSStefano Zampini   /* NEUMANN PROBLEM */
53050a545947SLisandro Dalcin   A_RR = NULL;
5306684f6988SStefano Zampini   if (neumann) {
5307d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
530804708bb6SStefano Zampini     PetscInt        ibs, mbs;
5309b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
531004708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
53110aa714b2SStefano Zampini 
53120aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
53130aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
53140aa714b2SStefano Zampini       IS iP;
53150aa714b2SStefano Zampini 
53160aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
53179566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
53180aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
53190aa714b2SStefano Zampini     }
5320f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
53219566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
5322f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
5323f4ddd8eeSStefano Zampini       PetscInt nn_R;
53249566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
53259566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
53269566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
5327f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
53289566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
53299566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5330f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5331f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5332727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
53339566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
5334f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
5335f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
5336f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
5337f4ddd8eeSStefano Zampini         }
5338f4ddd8eeSStefano Zampini       }
5339f4ddd8eeSStefano Zampini       /* last check */
5340d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
53419566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5342f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5343f4ddd8eeSStefano Zampini       }
5344f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
5345f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
5346f4ddd8eeSStefano Zampini     }
5347365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
5348365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
53499566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
53509566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
53519566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
535204708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
535304708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
53549566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
53559566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
5356af732b37SStefano Zampini       } else {
53579566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
53586816873aSStefano Zampini       }
535904708bb6SStefano Zampini     } else if (issbaij) { /* need to convert to BAIJ to get offdiagonal blocks */
536004708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
53619566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
53629566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
536304708bb6SStefano Zampini       } else {
53649566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
536504708bb6SStefano Zampini       }
536604708bb6SStefano Zampini     }
5367a00504b5SStefano Zampini     /* extract A_RR */
53680aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5369a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5370a00504b5SStefano Zampini 
5371a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
53729566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5373a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
53749566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
537516e386b8SStefano Zampini         } else {
53769566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
5377a00504b5SStefano Zampini         }
5378a00504b5SStefano Zampini       } else {
53799566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
53809566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
53819566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
5382a00504b5SStefano Zampini       }
5383a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
53849566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
538516e386b8SStefano Zampini     }
5386b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5387b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
538892cccca0SStefano Zampini     opts = PETSC_FALSE;
5389f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
539092cccca0SStefano Zampini       opts = PETSC_TRUE;
53919566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
53929566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
5393304d26faSStefano Zampini       /* default */
53949566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
53959566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
53969566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
53979566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
53989577ea80SStefano Zampini       if (issbaij) {
53999566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
54009577ea80SStefano Zampini       } else {
54019566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
54029577ea80SStefano Zampini       }
54039566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
540492cccca0SStefano Zampini     }
54059566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
54069566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
540792cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
54089566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
540992cccca0SStefano Zampini     }
54109566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
54116d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
54129566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
541392cccca0SStefano Zampini     }
54149566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
54159566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54169566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
541792cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5418cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5419cd18cfedSStefano Zampini       const PetscInt *idxs;
5420cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5421cd18cfedSStefano Zampini 
54229566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
54239566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
54249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5425cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
54269371c9d4SSatish Balay         for (d = 0; d < cdim; d++) { scoords[i * cdim + d] = coords[idxs[i] * cdim + d]; }
5427cd18cfedSStefano Zampini       }
54289566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
54299566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
54309566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5431cd18cfedSStefano Zampini     }
543292cccca0SStefano Zampini 
5433304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5434304d26faSStefano Zampini     if (!n_R) {
54359566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54369566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5437304d26faSStefano Zampini     }
5438df4d28bfSStefano Zampini     /* Reuse solver if it is present */
54390aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5440df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5441d62866d3SStefano Zampini 
54429566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
5443d62866d3SStefano Zampini     }
54449566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
5445684f6988SStefano Zampini   }
5446304d26faSStefano Zampini 
5447684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
54489566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
54499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
54509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
5451684f6988SStefano Zampini   }
54529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
5453c7017625SStefano Zampini 
5454c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
5455*48a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
5456*48a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
5457*48a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
5458c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
5459c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
5460684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
54619566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
54629566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
54639566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
54649566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
54659566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
54669566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
546763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Dirichlet solve (%s) = % 1.14e \n", PetscGlobalRank, ((PetscObject)(pcbddc->ksp_D))->prefix, (double)value));
54689566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5469304d26faSStefano Zampini     }
5470684f6988SStefano Zampini     if (neumann) { /* Neumann */
54719566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
54729566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
54739566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
54749566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
54759566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
54769566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
547763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Neumann solve (%s) = % 1.14e\n", PetscGlobalRank, ((PetscObject)(pcbddc->ksp_R))->prefix, (double)value));
54789566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5479304d26faSStefano Zampini     }
5480684f6988SStefano Zampini   }
54815cbda25cSStefano Zampini   /* free Neumann problem's matrix */
54829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
5483304d26faSStefano Zampini   PetscFunctionReturn(0);
5484304d26faSStefano Zampini }
5485304d26faSStefano Zampini 
54869371c9d4SSatish Balay static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose) {
5487674ae819SStefano Zampini   PC_BDDC        *pcbddc       = (PC_BDDC *)(pc->data);
5488be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
5489b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
5490674ae819SStefano Zampini 
5491674ae819SStefano Zampini   PetscFunctionBegin;
5492*48a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
549380677318SStefano Zampini   if (!pcbddc->switch_static) {
549480677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
54959566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
54969566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
549720c7b377SStefano Zampini     }
5498b334f244SStefano Zampini     if (!reuse_solver) {
54999566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55009566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
550120c7b377SStefano Zampini     } else {
5502df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5503be83ff47SStefano Zampini 
55049566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
55059566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
550620c7b377SStefano Zampini     }
5507be83ff47SStefano Zampini   } else {
55089566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55099566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55109566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55119566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
551280677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
55139566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
55149566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
55159566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55169566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
5517674ae819SStefano Zampini     }
5518674ae819SStefano Zampini   }
55199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
5520b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
552180677318SStefano Zampini     if (applytranspose) {
55229566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
552380677318SStefano Zampini     } else {
55249566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
552580677318SStefano Zampini     }
55269566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
5527be83ff47SStefano Zampini   } else {
5528df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5529be83ff47SStefano Zampini 
5530be83ff47SStefano Zampini     if (applytranspose) {
55319566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5532be83ff47SStefano Zampini     } else {
55339566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5534be83ff47SStefano Zampini     }
5535be83ff47SStefano Zampini   }
55369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
55379566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
553880677318SStefano Zampini   if (!pcbddc->switch_static) {
5539b334f244SStefano Zampini     if (!reuse_solver) {
55409566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55419566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
5542be83ff47SStefano Zampini     } else {
5543df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5544be83ff47SStefano Zampini 
55459566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
55469566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
5547be83ff47SStefano Zampini     }
554880677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
55499566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
55509566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
555180677318SStefano Zampini     }
555280677318SStefano Zampini   } else {
55539566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55549566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
55569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
555780677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
55589566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
55599566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
556080677318SStefano Zampini     }
55619566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55629566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55639566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
55649566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
5565674ae819SStefano Zampini   }
5566674ae819SStefano Zampini   PetscFunctionReturn(0);
5567674ae819SStefano Zampini }
5568674ae819SStefano Zampini 
5569dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
55709371c9d4SSatish Balay PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose) {
5571674ae819SStefano Zampini   PC_BDDC          *pcbddc = (PC_BDDC *)(pc->data);
5572674ae819SStefano Zampini   PC_IS            *pcis   = (PC_IS *)(pc->data);
5573674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
5574674ae819SStefano Zampini 
5575674ae819SStefano Zampini   PetscFunctionBegin;
5576dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
55774fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5578dc359a40SStefano Zampini     if (applytranspose) {
55799566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
55809566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
5581dc359a40SStefano Zampini     } else {
55829566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
55839566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
558415aaf578SStefano Zampini     }
55854fee134fSStefano Zampini   } else {
55869566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
55874fee134fSStefano Zampini   }
5588efc2fbd9SStefano Zampini 
5589efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
55904f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
5591efc2fbd9SStefano Zampini     PetscScalar *array;
55924f1b2e48SStefano Zampini     PetscInt     j;
5593efc2fbd9SStefano Zampini 
55949566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
55954f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
55969566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5597efc2fbd9SStefano Zampini   }
5598efc2fbd9SStefano Zampini 
559912edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
56009566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
56019566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
56029566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
560312edc857SStefano Zampini 
56049f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
560512edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
560651694757SStefano Zampini     Mat          coarse_mat;
5607964fefecSStefano Zampini     Vec          rhs, sol;
560851694757SStefano Zampini     MatNullSpace nullsp;
560927b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
5610964fefecSStefano Zampini 
561127b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
561227b6a85dSStefano Zampini       PC coarse_pc;
561327b6a85dSStefano Zampini 
56149566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
56159566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
561627b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
561727b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
561827b6a85dSStefano Zampini         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)(coarse_pc->data);
561927b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
56203bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
562127b6a85dSStefano Zampini       }
562227b6a85dSStefano Zampini     }
56239566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
56249566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
56259566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
562612edc857SStefano Zampini     if (applytranspose) {
562728b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
56289566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56299566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
56309566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56319566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
56329566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
56331baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
56342701bc32SStefano Zampini     } else {
56359566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
56361f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
56372701bc32SStefano Zampini         PC coarse_pc;
56382701bc32SStefano Zampini 
56391baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
56409566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
56419566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
56429566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
56439566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
564412edc857SStefano Zampini       } else {
56459566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56469566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
56479566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56489566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
56491baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
565012edc857SStefano Zampini       }
56512701bc32SStefano Zampini     }
56521d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
565327b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
565427b6a85dSStefano Zampini       PC       coarse_pc;
565527b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
565627b6a85dSStefano Zampini 
56579566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
565827b6a85dSStefano Zampini       coarsepcbddc                           = (PC_BDDC *)(coarse_pc->data);
565927b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
56603bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
566127b6a85dSStefano Zampini     }
566212edc857SStefano Zampini   }
5663674ae819SStefano Zampini 
5664674ae819SStefano Zampini   /* Local solution on R nodes */
5665*48a46eb9SPierre Jolivet   if (pcis->n && !pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
56669f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
56679566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
56689566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
5669674ae819SStefano Zampini 
56704fee134fSStefano Zampini   /* Sum contributions from the two levels */
56714fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5672dc359a40SStefano Zampini     if (applytranspose) {
56739566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
56749566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5675dc359a40SStefano Zampini     } else {
56769566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
56779566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5678dc359a40SStefano Zampini     }
5679efc2fbd9SStefano Zampini     /* store p0 */
56804f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5681efc2fbd9SStefano Zampini       PetscScalar *array;
56824f1b2e48SStefano Zampini       PetscInt     j;
5683efc2fbd9SStefano Zampini 
56849566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
56854f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
56869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5687efc2fbd9SStefano Zampini     }
56884fee134fSStefano Zampini   } else { /* expand the coarse solution */
56894fee134fSStefano Zampini     if (applytranspose) {
56909566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
56914fee134fSStefano Zampini     } else {
56929566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
56934fee134fSStefano Zampini     }
56944fee134fSStefano Zampini   }
5695674ae819SStefano Zampini   PetscFunctionReturn(0);
5696674ae819SStefano Zampini }
5697674ae819SStefano Zampini 
56989371c9d4SSatish Balay PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode) {
5699674ae819SStefano Zampini   PC_BDDC           *pcbddc = (PC_BDDC *)(pc->data);
570012edc857SStefano Zampini   Vec                from, to;
57017ebab0bbSStefano Zampini   const PetscScalar *array;
5702674ae819SStefano Zampini 
5703674ae819SStefano Zampini   PetscFunctionBegin;
570412edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
570512edc857SStefano Zampini     from = pcbddc->coarse_vec;
570612edc857SStefano Zampini     to   = pcbddc->vec1_P;
570712edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
570812edc857SStefano Zampini       Vec tvec;
570958da7f69SStefano Zampini 
57109566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
57119566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
57129566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
57139566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
57149566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
57159566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
571612edc857SStefano Zampini     }
571712edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
571812edc857SStefano Zampini     from = pcbddc->vec1_P;
571912edc857SStefano Zampini     to   = pcbddc->coarse_vec;
572012edc857SStefano Zampini   }
57219566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
5722674ae819SStefano Zampini   PetscFunctionReturn(0);
5723674ae819SStefano Zampini }
5724674ae819SStefano Zampini 
57259371c9d4SSatish Balay PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode) {
5726674ae819SStefano Zampini   PC_BDDC           *pcbddc = (PC_BDDC *)(pc->data);
572712edc857SStefano Zampini   Vec                from, to;
57287ebab0bbSStefano Zampini   const PetscScalar *array;
5729674ae819SStefano Zampini 
5730674ae819SStefano Zampini   PetscFunctionBegin;
573112edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
573212edc857SStefano Zampini     from = pcbddc->coarse_vec;
573312edc857SStefano Zampini     to   = pcbddc->vec1_P;
573412edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
573512edc857SStefano Zampini     from = pcbddc->vec1_P;
573612edc857SStefano Zampini     to   = pcbddc->coarse_vec;
573712edc857SStefano Zampini   }
57389566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
573912edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
574012edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
574112edc857SStefano Zampini       Vec tvec;
574258da7f69SStefano Zampini 
57439566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
57449566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
57459566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
57469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
574758da7f69SStefano Zampini     }
574858da7f69SStefano Zampini   } else {
574958da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
57509566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
575112edc857SStefano Zampini     }
575212edc857SStefano Zampini   }
5753674ae819SStefano Zampini   PetscFunctionReturn(0);
5754674ae819SStefano Zampini }
5755674ae819SStefano Zampini 
57569371c9d4SSatish Balay PetscErrorCode PCBDDCConstraintsSetUp(PC pc) {
5757674ae819SStefano Zampini   PC_IS       *pcis   = (PC_IS *)(pc->data);
5758674ae819SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5759674ae819SStefano Zampini   Mat_IS      *matis  = (Mat_IS *)pc->pmat->data;
5760984c4197SStefano Zampini   /* one and zero */
5761984c4197SStefano Zampini   PetscScalar  one = 1.0, zero = 0.0;
5762984c4197SStefano Zampini   /* space to store constraints and their local indices */
57639162d606SStefano Zampini   PetscScalar *constraints_data;
57649162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
57659162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
57669162d606SStefano Zampini   PetscInt    *constraints_n;
5767984c4197SStefano Zampini   /* iterators */
5768b3d85658SStefano Zampini   PetscInt     i, j, k, total_counts, total_counts_cc, cum;
5769984c4197SStefano Zampini   /* BLAS integers */
5770e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
5771e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
5772c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
5773727cdba6SStefano Zampini   /* reuse */
57740e6343abSStefano Zampini   PetscInt     olocal_primal_size, olocal_primal_size_cc;
57750e6343abSStefano Zampini   PetscInt    *olocal_primal_ref_node, *olocal_primal_ref_mult;
5776984c4197SStefano Zampini   /* change of basis */
5777b3d85658SStefano Zampini   PetscBool    qr_needed;
57789162d606SStefano Zampini   PetscBT      change_basis, qr_needed_idx;
5779984c4197SStefano Zampini   /* auxiliary stuff */
578064efe560SStefano Zampini   PetscInt    *nnz, *is_indices;
57818a0068c3SStefano Zampini   PetscInt     ncc;
5782984c4197SStefano Zampini   /* some quantities */
578345a1bb75SStefano Zampini   PetscInt     n_vertices, total_primal_vertices, valid_constraints;
5784a58a30b4SStefano Zampini   PetscInt     size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
578557715f18SStefano Zampini   PetscReal    tol; /* tolerance for retaining eigenmodes */
5786984c4197SStefano Zampini 
5787674ae819SStefano Zampini   PetscFunctionBegin;
578857715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
57898e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
57909566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
57919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
57929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
5793088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
5794088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
57950e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
57969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
57979566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
57989566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
57999566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
58009566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
5801cf5a6209SStefano Zampini 
5802cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
58039162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
5804cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
5805cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
5806cf5a6209SStefano Zampini     Vec         *localnearnullsp;
5807cf5a6209SStefano Zampini     PetscScalar *array;
580832fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
5809cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
5810674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
5811b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
5812674ae819SStefano Zampini     PetscScalar *work;
5813674ae819SStefano Zampini     PetscReal   *singular_vals;
5814674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
5815674ae819SStefano Zampini     PetscReal *rwork;
5816674ae819SStefano Zampini #endif
581755080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
5818964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
5819964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
582055080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
5821674ae819SStefano Zampini 
582255080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
5823b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
582455080a34SStefano Zampini     use_pod = PETSC_TRUE;
582555080a34SStefano Zampini #endif
5826674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
58279566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
582832fe681dSStefano Zampini     o_nf       = n_ISForFaces;
582932fe681dSStefano Zampini     o_ne       = n_ISForEdges;
583032fe681dSStefano Zampini     n_vertices = 0;
583132fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
5832e4d548c7SStefano Zampini     /* print some info */
58335c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
583432fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
58359566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
58369566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
58379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
583832fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
583963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
584063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
58419566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
58429566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
5843e4d548c7SStefano Zampini     }
5844e4d548c7SStefano Zampini 
584532fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
584632fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
584732fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
584870022509SStefano Zampini 
5849674ae819SStefano Zampini     /* check if near null space is attached to global mat */
58506d9e27e4SStefano Zampini     if (pcbddc->use_nnsp) {
58519566063dSJacob Faibussowitsch       PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
58526d9e27e4SStefano Zampini     } else nearnullsp = NULL;
58536d9e27e4SStefano Zampini 
5854674ae819SStefano Zampini     if (nearnullsp) {
58559566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
5856f4ddd8eeSStefano Zampini       /* remove any stored info */
58579566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
58589566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
5859f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
58609566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
5861f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
58629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
5863*48a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
5864984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
5865984c4197SStefano Zampini       nnsp_size     = 0;
5866674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
5867674ae819SStefano Zampini     }
5868984c4197SStefano Zampini     /* get max number of constraints on a single cc */
5869984c4197SStefano Zampini     max_constraints = nnsp_size;
5870984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
5871984c4197SStefano Zampini 
5872674ae819SStefano Zampini     /*
5873674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
58749162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
58759162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
58769162d606SStefano Zampini          There can be multiple constraints per connected component
5877674ae819SStefano Zampini                                                                                                                                                            */
58789162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
58799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
58809162d606SStefano Zampini 
58819162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
58829162d606SStefano Zampini     total_counts *= max_constraints;
5883674ae819SStefano Zampini     total_counts += n_vertices;
58849566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
58859162d606SStefano Zampini 
5886674ae819SStefano Zampini     total_counts           = 0;
5887674ae819SStefano Zampini     max_size_of_constraint = 0;
5888674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
58899162d606SStefano Zampini       IS used_is;
5890674ae819SStefano Zampini       if (i < n_ISForEdges) {
58919162d606SStefano Zampini         used_is = ISForEdges[i];
5892674ae819SStefano Zampini       } else {
58939162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
5894674ae819SStefano Zampini       }
58959566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
5896674ae819SStefano Zampini       total_counts += j;
5897674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
5898674ae819SStefano Zampini     }
58999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
59009162d606SStefano Zampini 
5901984c4197SStefano Zampini     /* get local part of global near null space vectors */
59029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
5903984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
59049566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
59059566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
59069566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
5907984c4197SStefano Zampini     }
5908674ae819SStefano Zampini 
5909242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
5910242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
5911a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
5912242a89d7SStefano Zampini 
5913984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
5914a773dcb8SStefano Zampini     if (!skip_lapack) {
5915674ae819SStefano Zampini       PetscScalar temp_work;
5916911cabfeSStefano Zampini 
591755080a34SStefano Zampini       if (use_pod) {
5918984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
59199566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
59209566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
59219566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
5922674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
59239566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
5924674ae819SStefano Zampini #endif
5925674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
59269566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
59279566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
5928674ae819SStefano Zampini         lwork = -1;
59299566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
5930674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
5931792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
5932674ae819SStefano Zampini #else
5933792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
5934674ae819SStefano Zampini #endif
59359566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
593628b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %d", (int)lierr);
593755080a34SStefano Zampini       } else {
593855080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
5939674ae819SStefano Zampini         /* SVD */
5940674ae819SStefano Zampini         PetscInt max_n, min_n;
5941674ae819SStefano Zampini         max_n = max_size_of_constraint;
5942984c4197SStefano Zampini         min_n = max_constraints;
5943984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
5944674ae819SStefano Zampini           min_n = max_size_of_constraint;
5945984c4197SStefano Zampini           max_n = max_constraints;
5946674ae819SStefano Zampini         }
59479566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
5948674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
59499566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
5950674ae819SStefano Zampini #endif
5951674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
5952674ae819SStefano Zampini         lwork = -1;
59539566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
59549566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
59559566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
59569566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
5957674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
5958792fecdfSBarry 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));
5959674ae819SStefano Zampini #else
5960792fecdfSBarry 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));
5961674ae819SStefano Zampini #endif
59629566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
596328b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %d", (int)lierr);
596455080a34SStefano Zampini #else
596555080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
5966984c4197SStefano Zampini #endif /* on missing GESVD */
596755080a34SStefano Zampini       }
5968674ae819SStefano Zampini       /* Allocate optimal workspace */
59699566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
59709566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
5971674ae819SStefano Zampini     }
5972674ae819SStefano Zampini     /* Now we can loop on constraining sets */
5973674ae819SStefano Zampini     total_counts            = 0;
59749162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
59759162d606SStefano Zampini     constraints_data_ptr[0] = 0;
5976674ae819SStefano Zampini     /* vertices */
59779162d606SStefano Zampini     if (n_vertices) {
59789566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
59799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
5980674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
59819162d606SStefano Zampini         constraints_n[total_counts]            = 1;
59829162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
59839162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
59849162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
5985674ae819SStefano Zampini         total_counts++;
5986674ae819SStefano Zampini       }
59879566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
5988674ae819SStefano Zampini     }
5989984c4197SStefano Zampini 
5990674ae819SStefano Zampini     /* edges and faces */
59919162d606SStefano Zampini     total_counts_cc = total_counts;
5992911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
59939162d606SStefano Zampini       IS        used_is;
59949162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
59959162d606SStefano Zampini 
5996911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
59979162d606SStefano Zampini         used_is       = ISForEdges[ncc];
5998984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
5999674ae819SStefano Zampini       } else {
60009162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6001984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6002674ae819SStefano Zampini       }
6003674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
60049162d606SStefano Zampini 
60059566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
600632fe681dSStefano Zampini       if (!size_of_constraint) continue;
60079566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6008984c4197SStefano Zampini       /* change of basis should not be performed on local periodic nodes */
6009984c4197SStefano Zampini       if (pcbddc->mat_graph->mirrors && pcbddc->mat_graph->mirrors[is_indices[0]]) boolforchange = PETSC_FALSE;
6010674ae819SStefano Zampini       if (nnsp_has_cnst) {
60115b08dc53SStefano Zampini         PetscScalar quad_value;
60129162d606SStefano Zampini 
60139566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
60149162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
60159162d606SStefano Zampini 
6016a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6017674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6018a773dcb8SStefano Zampini         } else {
6019a773dcb8SStefano Zampini           quad_value = 1.0;
6020a773dcb8SStefano Zampini         }
60219371c9d4SSatish Balay         for (j = 0; j < size_of_constraint; j++) { constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value; }
60229162d606SStefano Zampini         temp_constraints++;
6023674ae819SStefano Zampini         total_counts++;
6024674ae819SStefano Zampini       }
6025674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6026984c4197SStefano Zampini         PetscReal    real_value;
60279162d606SStefano Zampini         PetscScalar *ptr_to_data;
60289162d606SStefano Zampini 
60299566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
60309162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
60319371c9d4SSatish Balay         for (j = 0; j < size_of_constraint; j++) { ptr_to_data[j] = array[is_indices[j]]; }
60329566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6033984c4197SStefano Zampini         /* check if array is null on the connected component */
60349566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6035792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
603657715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6037674ae819SStefano Zampini           temp_constraints++;
6038674ae819SStefano Zampini           total_counts++;
60399162d606SStefano Zampini           if (!idxs_copied) {
60409566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
60419162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6042674ae819SStefano Zampini           }
6043674ae819SStefano Zampini         }
60449162d606SStefano Zampini       }
60459566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
604645a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6047eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6048a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
60499162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
60509162d606SStefano Zampini 
60519162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
60529566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6053792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6054a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6055792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6056a773dcb8SStefano Zampini         } else { /* perform SVD */
60579162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6058674ae819SStefano Zampini 
605955080a34SStefano Zampini           if (use_pod) {
6060984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6061984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6062984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6063984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6064984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6065984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6066984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
60679566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6068674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
60699566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
60709566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6071674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
6072*48a46eb9SPierre 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));
6073674ae819SStefano Zampini             }
6074e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
60759566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
60769566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6077674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6078792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6079674ae819SStefano Zampini #else
6080792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6081674ae819SStefano Zampini #endif
60829566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
608328b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %d", (int)lierr);
6084984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6085674ae819SStefano Zampini             j = 0;
608687b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6087674ae819SStefano Zampini             total_counts      = total_counts - j;
608845a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6089e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
60909566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
60919566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
60929566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
60939566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
60949566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
60959566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6096674ae819SStefano Zampini             if (j < temp_constraints) {
6097984c4197SStefano Zampini               PetscInt ii;
6098984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
60999566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6100792fecdfSBarry 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));
61019566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6102984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
61039371c9d4SSatish Balay                 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]; }
6104674ae819SStefano Zampini               }
6105674ae819SStefano Zampini             }
610655080a34SStefano Zampini           } else {
610755080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
61089566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
61099566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61109566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
61119566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6112674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6113792fecdfSBarry 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));
6114674ae819SStefano Zampini #else
6115792fecdfSBarry 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));
6116674ae819SStefano Zampini #endif
611728b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
61189566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6119984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6120e310c8b4SStefano Zampini             k = temp_constraints;
6121e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6122674ae819SStefano Zampini             j = 0;
612387b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
612445a1bb75SStefano Zampini             valid_constraints = k - j;
6125911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
612655080a34SStefano Zampini #else
612755080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6128984c4197SStefano Zampini #endif /* on missing GESVD */
6129674ae819SStefano Zampini           }
6130a773dcb8SStefano Zampini         }
613155080a34SStefano Zampini       }
61329162d606SStefano Zampini       /* update pointers information */
61339162d606SStefano Zampini       if (valid_constraints) {
61349162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
61359162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
61369162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
61379162d606SStefano Zampini         /* set change_of_basis flag */
61389371c9d4SSatish Balay         if (boolforchange) { PetscBTSet(change_basis, total_counts_cc); }
6139b3d85658SStefano Zampini         total_counts_cc++;
614045a1bb75SStefano Zampini       }
614145a1bb75SStefano Zampini     }
6142984c4197SStefano Zampini     /* free workspace */
61438f1c130eSStefano Zampini     if (!skip_lapack) {
61449566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6145984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
61469566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6147984c4197SStefano Zampini #endif
61489566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
61499566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
61509566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6151984c4197SStefano Zampini     }
6152*48a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
61539566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6154cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
615532fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
615608122e43SStefano Zampini   } else {
615708122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6158984c4197SStefano Zampini 
615908122e43SStefano Zampini     total_counts = 0;
616008122e43SStefano Zampini     n_vertices   = 0;
6161*48a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
616208122e43SStefano Zampini     max_constraints = 0;
61639162d606SStefano Zampini     total_counts_cc = 0;
616408122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
616508122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
61669162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
616708122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
616808122e43SStefano Zampini     }
61699162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
61709162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
61719162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
61729162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
617374d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
61749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
61759162d606SStefano Zampini     total_counts_cc = 0;
61769162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
61779371c9d4SSatish Balay       if (pcbddc->adaptive_constraints_n[i]) { constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i]; }
617808122e43SStefano Zampini     }
617908122e43SStefano Zampini 
61808bec7fa6SStefano Zampini     max_size_of_constraint = 0;
61819162d606SStefano 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]);
61829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
618308122e43SStefano Zampini     /* Change of basis */
61849566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
618508122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
618608122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
6187*48a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
618808122e43SStefano Zampini       }
618908122e43SStefano Zampini     }
619008122e43SStefano Zampini   }
6191984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
61929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
619308122e43SStefano Zampini 
61949162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
619532fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
61969566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
619763a3b9bcSJacob 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);
619832fe681dSStefano Zampini   }
6199674ae819SStefano Zampini 
6200674ae819SStefano Zampini   /* Create constraint matrix */
62019566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
62029566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
62039566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6204984c4197SStefano Zampini 
6205984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6206a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
62075a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
62089566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
6209984c4197SStefano Zampini   total_primal_vertices        = 0;
6210b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
62119162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
62129162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
621372b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
62149162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6215b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
621664efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
62179371c9d4SSatish Balay       for (k = 0; k < constraints_n[i]; k++) { pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k]; }
6218b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
621991af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
6220a717540cSStefano Zampini         PetscBTSet(qr_needed_idx, i);
6221a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
6222a717540cSStefano Zampini       }
6223fa434743SStefano Zampini     } else {
6224b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
6225fa434743SStefano Zampini     }
6226a717540cSStefano Zampini   }
6227b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6228b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
6229674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
62309566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
62319566063dSJacob 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));
62329566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
62330e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
6234984c4197SStefano Zampini 
6235984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
623674d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
62379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
6238984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
623974d5cdf7SStefano Zampini 
6240984c4197SStefano Zampini   j            = total_primal_vertices;
624174d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
6242b3d85658SStefano Zampini   cum          = total_primal_vertices;
62439162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
62444641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
6245b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6246b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6247b3d85658SStefano Zampini       cum++;
62489162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
624974d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
625074d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
625174d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
625274d5cdf7SStefano Zampini       }
62539162d606SStefano Zampini       j += constraints_n[i];
6254674ae819SStefano Zampini     }
6255674ae819SStefano Zampini   }
62569566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
62579566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
62589566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
6259088faed8SStefano Zampini 
6260674ae819SStefano Zampini   /* set values in constraint matrix */
6261*48a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
6262984c4197SStefano Zampini   total_counts = total_primal_vertices;
62639162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
62644641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
62659162d606SStefano Zampini       PetscInt *cols;
62669162d606SStefano Zampini 
62679162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
62689162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
62699162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
62709162d606SStefano Zampini         PetscInt     row = total_counts + k;
62719162d606SStefano Zampini         PetscScalar *vals;
62729162d606SStefano Zampini 
62739162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
62749566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
62759162d606SStefano Zampini       }
62769162d606SStefano Zampini       total_counts += constraints_n[i];
6277674ae819SStefano Zampini     }
6278674ae819SStefano Zampini   }
6279674ae819SStefano Zampini   /* assembling */
62809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
62819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
62829566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
6283088faed8SStefano Zampini 
6284674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6285674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
6286026de310SStefano Zampini     /* dual and primal dofs on a single cc */
6287984c4197SStefano Zampini     PetscInt     dual_dofs, primal_dofs;
6288984c4197SStefano Zampini     /* working stuff for GEQRF */
62895a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
6290984c4197SStefano Zampini     PetscBLASInt lqr_work;
6291984c4197SStefano Zampini     /* working stuff for UNGQR */
62923c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
6293984c4197SStefano Zampini     PetscBLASInt lgqr_work;
6294984c4197SStefano Zampini     /* working stuff for TRTRS */
62955a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
62963f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
6297984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
6298984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
6299984c4197SStefano Zampini     PetscScalar *start_vals;
6300984c4197SStefano Zampini     /* working stuff for values insertion */
63014641a718SStefano Zampini     PetscBT      is_primal;
630264efe560SStefano Zampini     PetscInt    *aux_primal_numbering_B;
6303906d46d4SStefano Zampini     /* matrix sizes */
6304906d46d4SStefano Zampini     PetscInt     global_size, local_size;
6305906d46d4SStefano Zampini     /* temporary change of basis */
6306906d46d4SStefano Zampini     Mat          localChangeOfBasisMatrix;
6307cf5a6209SStefano Zampini     /* extra space for debugging */
63085a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
6309984c4197SStefano Zampini 
63109566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
63119566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
63129566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
6313906d46d4SStefano Zampini     /* nonzeros for local mat */
63149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
63151dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6316bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
63171dd7afcfSStefano Zampini     } else {
63181dd7afcfSStefano Zampini       const PetscInt *ii;
63191dd7afcfSStefano Zampini       PetscInt        n;
63201dd7afcfSStefano Zampini       PetscBool       flg_row;
63219566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
63221dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
63239566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
63241dd7afcfSStefano Zampini     }
63259162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
6326a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
63279162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
6328a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
63299162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
6330a717540cSStefano Zampini         } else {
63319162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
63329162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
6333a717540cSStefano Zampini         }
6334a717540cSStefano Zampini       }
6335a717540cSStefano Zampini     }
63369566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
63379566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
63389566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
63391dd7afcfSStefano Zampini     /* Set interior change in the matrix */
63401dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6341*48a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
63421dd7afcfSStefano Zampini     } else {
63431dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
63441dd7afcfSStefano Zampini       PetscScalar    *aa;
63451dd7afcfSStefano Zampini       PetscInt        n;
63461dd7afcfSStefano Zampini       PetscBool       flg_row;
63479566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
63489566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
6349*48a46eb9SPierre 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));
63509566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
63519566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
63521dd7afcfSStefano Zampini     }
6353a717540cSStefano Zampini 
6354a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
63559566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
63569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
6357a717540cSStefano Zampini     }
6358a717540cSStefano Zampini 
6359a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
6360a717540cSStefano Zampini     /*
6361a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
6362a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
6363a717540cSStefano Zampini 
63647c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
6365a717540cSStefano Zampini 
63667c625d9fSStefano 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)
6367a6b551f4SStefano Zampini 
6368a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
6369a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
6370a717540cSStefano Zampini             |              ...                        |
6371a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
6372a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
6373a717540cSStefano Zampini 
6374a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
6375a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
6376a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
6377a6b551f4SStefano Zampini 
6378a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
6379a717540cSStefano Zampini     */
63805a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
6381984c4197SStefano Zampini       /* space to store Q */
63829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
63834e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
63849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
6385984c4197SStefano Zampini       /* first we issue queries for optimal work */
63869566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
63879566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
63889566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
6389984c4197SStefano Zampini       lqr_work = -1;
6390792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
639128b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %d", (int)lierr);
63929566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
63939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((PetscInt)PetscRealPart(lqr_work_t), &qr_work));
6394984c4197SStefano Zampini       lgqr_work = -1;
63959566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
63969566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
63979566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
63989566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
63993f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
6400792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
640128b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %d", (int)lierr);
64029566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
64039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((PetscInt)PetscRealPart(lgqr_work_t), &gqr_work));
6404984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
64059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
6406a717540cSStefano Zampini       /* allocating workspace for check */
6407*48a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
6408a717540cSStefano Zampini     }
6409984c4197SStefano Zampini     /* array to store whether a node is primal or not */
64109566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
64119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
64129566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
641363a3b9bcSJacob 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);
6414*48a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
64159566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
6416984c4197SStefano Zampini 
6417a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
64189162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
64199162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
64204641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
6421984c4197SStefano Zampini         /* get constraint info */
64229162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
6423984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
6424984c4197SStefano Zampini 
6425*48a46eb9SPierre 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));
6426984c4197SStefano Zampini 
6427fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
6428a717540cSStefano Zampini 
6429a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
6430*48a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6431984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
64329566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6433984c4197SStefano Zampini 
6434984c4197SStefano Zampini           /* compute QR decomposition of constraints */
64359566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
64369566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
64379566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64389566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6439792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
644028b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %d", (int)lierr);
64419566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6442984c4197SStefano Zampini 
6443a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
64449566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
6445984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
64469566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
64479566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
64489566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64499566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
64509566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6451792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
645228b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %d", (int)lierr);
64539566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6454984c4197SStefano Zampini 
6455a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
64569566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
64579566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
64589566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
64599566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64609566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6461792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
646228b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %d", (int)lierr);
64639566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6464984c4197SStefano Zampini 
6465984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
6466984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
6467984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
64689566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
64699566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
64709566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
64719566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64729566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
64739566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
64749566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6475792fecdfSBarry 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));
64769566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
64779566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6478984c4197SStefano Zampini 
6479984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
64809162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
6481984c4197SStefano Zampini           /* insert cols for primal dofs */
6482984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
6483984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
64849162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
64859566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6486984c4197SStefano Zampini           }
6487984c4197SStefano Zampini           /* insert cols for dual dofs */
6488984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
64899162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
6490984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
64919162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
64929566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6493984c4197SStefano Zampini               j++;
6494674ae819SStefano Zampini             }
6495674ae819SStefano Zampini           }
6496984c4197SStefano Zampini 
6497984c4197SStefano Zampini           /* check change of basis */
6498984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
6499984c4197SStefano Zampini             PetscInt  ii, jj;
6500984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
65019566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
65029566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
65039566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
65049566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65059566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
65069566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
65079566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6508792fecdfSBarry 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));
65099566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6510984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
6511984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
6512cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
6513c068d9bbSLisandro 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;
6514674ae819SStefano Zampini               }
6515674ae819SStefano Zampini             }
6516984c4197SStefano Zampini             if (!valid_qr) {
65179566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
6518984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
6519984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
6520cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
652163a3b9bcSJacob 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])));
6522674ae819SStefano Zampini                   }
6523c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
652463a3b9bcSJacob 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])));
6525984c4197SStefano Zampini                   }
6526984c4197SStefano Zampini                 }
6527984c4197SStefano Zampini               }
6528674ae819SStefano Zampini             } else {
65299566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
6530674ae819SStefano Zampini             }
6531674ae819SStefano Zampini           }
6532a717540cSStefano Zampini         } else { /* simple transformation block */
6533a717540cSStefano Zampini           PetscInt    row, col;
6534a6b551f4SStefano Zampini           PetscScalar val, norm;
6535a6b551f4SStefano Zampini 
65369566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6537792fecdfSBarry 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));
6538a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
65399162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
65409162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
6541bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
65429162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
65439566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
65449566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
6545a717540cSStefano Zampini             } else {
6546a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
65479162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
6548a717540cSStefano Zampini                 if (row != col) {
65499162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
6550a717540cSStefano Zampini                 } else {
65519162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
6552a717540cSStefano Zampini                 }
65539566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
6554a717540cSStefano Zampini               }
6555a717540cSStefano Zampini             }
6556a717540cSStefano Zampini           }
6557*48a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
6558a717540cSStefano Zampini         }
6559984c4197SStefano Zampini       } else {
6560*48a46eb9SPierre 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));
6561674ae819SStefano Zampini       }
6562674ae819SStefano Zampini     }
6563a717540cSStefano Zampini 
6564a717540cSStefano Zampini     /* free workspace */
6565a717540cSStefano Zampini     if (qr_needed) {
65661baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
65679566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
65689566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
65699566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
65709566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
65719566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
6572674ae819SStefano Zampini     }
65739566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
65749566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
65759566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
6576906d46d4SStefano Zampini 
6577906d46d4SStefano Zampini     /* assembling of global change of variable */
657888c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
6579bbb9e6c6SStefano Zampini       Mat      tmat;
658016f15bc4SStefano Zampini       PetscInt bs;
658116f15bc4SStefano Zampini 
65829566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
65839566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
65849566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
65859566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
65869566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
65879566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
65889566063dSJacob Faibussowitsch       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->ChangeOfBasisMatrix));
65899566063dSJacob Faibussowitsch       PetscCall(MatSetType(pcbddc->ChangeOfBasisMatrix, MATAIJ));
65909566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(pc->pmat, &bs));
65919566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(pcbddc->ChangeOfBasisMatrix, bs));
65929566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(pcbddc->ChangeOfBasisMatrix, local_size, local_size, global_size, global_size));
65939566063dSJacob Faibussowitsch       PetscCall(MatISSetMPIXAIJPreallocation_Private(tmat, pcbddc->ChangeOfBasisMatrix, PETSC_TRUE));
65949566063dSJacob Faibussowitsch       PetscCall(MatConvert(tmat, MATAIJ, MAT_REUSE_MATRIX, &pcbddc->ChangeOfBasisMatrix));
65959566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
65969566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
65979566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
65989566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
65999566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
66009566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
66019566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
660288c03ad3SStefano Zampini 
6603906d46d4SStefano Zampini       /* check */
6604906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
6605906d46d4SStefano Zampini         PetscReal error;
6606906d46d4SStefano Zampini         Vec       x, x_change;
6607906d46d4SStefano Zampini 
66089566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
66099566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
66109566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
66119566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
66129566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
66139566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
66149566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
66159566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
66169566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
66179566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
66189566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
66199566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
6620049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
66219566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
66229566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
6623906d46d4SStefano Zampini       }
6624b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
6625b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
6626b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6627bf3a8328SStefano Zampini 
662808401ef6SPierre 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");
6629b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
6630ac632422SStefano Zampini           Mat S_new, tmat;
6631bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
6632bbb9e6c6SStefano Zampini 
66339566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
66349566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
6635bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6636bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
6637bf3a8328SStefano Zampini             IS                     is_V;
66389566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
66399566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
66409566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
66419566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
66429566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
6643bf3a8328SStefano Zampini           }
66449566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
66459566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
66469566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
66479566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
6648bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6649bf3a8328SStefano Zampini             const PetscScalar *array;
6650bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
6651bf3a8328SStefano Zampini             PetscInt           i, n_V;
6652bf3a8328SStefano Zampini 
66539566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
66549566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
66559566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
66569566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
66579566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
6658b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
6659b087196eSStefano Zampini               PetscScalar val;
6660b087196eSStefano Zampini               PetscInt    idx;
6661b087196eSStefano Zampini 
6662b087196eSStefano Zampini               idx = idxs_V[i];
6663b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
66649566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
6665b087196eSStefano Zampini             }
66669566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
66679566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
66689566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
66699566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
66709566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
6671bf3a8328SStefano Zampini           }
6672ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
66739566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
6674ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
66759566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
66769566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
66779566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
66781baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
6679ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
66809566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
6681ac632422SStefano Zampini           }
66829566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
66839566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
6684b96c3477SStefano Zampini         }
6685c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
6686b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
6687c9db6a07SStefano Zampini           PetscInt i;
6688c9db6a07SStefano Zampini 
6689*48a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
66909566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
6691c9db6a07SStefano Zampini         }
6692b96c3477SStefano Zampini       }
669316909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
669416909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
669516909a7fSStefano Zampini       } else {
66969566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
669716909a7fSStefano Zampini       }
66981dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
669927b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
670072b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
67019566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
670272b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
670372b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
670472b8c272SStefano Zampini     }
67051dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
670627b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
67079566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
6708b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
6709906d46d4SStefano Zampini     } else {
67101dd7afcfSStefano Zampini       Mat benign_global = NULL;
671127b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
67121dd7afcfSStefano Zampini         Mat M;
67131dd7afcfSStefano Zampini 
67149e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
67159566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
67169566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
67179566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
67189e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
67199566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
67209566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
6721906d46d4SStefano Zampini         } else {
67229566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
67239566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
6724906d46d4SStefano Zampini         }
67259566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
67269566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
67279566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
67289566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
67291dd7afcfSStefano Zampini       }
67301dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
67319566063dSJacob Faibussowitsch         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->ChangeOfBasisMatrix));
67329566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
673327b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
67341dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
67351dd7afcfSStefano Zampini       }
67361dd7afcfSStefano Zampini     }
673716909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
673816909a7fSStefano Zampini       IS              is_global;
673916909a7fSStefano Zampini       const PetscInt *gidxs;
674016909a7fSStefano Zampini 
67419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
67429566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
67439566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
67449566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
67459566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
674616909a7fSStefano Zampini     }
67471dd7afcfSStefano Zampini   }
6748*48a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
6749a717540cSStefano Zampini 
675072b8c272SStefano Zampini   if (!pcbddc->fake_change) {
67514f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
67524f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
67534f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
67544f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
6755019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
6756019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
6757019a44ceSStefano Zampini       pcbddc->local_primal_size++;
6758019a44ceSStefano Zampini     }
6759019a44ceSStefano Zampini 
6760019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
6761727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
6762727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
67639566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6764c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
67650e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
67669566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6767727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
6768727cdba6SStefano Zampini       }
67690e6343abSStefano Zampini     }
6770727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
67711c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
677272b8c272SStefano Zampini   }
67739566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
6774727cdba6SStefano Zampini 
6775a717540cSStefano Zampini   /* flush dbg viewer */
67761baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6777a717540cSStefano Zampini 
6778e310c8b4SStefano Zampini   /* free workspace */
67799566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
67809566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
678108122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
67829566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
67839566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
678408122e43SStefano Zampini   } else {
6785d0609cedSBarry 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));
67869566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
67879566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
678808122e43SStefano Zampini   }
6789674ae819SStefano Zampini   PetscFunctionReturn(0);
6790674ae819SStefano Zampini }
6791674ae819SStefano Zampini 
67929371c9d4SSatish Balay PetscErrorCode PCBDDCAnalyzeInterface(PC pc) {
679371582508SStefano Zampini   ISLocalToGlobalMapping map;
6794674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
6795674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
679666da6bd7Sstefano_zampini   PetscInt               i, N;
679766da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
6798674ae819SStefano Zampini 
6799674ae819SStefano Zampini   PetscFunctionBegin;
68008af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
6801b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
68028e61c736SStefano Zampini     /* Reset previously computed graph */
68039566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
6804674ae819SStefano Zampini     /* Init local Graph struct */
68059566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
68069566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
68079566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
6808674ae819SStefano Zampini 
6809*48a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
6810575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
68119371c9d4SSatish 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,
68129371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
68139577ea80SStefano Zampini 
6814674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
681566da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
68164d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
68174d379d7bSStefano Zampini       PetscInt  nvtxs;
6818e496cd5dSStefano Zampini       PetscBool flg_row = PETSC_FALSE;
6819674ae819SStefano Zampini 
68209566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
68212fffb893SStefano Zampini       if (flg_row) {
68229566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
6823b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
68242fffb893SStefano Zampini       }
68259566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
682666da6bd7Sstefano_zampini       rcsr = PETSC_TRUE;
6827674ae819SStefano Zampini     }
68281baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6829674ae819SStefano Zampini 
6830ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
6831ab8c8b98SStefano Zampini       PetscReal   *lcoords;
6832ab8c8b98SStefano Zampini       PetscInt     n;
6833ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
6834ab8c8b98SStefano Zampini 
68354f819b78SStefano Zampini       /* TODO: support for blocked */
683663a3b9bcSJacob 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);
68379566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
68389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
68399566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_contiguous(pcbddc->mat_graph->cdim, MPIU_REAL, &dimrealtype));
68409566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
68419566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
68429566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
68439566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
68449566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
6845ab8c8b98SStefano Zampini 
6846ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
6847ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
6848ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
6849ab8c8b98SStefano Zampini     }
68509371c9d4SSatish 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,
68519371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
6852625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
6853ab8c8b98SStefano Zampini 
6854674ae819SStefano Zampini     /* Setup of Graph */
68554b2aedd3SStefano Zampini     pcbddc->mat_graph->commsizelimit = 0; /* don't use the COMM_SELF variant of the graph */
68569566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
6857674ae819SStefano Zampini 
68584f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
68594f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
686020c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
68614f1b2e48SStefano Zampini 
68629566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
68639566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
686420c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
68654f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
68664f1b2e48SStefano Zampini         const PetscInt *idxs;
68674f1b2e48SStefano Zampini         PetscInt        nl, j;
68684f1b2e48SStefano Zampini 
68699566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
68709566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
687171582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
68729566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
68734f1b2e48SStefano Zampini       }
687420c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
687520c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
68764f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
68774f1b2e48SStefano Zampini     }
68788af8fcf9SStefano Zampini   }
68794f1b2e48SStefano Zampini 
6880cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
6881674ae819SStefano Zampini     /* Graph's connected components analysis */
68829566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
688371582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
68844f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
68858af8fcf9SStefano Zampini   }
688666da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
6887674ae819SStefano Zampini   PetscFunctionReturn(0);
6888674ae819SStefano Zampini }
6889674ae819SStefano Zampini 
68909371c9d4SSatish Balay PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[]) {
6891295df10fSStefano Zampini   PetscInt     i, j, n;
68929a7d3425SStefano Zampini   PetscScalar *alphas;
6893295df10fSStefano Zampini   PetscReal    norm, *onorms;
68949a7d3425SStefano Zampini 
68959a7d3425SStefano Zampini   PetscFunctionBegin;
6896295df10fSStefano Zampini   n = *nio;
68978c0031efSStefano Zampini   if (!n) PetscFunctionReturn(0);
68989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
68999566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
690092cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
6901295df10fSStefano Zampini     onorms[0] = 0.0;
69029566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
6903295df10fSStefano Zampini   } else {
6904295df10fSStefano Zampini     onorms[0] = norm;
690592cccca0SStefano Zampini   }
6906295df10fSStefano Zampini 
69078c0031efSStefano Zampini   for (i = 1; i < n; i++) {
69089566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
69098c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
69109566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
69119566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
691292cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
6913295df10fSStefano Zampini       onorms[i] = 0.0;
69149566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
6915295df10fSStefano Zampini     } else {
6916295df10fSStefano Zampini       onorms[i] = norm;
691792cccca0SStefano Zampini     }
69189a7d3425SStefano Zampini   }
6919295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
6920295df10fSStefano Zampini   for (i = 0; i < n; i++) {
6921295df10fSStefano Zampini     if (onorms[i] == 0.0) {
6922295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
6923295df10fSStefano Zampini         if (onorms[j] != 0.0) {
69249566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
6925295df10fSStefano Zampini           onorms[j] = 0.0;
6926295df10fSStefano Zampini         }
6927295df10fSStefano Zampini       }
6928295df10fSStefano Zampini     }
6929295df10fSStefano Zampini   }
6930295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
69319566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
69329a7d3425SStefano Zampini   PetscFunctionReturn(0);
69339a7d3425SStefano Zampini }
69349a7d3425SStefano Zampini 
69359371c9d4SSatish Balay PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void) {
6936e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
693757de7509SStefano Zampini   Mat                    A;
6938e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
6939e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
694052e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
694152e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
6942bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
694357de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
694427b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
694527b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
694627b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
694727b6a85dSStefano Zampini   MPI_Comm               subcomm;
6948a57a6d2fSStefano Zampini 
6949e7931f94SStefano Zampini   PetscFunctionBegin;
695057de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
69519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
695228b400f6SJacob 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);
695357de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
695457de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
695563a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
695657de7509SStefano Zampini 
695757de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
69589566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
69599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
69609566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
69619566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
6962bb360cb4SStefano Zampini   im_active = !!n;
69631c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
696457de7509SStefano Zampini   void_procs = size - active_procs;
696557de7509SStefano Zampini   /* get ranks of of non-active processes in mat communicator */
696657de7509SStefano Zampini   if (void_procs) {
696757de7509SStefano Zampini     PetscInt ncand;
696857de7509SStefano Zampini 
696957de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
69709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
69719566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
697257de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
69739371c9d4SSatish Balay       if (!procs_candidates[i]) { procs_candidates[ncand++] = i; }
697457de7509SStefano Zampini     }
697557de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
697657de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
697757de7509SStefano Zampini   }
697857de7509SStefano Zampini 
6979bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
69809dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
69819566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
6982bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
698314f0bfb9SStefano Zampini     PetscInt issize, isidx, dest;
698414f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
698514f0bfb9SStefano Zampini     else dest = rank;
698657de7509SStefano Zampini     if (im_active) {
698757de7509SStefano Zampini       issize = 1;
698857de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
698914f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
699057de7509SStefano Zampini       } else {
699114f0bfb9SStefano Zampini         isidx = dest;
699257de7509SStefano Zampini       }
699357de7509SStefano Zampini     } else {
699457de7509SStefano Zampini       issize = 0;
699557de7509SStefano Zampini       isidx  = -1;
699657de7509SStefano Zampini     }
6997bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
69989566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
69999566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
700057de7509SStefano Zampini     PetscFunctionReturn(0);
700157de7509SStefano Zampini   }
70029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-matis_partitioning_use_vwgt", &use_vwgt, NULL));
70039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-matis_partitioning_threshold", &threshold, NULL));
700427b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7005e7931f94SStefano Zampini 
7006e7931f94SStefano Zampini   /* Get info on mapping */
70079566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
70089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7009e7931f94SStefano Zampini 
7010e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
70119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7012e7931f94SStefano Zampini   xadj[0] = 0;
7013e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
70149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
70159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
70169566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
701727b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
70189371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7019e7931f94SStefano Zampini 
702027b6a85dSStefano Zampini   xadj_count = 0;
70212b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
702227b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
702327b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7024d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7025d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7026d023bfaeSStefano Zampini         xadj_count++;
702727b6a85dSStefano Zampini         break;
702827b6a85dSStefano Zampini       }
7029e7931f94SStefano Zampini     }
7030e7931f94SStefano Zampini   }
7031d023bfaeSStefano Zampini   xadj[1] = xadj_count;
70329566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
70339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
70349566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7035e7931f94SStefano Zampini 
70369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7037e7931f94SStefano Zampini 
703827b6a85dSStefano Zampini   /* Restrict work on active processes only */
70399566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
704027b6a85dSStefano Zampini   if (void_procs) {
70419566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
70429566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
70439566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
704427b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
704527b6a85dSStefano Zampini   } else {
704627b6a85dSStefano Zampini     psubcomm = NULL;
704727b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
704827b6a85dSStefano Zampini   }
704927b6a85dSStefano Zampini 
705027b6a85dSStefano Zampini   v_wgt = NULL;
705127b6a85dSStefano Zampini   if (!color) {
70529566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
70539566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
70549566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7055c8587f34SStefano Zampini   } else {
705652e5ac9dSStefano Zampini     Mat             subdomain_adj;
705752e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
705852e5ac9dSStefano Zampini     MatPartitioning partitioner;
705927b6a85dSStefano Zampini     PetscInt        rstart = 0, rend = 0;
706052e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
706157de7509SStefano Zampini     PetscMPIInt     size;
7062b0c7d250SStefano Zampini     PetscBool       aggregate;
7063b0c7d250SStefano Zampini 
70649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
706527b6a85dSStefano Zampini     if (void_procs) {
706627b6a85dSStefano Zampini       PetscInt prank = rank;
70679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
70689566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
7069*48a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
70709566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
707127b6a85dSStefano Zampini     } else {
707227b6a85dSStefano Zampini       oldranks = NULL;
707327b6a85dSStefano Zampini     }
7074b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
707527b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7076b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7077b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7078b0c7d250SStefano Zampini       PetscScalar *vals;
7079b0c7d250SStefano Zampini 
70809566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7081b0c7d250SStefano Zampini       lrows = 0;
7082b0c7d250SStefano Zampini       if (nrank < redprocs) {
7083b0c7d250SStefano Zampini         lrows = size / redprocs;
7084b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7085b0c7d250SStefano Zampini       }
70869566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
70879566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
70889566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
70899566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7090b0c7d250SStefano Zampini       row   = nrank;
7091b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7092b0c7d250SStefano Zampini       cols  = adjncy;
70939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7094b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
70959566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
70969566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
70979566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
70989566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
70999566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
71009566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
71019566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
710227b6a85dSStefano Zampini       if (use_vwgt) {
710327b6a85dSStefano Zampini         Vec                v;
710427b6a85dSStefano Zampini         const PetscScalar *array;
710527b6a85dSStefano Zampini         PetscInt           nl;
710627b6a85dSStefano Zampini 
71079566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
71089566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
71099566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
71109566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
71119566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
71129566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
71139566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
711422db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
71159566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
71169566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
711727b6a85dSStefano Zampini       }
7118b0c7d250SStefano Zampini     } else {
71199566063dSJacob Faibussowitsch       PetscCall(MatCreateMPIAdj(subcomm, 1, (PetscInt)size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
712027b6a85dSStefano Zampini       if (use_vwgt) {
71219566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7122bb360cb4SStefano Zampini         v_wgt[0] = n;
712327b6a85dSStefano Zampini       }
7124b0c7d250SStefano Zampini     }
71259566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7126e7931f94SStefano Zampini 
7127e7931f94SStefano Zampini     /* Partition */
71289566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7129ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
71309566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7131ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
71329566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7133ce64c636SStefano Zampini #else
71349566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7135ce64c636SStefano Zampini #endif
71369566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
71371baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
713857de7509SStefano Zampini     *n_subdomains = PetscMin((PetscInt)size, *n_subdomains);
71399566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
71409566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
71419566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
71429566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7143e7931f94SStefano Zampini 
714452e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
71459566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
71469566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
71479566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
714857de7509SStefano Zampini     if (!aggregate) {
714957de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
71506bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
715157de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
715227b6a85dSStefano Zampini       } else if (oldranks) {
7153b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
715427b6a85dSStefano Zampini       } else {
715527b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
715657de7509SStefano Zampini       }
715728143c3dSStefano Zampini     } else {
71587fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7159b0c7d250SStefano Zampini       PetscMPIInt  tag;
7160b0c7d250SStefano Zampini       MPI_Request *reqs;
7161b0c7d250SStefano Zampini 
71629566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
71639566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
7164*48a46eb9SPierre Jolivet       for (i = rstart; i < rend; i++) PetscCallMPI(MPI_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
71659566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
71669566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Waitall(rend - rstart, reqs, MPI_STATUSES_IGNORE));
71679566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
716857de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
71696bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
71707fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
717127b6a85dSStefano Zampini       } else if (oldranks) {
71727fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
717327b6a85dSStefano Zampini       } else {
71747fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
717528143c3dSStefano Zampini       }
717657de7509SStefano Zampini     }
71779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7178e7931f94SStefano Zampini     /* clean up */
71799566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
71809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
71819566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
71829566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
7183e7931f94SStefano Zampini   }
71849566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
71859566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
7186e7931f94SStefano Zampini 
7187e7931f94SStefano Zampini   /* assemble parallel IS for sends */
7188e7931f94SStefano Zampini   i = 1;
718927b6a85dSStefano Zampini   if (!color) i = 0;
71909566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
7191e7931f94SStefano Zampini   PetscFunctionReturn(0);
7192e7931f94SStefano Zampini }
7193e7931f94SStefano Zampini 
71949371c9d4SSatish Balay typedef enum {
71959371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
71969371c9d4SSatish Balay   MATAIJ_PRIVATE,
71979371c9d4SSatish Balay   MATBAIJ_PRIVATE,
71989371c9d4SSatish Balay   MATSBAIJ_PRIVATE
71999371c9d4SSatish Balay } MatTypePrivate;
7200e7931f94SStefano Zampini 
72019371c9d4SSatish Balay 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[]) {
720270cf5478SStefano Zampini   Mat                    local_mat;
7203e7931f94SStefano Zampini   IS                     is_sends_internal;
72049d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
72051ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
72069d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
7207e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
7208e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
7209e7931f94SStefano Zampini   const PetscInt        *is_indices;
7210e7931f94SStefano Zampini   MatType                new_local_type;
7211e7931f94SStefano Zampini   /* buffers */
7212e7931f94SStefano Zampini   PetscInt              *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
721328143c3dSStefano Zampini   PetscInt              *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
72149d30be91SStefano Zampini   PetscInt              *recv_buffer_idxs_local;
72151683a169SBarry Smith   PetscScalar           *ptr_vals, *recv_buffer_vals;
72161683a169SBarry Smith   const PetscScalar     *send_buffer_vals;
72171ae86dd6SStefano Zampini   PetscScalar           *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
7218e7931f94SStefano Zampini   /* MPI */
721928143c3dSStefano Zampini   MPI_Comm               comm, comm_n;
722028143c3dSStefano Zampini   PetscSubcomm           subcomm;
7221e569e4e1SStefano Zampini   PetscMPIInt            n_sends, n_recvs, size;
722228143c3dSStefano Zampini   PetscMPIInt           *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
722328143c3dSStefano Zampini   PetscMPIInt           *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
72241ae86dd6SStefano Zampini   PetscMPIInt            len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
72251ae86dd6SStefano Zampini   MPI_Request           *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
72261ae86dd6SStefano Zampini   MPI_Request           *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
7227e7931f94SStefano Zampini 
7228e7931f94SStefano Zampini   PetscFunctionBegin;
722957de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
72309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
72315f80ce2aSJacob 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);
723257de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
723357de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
723457de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
723557de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
723657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
72371ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
72381ae86dd6SStefano Zampini   if (nvecs) {
723908401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
72401ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
72411ae86dd6SStefano Zampini   }
724257de7509SStefano Zampini   /* further checks */
72439566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
72449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
72455f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
72469566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
72475f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
724857de7509SStefano Zampini   if (reuse && *mat_n) {
724970cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
725057de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
72519566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
72525f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
72539566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
72549566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
725563a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
725663a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
725770cf5478SStefano Zampini   }
72589566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
7259064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
726057de7509SStefano Zampini 
7261e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
7262e7931f94SStefano Zampini   if (!is_sends) {
72635f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
72649566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
7265c8587f34SStefano Zampini   } else {
72669566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
7267e7931f94SStefano Zampini     is_sends_internal = is_sends;
7268c8587f34SStefano Zampini   }
7269e7931f94SStefano Zampini 
7270e7931f94SStefano Zampini   /* get comm */
72719566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7272e7931f94SStefano Zampini 
7273e7931f94SStefano Zampini   /* compute number of sends */
72749566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
72759566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
7276e7931f94SStefano Zampini 
7277e7931f94SStefano Zampini   /* compute number of receives */
72789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
72799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
72809566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
72819566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
7282e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
72839566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
72849566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
7285e7931f94SStefano Zampini 
728628143c3dSStefano Zampini   /* restrict comm if requested */
72870a545947SLisandro Dalcin   subcomm     = NULL;
728828143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
728928143c3dSStefano Zampini   if (restrict_comm) {
7290779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
7291779c1cceSStefano Zampini 
729228143c3dSStefano Zampini     color = 0;
729353a05cb3SStefano Zampini     if (restrict_full) {
72946aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
729553a05cb3SStefano Zampini     } else {
72966aad120cSJose 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 */
729753a05cb3SStefano Zampini     }
72981c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
7299e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
730028143c3dSStefano Zampini     /* check if reuse has been requested */
730157de7509SStefano Zampini     if (reuse) {
730228143c3dSStefano Zampini       if (*mat_n) {
730328143c3dSStefano Zampini         PetscMPIInt subcommsize2;
73049566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
73055f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
730628143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
730728143c3dSStefano Zampini       } else {
730828143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
730928143c3dSStefano Zampini       }
731028143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
7311779c1cceSStefano Zampini       PetscMPIInt rank;
7312779c1cceSStefano Zampini 
73139566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
73149566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
73159566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
73169566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
7317306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
731828143c3dSStefano Zampini     }
731928143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
732028143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
732128143c3dSStefano Zampini   } else {
732228143c3dSStefano Zampini     comm_n = comm;
732328143c3dSStefano Zampini   }
732428143c3dSStefano Zampini 
7325e7931f94SStefano Zampini   /* prepare send/receive buffers */
73269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
73279566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
73289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
73299566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
7330*48a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
7331e7931f94SStefano Zampini 
733228143c3dSStefano Zampini   /* Get data from local matrices */
7333e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
7334e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
7335e7931f94SStefano Zampini   /*
7336e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
7337e7931f94SStefano Zampini        send_buffer_idxs should contain:
7338e7931f94SStefano Zampini        - MatType_PRIVATE type
7339e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
7340e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
7341e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
7342e7931f94SStefano Zampini     */
7343e432b41dSStefano Zampini   {
7344e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
7345e432b41dSStefano Zampini 
73469566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
73479566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
73489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
73499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
7350e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
7351e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
73529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
73539566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
73549566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
73559566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
7356e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
7357e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
7358e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
7359c8587f34SStefano Zampini     }
7360c8587f34SStefano Zampini   }
73619566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
736228143c3dSStefano Zampini   /* additional is (if any) */
736328143c3dSStefano Zampini   if (nis) {
736428143c3dSStefano Zampini     PetscMPIInt psum;
736528143c3dSStefano Zampini     PetscInt    j;
736628143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
736728143c3dSStefano Zampini       PetscInt plen;
73689566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
73699566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
73706aad120cSJose E. Roman       psum += len + 1; /* indices + length */
737128143c3dSStefano Zampini     }
73729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
737328143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
737428143c3dSStefano Zampini       PetscInt        plen;
737528143c3dSStefano Zampini       const PetscInt *is_array_idxs;
73769566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
737728143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
73789566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
73799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
73809566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
73816aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
738228143c3dSStefano Zampini     }
73839371c9d4SSatish Balay     for (i = 0; i < n_sends; i++) { ilengths_idxs_is[is_indices[i]] = psum; }
73849566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
738528143c3dSStefano Zampini   }
73869566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
738728143c3dSStefano Zampini 
7388e7931f94SStefano Zampini   buf_size_idxs    = 0;
7389e7931f94SStefano Zampini   buf_size_vals    = 0;
739028143c3dSStefano Zampini   buf_size_idxs_is = 0;
73911ae86dd6SStefano Zampini   buf_size_vecs    = 0;
7392e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7393e7931f94SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
7394e7931f94SStefano Zampini     buf_size_vals += (PetscInt)olengths_vals[i];
739528143c3dSStefano Zampini     if (nis) buf_size_idxs_is += (PetscInt)olengths_idxs_is[i];
73961ae86dd6SStefano Zampini     if (nvecs) buf_size_vecs += (PetscInt)olengths_idxs[i];
7397e7931f94SStefano Zampini   }
73989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
73999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
74009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
74019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
7402e7931f94SStefano Zampini 
7403e7931f94SStefano Zampini   /* get new tags for clean communications */
74049566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
74059566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
74069566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
74079566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
7408e7931f94SStefano Zampini 
7409e7931f94SStefano Zampini   /* allocate for requests */
74109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
74119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
74129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
74139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
74149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
74159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
74169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
74179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
7418e7931f94SStefano Zampini 
7419e7931f94SStefano Zampini   /* communications */
7420e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
7421e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
742228143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
74231ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
7424e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7425e7931f94SStefano Zampini     source_dest = onodes[i];
74269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, source_dest, tag_idxs, comm, &recv_req_idxs[i]));
74279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, source_dest, tag_vals, comm, &recv_req_vals[i]));
7428e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7429e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
743028143c3dSStefano Zampini     if (nis) {
743157de7509SStefano Zampini       source_dest = onodes_is[i];
74329566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_idxs_is, olengths_idxs_is[i], MPIU_INT, source_dest, tag_idxs_is, comm, &recv_req_idxs_is[i]));
743328143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
743428143c3dSStefano Zampini     }
74351ae86dd6SStefano Zampini     if (nvecs) {
74361ae86dd6SStefano Zampini       source_dest = onodes[i];
74379566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &recv_req_vecs[i]));
74381ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
74391ae86dd6SStefano Zampini     }
7440e7931f94SStefano Zampini   }
7441e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
74429566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
74439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
74449566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend((PetscScalar *)send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
7445*48a46eb9SPierre Jolivet     if (nis) PetscCallMPI(MPI_Isend(send_buffer_idxs_is, ilengths_idxs_is[source_dest], MPIU_INT, source_dest, tag_idxs_is, comm, &send_req_idxs_is[i]));
74461ae86dd6SStefano Zampini     if (nvecs) {
74479566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
74489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
74491ae86dd6SStefano Zampini     }
7450e7931f94SStefano Zampini   }
74519566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
74529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
7453e7931f94SStefano Zampini 
7454e7931f94SStefano Zampini   /* assemble new l2g map */
74559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
7456e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
74579d30be91SStefano Zampini   new_local_rows = 0;
7458e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
74599d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7460e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7461e7931f94SStefano Zampini   }
74629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
7463e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
74649d30be91SStefano Zampini   new_local_rows = 0;
7465e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
74669566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
74679d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7468e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7469e7931f94SStefano Zampini   }
74709566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
74719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
74729566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
7473e7931f94SStefano Zampini 
7474e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
7475e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
7476e7931f94SStefano 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) */
7477e7931f94SStefano Zampini   if (n_recvs) {
747828143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
7479e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
7480e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
7481e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
7482e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
7483e7931f94SStefano Zampini         break;
7484e7931f94SStefano Zampini       }
7485e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
7486e7931f94SStefano Zampini     }
7487e7931f94SStefano Zampini     switch (new_local_type_private) {
748828143c3dSStefano Zampini     case MATDENSE_PRIVATE:
7489e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7490e7931f94SStefano Zampini       bs             = 1;
7491e7931f94SStefano Zampini       break;
7492e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
7493e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7494e7931f94SStefano Zampini       bs             = 1;
7495e7931f94SStefano Zampini       break;
74969371c9d4SSatish Balay     case MATBAIJ_PRIVATE: new_local_type = MATSEQBAIJ; break;
74979371c9d4SSatish Balay     case MATSBAIJ_PRIVATE: new_local_type = MATSEQSBAIJ; break;
74989371c9d4SSatish Balay     default: SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
7499e7931f94SStefano Zampini     }
7500ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
7501ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
750228143c3dSStefano Zampini     bs             = 1;
7503e7931f94SStefano Zampini   }
7504e7931f94SStefano Zampini 
750570cf5478SStefano Zampini   /* create MATIS object if needed */
750657de7509SStefano Zampini   if (!reuse) {
75079566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
75089566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
750970cf5478SStefano Zampini   } else {
751070cf5478SStefano Zampini     /* it also destroys the local matrices */
751157de7509SStefano Zampini     if (*mat_n) {
75129566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
751357de7509SStefano Zampini     } else { /* this is a fake object */
75149566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
751557de7509SStefano Zampini     }
751670cf5478SStefano Zampini   }
75179566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
75189566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
75199d30be91SStefano Zampini 
75209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
75219d30be91SStefano Zampini 
75229d30be91SStefano Zampini   /* Global to local map of received indices */
75239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
75249566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
75259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
75269d30be91SStefano Zampini 
75279d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
75289d30be91SStefano Zampini   buf_size_idxs = 0;
75299d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75309d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
75319d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
75329d30be91SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
75339d30be91SStefano Zampini   }
75349566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
75359d30be91SStefano Zampini 
75369d30be91SStefano Zampini   /* set preallocation */
75379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
75389d30be91SStefano Zampini   if (!newisdense) {
75390a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
75409d30be91SStefano Zampini 
75419d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
7542*48a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
75439d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
75449d30be91SStefano Zampini       PetscInt j;
75459d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
75469371c9d4SSatish Balay         for (j = 0; j < *(ptr_idxs + 1); j++) { new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1); }
75479d30be91SStefano Zampini       } else {
75489d30be91SStefano Zampini         /* TODO */
75499d30be91SStefano Zampini       }
75509d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
75519d30be91SStefano Zampini     }
75529d30be91SStefano Zampini     if (new_local_nnz) {
75539d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
75549566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
75559d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
75569566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
75579d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
75589566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
75599d30be91SStefano Zampini     } else {
75609566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
75619d30be91SStefano Zampini     }
75629566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
75639d30be91SStefano Zampini   } else {
75649566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
75659d30be91SStefano Zampini   }
7566e7931f94SStefano Zampini 
7567e7931f94SStefano Zampini   /* set values */
7568e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
75699d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
7570e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7571e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
75729566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
75739566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
75749566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
75759566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
75769566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
757728143c3dSStefano Zampini     } else {
757828143c3dSStefano Zampini       /* TODO */
7579e7931f94SStefano Zampini     }
7580e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7581e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
7582e7931f94SStefano Zampini   }
75839566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
75849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
75859566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
75869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
75879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
75889566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
7589e7931f94SStefano Zampini 
7590dfd14d43SStefano Zampini #if 0
759128143c3dSStefano Zampini   if (!restrict_comm) { /* check */
7592e7931f94SStefano Zampini     Vec       lvec,rvec;
7593e7931f94SStefano Zampini     PetscReal infty_error;
7594e7931f94SStefano Zampini 
75959566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
75969566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
75979566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
75989566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
75999566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
76009566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
76019566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
76029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
76039566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
7604e7931f94SStefano Zampini   }
760528143c3dSStefano Zampini #endif
7606e7931f94SStefano Zampini 
760728143c3dSStefano Zampini   /* assemble new additional is (if any) */
760828143c3dSStefano Zampini   if (nis) {
760928143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
761028143c3dSStefano Zampini 
76119566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
76129566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
761328143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
761428143c3dSStefano Zampini     psum     = 0;
761528143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
761628143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
761728143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
761828143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
761928143c3dSStefano Zampini         psum += plen;
762028143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
762128143c3dSStefano Zampini       }
762228143c3dSStefano Zampini     }
76239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
76249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
76259371c9d4SSatish Balay     for (i = 1; i < nis; i++) { temp_idxs[i] = temp_idxs[i - 1] + count_is[i - 1]; }
76269566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
762728143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
762828143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
762928143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
763028143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
76319566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
763228143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
763328143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
763428143c3dSStefano Zampini       }
763528143c3dSStefano Zampini     }
763628143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
76379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
76389566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
76399566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
764028143c3dSStefano Zampini     }
76419566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
76429566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
76439566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
764428143c3dSStefano Zampini   }
7645e7931f94SStefano Zampini   /* free workspace */
76469566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
76479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
76489566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
76499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
7650e7931f94SStefano Zampini   if (isdense) {
76519566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
76529566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
76539566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
7654e7931f94SStefano Zampini   } else {
76559566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
7656e7931f94SStefano Zampini   }
765728143c3dSStefano Zampini   if (nis) {
76589566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
76599566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
766028143c3dSStefano Zampini   }
76611ae86dd6SStefano Zampini 
76621ae86dd6SStefano Zampini   if (nvecs) {
76639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
76649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
76659566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
76669566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
76679566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
76689566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
76699566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
76701ae86dd6SStefano Zampini     /* set values */
76711ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
76721ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
76739566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
76741ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
76751ae86dd6SStefano Zampini       PetscInt j;
76769371c9d4SSatish Balay       for (j = 0; j < *(ptr_idxs + 1); j++) { send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j); }
76771ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
76781ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
76791ae86dd6SStefano Zampini     }
76809566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
76819566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
76829566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
76831ae86dd6SStefano Zampini   }
76841ae86dd6SStefano Zampini 
76859566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
76869566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
76879566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
76889566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
76899566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
76909566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
76919566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
76929566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
76939566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
76949566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
76959566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
76969566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
76979566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
76989566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
76999566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
770028143c3dSStefano Zampini   if (nis) {
77019566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
77029566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
77039566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
770428143c3dSStefano Zampini   }
77059566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
77066aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
77079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
7708*48a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
77091ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
77109566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
77111ae86dd6SStefano Zampini     }
771253a05cb3SStefano Zampini     *mat_n = NULL;
771328143c3dSStefano Zampini   }
7714e7931f94SStefano Zampini   PetscFunctionReturn(0);
7715e7931f94SStefano Zampini }
7716a57a6d2fSStefano Zampini 
771712edc857SStefano Zampini /* temporary hack into ksp private data structure */
7718af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
771912edc857SStefano Zampini 
77209371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, PetscScalar *coarse_submat_vals) {
7721c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7722c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
772320a2ab83SStefano Zampini   Mat                    coarse_mat, coarse_mat_is, coarse_submat_dense;
77241ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
77251e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
77269881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
772720a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
77284f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
77296e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
773030368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
7731e569e4e1SStefano Zampini   PetscInt               coarse_eqs_per_proc;
7732f9eb5b7dSStefano Zampini   PC                     pc_temp;
7733c8587f34SStefano Zampini   PCType                 coarse_pc_type;
7734c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
7735f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
77367274672aSStefano Zampini   PetscBool              coarse_reuse;
77371e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
773868457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
773922bc73bbSStefano Zampini   PetscScalar           *array;
774057de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
774157de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
7742e569e4e1SStefano Zampini   PetscMPIInt            size;
7743fdc09c96SStefano Zampini 
7744c8587f34SStefano Zampini   PetscFunctionBegin;
77459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
7746c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
774768457ee5SStefano 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 */
7748fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
77495a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
77507de4f681Sstefano_zampini 
77517de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
7752fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
77539566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
77549566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
7755f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
7756fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
775751bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
775851bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
77599566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
7760fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
7761fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
7762fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
7763f4ddd8eeSStefano Zampini       }
7764fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
7765fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
7766f4ddd8eeSStefano Zampini     }
776770cf5478SStefano Zampini     /* reset any subassembling information */
7768*48a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
77696e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
7770fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
7771f4ddd8eeSStefano Zampini   }
777257de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
77739566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
77749566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
777557de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
777618a45a71SStefano Zampini   } else {
777757de7509SStefano Zampini     coarse_mat       = NULL;
777857de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
77796e683305SStefano Zampini   }
7780e7931f94SStefano Zampini 
7781abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
77829566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
77839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
7784abbbba34SStefano Zampini 
7785abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
77869566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_submat_dense));
77879566063dSJacob Faibussowitsch   PetscCall(MatCreateIS(PetscObjectComm((PetscObject)pc), 1, PETSC_DECIDE, PETSC_DECIDE, pcbddc->coarse_size, pcbddc->coarse_size, coarse_islg, coarse_islg, &t_coarse_mat_is));
77889566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat_dense));
77899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
77909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
77919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_submat_dense));
7792abbbba34SStefano Zampini 
779357de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
779457de7509SStefano Zampini   im_active = !!(pcis->n);
77951c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
779657de7509SStefano Zampini 
779714f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
779828d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
779957de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
78009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
780157de7509SStefano Zampini   coarse_mat_is        = NULL;
780257de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
780357de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
7804e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
7805ce64c636SStefano Zampini   if (coarse_eqs_per_proc < 0) coarse_eqs_per_proc = pcbddc->coarse_size;
780657de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
7807e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
780857de7509SStefano Zampini   if (multilevel_requested) {
780957de7509SStefano Zampini     ncoarse    = active_procs / pcbddc->coarsening_ratio;
781057de7509SStefano Zampini     restr      = PETSC_FALSE;
781157de7509SStefano Zampini     full_restr = PETSC_FALSE;
781257de7509SStefano Zampini   } else {
7813e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
781457de7509SStefano Zampini     restr      = PETSC_TRUE;
781557de7509SStefano Zampini     full_restr = PETSC_TRUE;
781657de7509SStefano Zampini   }
7817e569e4e1SStefano Zampini   if (!pcbddc->coarse_size || size == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
781857de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
781957de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
7820a198735bSStefano Zampini     if (pcbddc->coarsening_ratio > 1) {
7821bb360cb4SStefano Zampini       if (multilevel_requested) {
78229566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7823bb360cb4SStefano Zampini       } else {
78249566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7825bb360cb4SStefano Zampini       }
7826a198735bSStefano Zampini     } else {
78277de4f681Sstefano_zampini       PetscMPIInt rank;
782828d58a37SPierre Jolivet 
78299566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
7830e569e4e1SStefano Zampini       have_void = (active_procs == (PetscInt)size) ? PETSC_FALSE : PETSC_TRUE;
78319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
7832a198735bSStefano Zampini     }
783357de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
783457de7509SStefano Zampini     PetscInt psum;
783557de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
783657de7509SStefano Zampini     else psum = 0;
78371c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
7838075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
783957de7509SStefano Zampini   }
784057de7509SStefano Zampini   /* determine if we can go multilevel */
784157de7509SStefano Zampini   if (multilevel_requested) {
784257de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
784357de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
784457de7509SStefano Zampini   }
784557de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
784657de7509SStefano Zampini 
7847e4d548c7SStefano Zampini   /* dump subassembling pattern */
7848*48a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
78496e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
78501e0482f5SStefano Zampini   nedcfield = -1;
78514f819b78SStefano Zampini   corners   = NULL;
78528966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
78536e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
78546e683305SStefano Zampini     const PetscInt        *idxs;
78556e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
78566e683305SStefano Zampini 
78576e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
78589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
78596e683305SStefano Zampini     /* allocate space for temporary storage */
78609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
78619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
78626e683305SStefano Zampini     /* allocate for IS array */
78636e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
78641e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
78651e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
78661e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
78671e0482f5SStefano Zampini       } else {
78681e0482f5SStefano Zampini         nedcfield = 0;
786963a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
78701e0482f5SStefano Zampini         nisdofs = 1;
78711e0482f5SStefano Zampini       }
78721e0482f5SStefano Zampini     }
78736e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
787427b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
787530368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
78769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
78776e683305SStefano Zampini     /* dofs splitting */
78786e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
78799566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
78801e0482f5SStefano Zampini       if (nedcfield != i) {
78819566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
78829566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
78839566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
78849566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
78851e0482f5SStefano Zampini       } else {
78869566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
78879566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
78889566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
788963a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
78909566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
78911e0482f5SStefano Zampini       }
78929566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
78939566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
78949566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
78956e683305SStefano Zampini     }
78966e683305SStefano Zampini     /* neumann boundaries */
78976e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
78989566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
78999566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
79009566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
79019566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
79029566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
79039566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
79049566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
79059566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
79066e683305SStefano Zampini     }
79074f819b78SStefano Zampini     /* coordinates */
79084f819b78SStefano Zampini     if (pcbddc->corner_selected) {
79099566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
79109566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
79119566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
79129566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
791363a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
79149566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
79159566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
79169566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
79179566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
79184f819b78SStefano Zampini     }
79199566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
79209566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
79219566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
79226e683305SStefano Zampini   } else {
79236e683305SStefano Zampini     nis     = 0;
79246e683305SStefano Zampini     nisdofs = 0;
79256e683305SStefano Zampini     nisneu  = 0;
792630368db7SStefano Zampini     nisvert = 0;
79276e683305SStefano Zampini     isarray = NULL;
79286e683305SStefano Zampini   }
79296e683305SStefano Zampini   /* destroy no longer needed map */
79309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
79316e683305SStefano Zampini 
793257de7509SStefano Zampini   /* subassemble */
793357de7509SStefano Zampini   if (multilevel_allowed) {
79341ae86dd6SStefano Zampini     Vec       vp[1];
79351ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
793657de7509SStefano Zampini     PetscBool reuse, reuser;
79371ae86dd6SStefano Zampini 
793857de7509SStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
793957de7509SStefano Zampini     else reuse = PETSC_FALSE;
79401c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&reuse, &reuser, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
79411ae86dd6SStefano Zampini     vp[0] = NULL;
79421ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
79439566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
79449566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
79459566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
79461ae86dd6SStefano Zampini       nvecs = 1;
79471ae86dd6SStefano Zampini 
79481ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
7949a198735bSStefano Zampini         Mat      B, loc_divudotp;
79501ae86dd6SStefano Zampini         Vec      v, p;
79511ae86dd6SStefano Zampini         IS       dummy;
79521ae86dd6SStefano Zampini         PetscInt np;
79531ae86dd6SStefano Zampini 
79549566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
79559566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
79569566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
79579566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
79589566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
79599566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
79609566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
79619566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
79629566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
79639566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
79649566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
79659566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
79669566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
79679566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
79689566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
79699566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
797074e2c79eSStefano Zampini       }
79711ae86dd6SStefano Zampini     }
79721ae86dd6SStefano Zampini     if (reuser) {
79739566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
797474e2c79eSStefano Zampini     } else {
79759566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
79761ae86dd6SStefano Zampini     }
79771ae86dd6SStefano Zampini     if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
79781683a169SBarry Smith       PetscScalar       *arraym;
79791683a169SBarry Smith       const PetscScalar *arrayv;
79801ae86dd6SStefano Zampini       PetscInt           nl;
79819566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vp[0], &nl));
79829566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
79839566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
79849566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(vp[0], &arrayv));
79859566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(arraym, arrayv, nl));
79869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
79879566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
79889566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vp[0]));
7989a198735bSStefano Zampini     } else {
79909566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
79911ae86dd6SStefano Zampini     }
79921ae86dd6SStefano Zampini   } else {
79939566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
79946e683305SStefano Zampini   }
799557de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
799657de7509SStefano Zampini     if (!multilevel_allowed) {
79979566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
79986e683305SStefano Zampini     } else {
799957de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
800057de7509SStefano Zampini       if (coarse_mat_is) {
800128b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
80029566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
800357de7509SStefano Zampini         coarse_mat = coarse_mat_is;
800457de7509SStefano Zampini       }
8005779c1cceSStefano Zampini     }
8006779c1cceSStefano Zampini   }
80079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
80089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
80096e683305SStefano Zampini 
80106e683305SStefano Zampini   /* create local to global scatters for coarse problem */
801168457ee5SStefano Zampini   if (compute_vecs) {
80126e683305SStefano Zampini     PetscInt lrows;
80139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
801457de7509SStefano Zampini     if (coarse_mat) {
80159566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
80166e683305SStefano Zampini     } else {
80176e683305SStefano Zampini       lrows = 0;
80186e683305SStefano Zampini     }
80199566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
80209566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
80219566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
80229566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
80239566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
80246e683305SStefano Zampini   }
80259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8026c8587f34SStefano Zampini 
8027f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8028f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8029f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8030f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8031f9eb5b7dSStefano Zampini   } else {
8032f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8033f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8034c8587f34SStefano Zampini   }
8035c8587f34SStefano Zampini 
80366e683305SStefano Zampini   /* print some info if requested */
80376e683305SStefano Zampini   if (pcbddc->dbg_flag) {
80386e683305SStefano Zampini     if (!multilevel_allowed) {
80399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
80406e683305SStefano Zampini       if (multilevel_requested) {
804163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Not enough active processes on level %" PetscInt_FMT " (active processes %" PetscInt_FMT ", coarsening ratio %" PetscInt_FMT ")\n", pcbddc->current_level, active_procs, pcbddc->coarsening_ratio));
80426e683305SStefano Zampini       } else if (pcbddc->max_levels) {
804363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
80446e683305SStefano Zampini       }
80459566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
80466e683305SStefano Zampini     }
80476e683305SStefano Zampini   }
80486e683305SStefano Zampini 
80491e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
80501e0482f5SStefano Zampini   coarseG = NULL;
80511e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
80521e0482f5SStefano Zampini     MPI_Comm ccomm;
80531e0482f5SStefano Zampini     if (coarse_mat) {
80541e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
80551e0482f5SStefano Zampini     } else {
80561e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
80571e0482f5SStefano Zampini     }
80589566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
80591e0482f5SStefano Zampini   }
80601e0482f5SStefano Zampini 
8061f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
806257de7509SStefano Zampini   if (coarse_mat) {
806328d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
80646a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8065b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
80667274672aSStefano Zampini 
80676e683305SStefano Zampini     if (pcbddc->dbg_flag) {
806857de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
80699566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
80706e683305SStefano Zampini     }
8071f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8072312be037SStefano Zampini       char   prefix[256], str_level[16];
8073e604994aSStefano Zampini       size_t len;
80741e0482f5SStefano Zampini 
80759566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
80769566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
80779566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
80789566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1));
80799566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
80809566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
80819566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
80829566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
80831e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
80849566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8085e604994aSStefano Zampini       /* prefix */
80869566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(prefix, ""));
80879566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(str_level, ""));
8088e604994aSStefano Zampini       if (!pcbddc->current_level) {
80899566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
80909566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8091c8587f34SStefano Zampini       } else {
80929566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8093312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8094312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8095a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
80969566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
80979566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)(pcbddc->current_level)));
80989566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8099e604994aSStefano Zampini       }
81009566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
81013e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
81029566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
81039566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
81049566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8105f9eb5b7dSStefano Zampini       /* allow user customization */
81069566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8107e569e4e1SStefano Zampini       /* get some info after set from options */
81089566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
810928d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
811028d58a37SPierre Jolivet       force = PETSC_FALSE;
81119566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
81129566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
81139566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
811428d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8115e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
81169566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
81179566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
81189566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
81199566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
81204f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8121d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8122dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8123dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8124d0609cedSBarry Smith           PetscOptionsEnd();
81254f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
81264f819b78SStefano Zampini         }
8127e569e4e1SStefano Zampini       }
81283e3c6dadSStefano Zampini     }
81293e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
81309566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
81313e3c6dadSStefano Zampini     if (nisdofs) {
81329566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
8133*48a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
81343e3c6dadSStefano Zampini     }
81353e3c6dadSStefano Zampini     if (nisneu) {
81369566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
81379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8138312be037SStefano Zampini     }
813930368db7SStefano Zampini     if (nisvert) {
81409566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
81419566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
814230368db7SStefano Zampini     }
81431baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8144f9eb5b7dSStefano Zampini 
8145f9eb5b7dSStefano Zampini     /* get some info after set from options */
81469566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
81474f819b78SStefano Zampini 
8148b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
8149*48a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
815028d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
815128d58a37SPierre Jolivet     force = PETSC_FALSE;
81529566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
81539566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
8154*48a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
81559566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
81564f3a063dSStefano Zampini     if (isredundant) {
81574f3a063dSStefano Zampini       KSP inner_ksp;
81584f3a063dSStefano Zampini       PC  inner_pc;
81599326c5c6Sstefano_zampini 
81609566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
81619566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
81624f3a063dSStefano Zampini     }
8163f9eb5b7dSStefano Zampini 
816457de7509SStefano Zampini     /* parameters which miss an API */
81659566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
816657de7509SStefano Zampini     if (isbddc) {
8167720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
81687274672aSStefano Zampini 
8169720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
817057de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8171e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
817227b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
817327b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
8174a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
8175a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
8176a198735bSStefano Zampini         IS                     row, col;
8177a198735bSStefano Zampini         const PetscInt        *gidxs;
8178a198735bSStefano Zampini         PetscInt               n, st, M, N;
8179a198735bSStefano Zampini 
81809566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
81819566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
8182a198735bSStefano Zampini         st = st - n;
81839566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
81849566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
81859566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
81869566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
81879566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
81889566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
81899566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
81909566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
81919566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
81929566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
81939566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
81949566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
81959566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
81969566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
81979566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
81989566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
81999566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
82009566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
82019566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
82029566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
82039566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
82049566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
8205720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8206bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8207720d30f9SStefano Zampini       }
8208d4d8cf7bSStefano Zampini     }
82099881197aSStefano Zampini 
82103301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
82119566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
8212b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
8213b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
8214b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
8215b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
8216b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
8217b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
8218b94d7dedSBarry Smith 
8219*48a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
82206e683305SStefano Zampini     /* set operators */
82219566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
82229566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
82239566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
82241baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
82256e683305SStefano Zampini   }
82269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
82279566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
8228b1ecc7b1SStefano Zampini #if 0
8229b9b85e73SStefano Zampini   {
8230b9b85e73SStefano Zampini     PetscViewer viewer;
8231b9b85e73SStefano Zampini     char filename[256];
8232b1ecc7b1SStefano Zampini     sprintf(filename,"coarse_mat_level%d.m",pcbddc->current_level);
82339566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
82349566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
82359566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
82369566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
82379566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
8238b9b85e73SStefano Zampini   }
8239b9b85e73SStefano Zampini #endif
8240f9eb5b7dSStefano Zampini 
82414f819b78SStefano Zampini   if (corners) {
82424f819b78SStefano Zampini     Vec             gv;
82434f819b78SStefano Zampini     IS              is;
82444f819b78SStefano Zampini     const PetscInt *idxs;
82454f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
82464f819b78SStefano Zampini     PetscScalar    *coords;
82474f819b78SStefano Zampini 
824828b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
82499566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
82509566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
82519566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
82529566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
82539566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
82549566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
82559566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
82569566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
82574f819b78SStefano Zampini 
82589566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
82599566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
82609566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
82619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
82624f819b78SStefano Zampini     for (i = 0; i < n; i++) {
82639371c9d4SSatish Balay       for (d = 0; d < cdim; d++) { coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d]; }
82644f819b78SStefano Zampini     }
82659566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
82669566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
82674f819b78SStefano Zampini 
82689566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
82699566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
82709566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
82719566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
82729566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
82739566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
82749566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
82759566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
82764f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
82774f819b78SStefano Zampini       PC        coarse_pc;
82784f819b78SStefano Zampini       PetscBool isbddc;
82794f819b78SStefano Zampini 
82809566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
82819566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
82824f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
82834f819b78SStefano Zampini         PetscReal *realcoords;
82844f819b78SStefano Zampini 
82859566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
82864f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
82879566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
82884f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
82894f819b78SStefano Zampini #else
82904f819b78SStefano Zampini         realcoords = coords;
82914f819b78SStefano Zampini #endif
82929566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
82934f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
82949566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
82954f819b78SStefano Zampini #endif
82964f819b78SStefano Zampini       }
82974f819b78SStefano Zampini     }
82989566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
82999566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
83004f819b78SStefano Zampini   }
83019566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
83024f819b78SStefano Zampini 
830398a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
830498a51de6SStefano Zampini     Vec crhs, csol;
830504708bb6SStefano Zampini 
83069566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
83079566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
8308*48a46eb9SPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &((pcbddc->coarse_ksp)->vec_sol), NULL));
8309*48a46eb9SPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &((pcbddc->coarse_ksp)->vec_rhs)));
8310b0f5fe93SStefano Zampini   }
83119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
8312b0f5fe93SStefano Zampini 
8313b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
8314b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
83159566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
8316*48a46eb9SPierre 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));
83179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
83189566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
83199566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
83209566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
8321b0f5fe93SStefano Zampini     if (coarse_mat) {
8322b0f5fe93SStefano Zampini       Vec          nullv;
8323b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
8324b0f5fe93SStefano Zampini       PetscInt     nl;
8325b0f5fe93SStefano Zampini 
83269566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
83279566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
83289566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
83299566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
83309566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
83319566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
83329566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
83339566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
83349566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
83359566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
8336b0f5fe93SStefano Zampini     }
8337b0f5fe93SStefano Zampini   }
83389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8339b0f5fe93SStefano Zampini 
83409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
8341b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
8342b0f5fe93SStefano Zampini     PetscBool ispreonly;
8343b0f5fe93SStefano Zampini 
8344b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
8345b0f5fe93SStefano Zampini       PetscBool isnull;
83467c625d9fSStefano Zampini 
83479566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
83481baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
8349bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
8350b0f5fe93SStefano Zampini     }
8351b0f5fe93SStefano Zampini     /* setup coarse ksp */
83529566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
8353cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
83549566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
83556e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
8356c8587f34SStefano Zampini       KSP         check_ksp;
83572b510759SStefano Zampini       KSPType     check_ksp_type;
8358c8587f34SStefano Zampini       PC          check_pc;
83596e683305SStefano Zampini       Vec         check_vec, coarse_vec;
83606a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
83612b510759SStefano Zampini       PetscInt    its;
83626e683305SStefano Zampini       PetscBool   compute_eigs;
83636e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
83646e683305SStefano Zampini       PetscInt    neigs;
83658e185a42SStefano Zampini       const char *prefix;
8366c8587f34SStefano Zampini 
83672b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
83689566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
83699566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
83709566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
83719566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
83729566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_DEFAULT, pcbddc->coarse_size));
8373e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
83749566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
83759566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
83762b510759SStefano Zampini       if (ispreonly) {
83772b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
83786e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
83792b510759SStefano Zampini       } else {
8380cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
83816e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
8382c8587f34SStefano Zampini       }
83839566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
83849566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
83859566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
83869566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
83879566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
83889566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
83899566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
83909566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
83919566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
83929566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
83939566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
8394c8587f34SStefano Zampini       /* create random vec */
83959566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
83969566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
83979566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
8398c8587f34SStefano Zampini       /* solve coarse problem */
83999566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
84009566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
8401cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
84026e683305SStefano Zampini       if (compute_eigs) {
84039566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
84049566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
84059566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
84061ae86dd6SStefano Zampini         if (neigs) {
84076e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
84086e683305SStefano Zampini           lambda_min = eigs_r[0];
84096e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
84102701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
84119566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
84129566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
8413cbcc2c2aSStefano Zampini             }
8414c8587f34SStefano Zampini           }
8415c8587f34SStefano Zampini         }
84161ae86dd6SStefano Zampini       }
8417cbcc2c2aSStefano Zampini 
8418c8587f34SStefano Zampini       /* check coarse problem residual error */
84196e683305SStefano Zampini       if (pcbddc->dbg_flag) {
84206e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
84219566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
84229566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
84239566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
84249566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
84259566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
84269566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
84279566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(pcbddc->coarse_ksp), dbg_viewer));
84289566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(check_pc), dbg_viewer));
842963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
843063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
8431*48a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
84326e683305SStefano Zampini         if (compute_eigs) {
84336e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
8434b03ebc13SStefano Zampini           KSPConvergedReason reason;
84359566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
84369566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
84379566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
84389566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
843963a3b9bcSJacob 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));
8440*48a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
84416e683305SStefano Zampini         }
84429566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
84439566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
84446e683305SStefano Zampini       }
84459566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
84469566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
84479566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
84486e683305SStefano Zampini       if (compute_eigs) {
84499566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
84509566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
8451c8587f34SStefano Zampini       }
84526e683305SStefano Zampini     }
84536e683305SStefano Zampini   }
84549566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
8455cbcc2c2aSStefano Zampini   /* print additional info */
8456cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
84576e683305SStefano Zampini     /* waits until all processes reaches this point */
84589566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
845963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
84609566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8461cbcc2c2aSStefano Zampini   }
8462cbcc2c2aSStefano Zampini 
84632b510759SStefano Zampini   /* free memory */
84649566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
84659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
8466c8587f34SStefano Zampini   PetscFunctionReturn(0);
8467c8587f34SStefano Zampini }
8468674ae819SStefano Zampini 
84699371c9d4SSatish Balay PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n) {
8470f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
8471f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
8472f34684f1SStefano Zampini   Mat_IS         *matis  = (Mat_IS *)pc->pmat->data;
8473dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
8474dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
847573be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
8476dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
8477f34684f1SStefano Zampini 
8478f34684f1SStefano Zampini   PetscFunctionBegin;
8479f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
848008401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
84819566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
84829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
84839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
84849566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
84859566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
84869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
84879566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
84889566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
848963a3b9bcSJacob 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);
84909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
84919566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
84929566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
84939566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
84949566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
8495f34684f1SStefano Zampini 
8496f34684f1SStefano Zampini   /* check numbering */
8497f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
8498019a44ceSStefano Zampini     PetscScalar coarsesum, *array, *array2;
8499dc456d91SStefano Zampini     PetscInt    i;
8500b9b85e73SStefano Zampini     PetscBool   set_error = PETSC_FALSE, set_error_reduced = PETSC_FALSE;
8501f34684f1SStefano Zampini 
85029566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
85039566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
85049566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse indices\n"));
85059566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
8506019a44ceSStefano Zampini     /* counter */
85079566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85089566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 1.0));
85099566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85109566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85119566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
85129566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
85139566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.0));
8514*48a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->local_primal_size; i++) PetscCall(VecSetValue(pcis->vec1_N, pcbddc->primal_indices_local_idxs[i], 1.0, INSERT_VALUES));
85159566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
85169566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
85179566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85189566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85199566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
85219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
85229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec1_N, &array));
85239566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec2_N, &array2));
8524f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8525019a44ceSStefano Zampini       if (array[i] != 0.0 && array[i] != array2[i]) {
85262c66d082SStefano Zampini         PetscInt owned = (PetscInt)PetscRealPart(array[i]), gi;
852775c01103SStefano Zampini         PetscInt neigh = (PetscInt)PetscRealPart(array2[i]);
8528b9b85e73SStefano Zampini         set_error      = PETSC_TRUE;
85299566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, 1, &i, &gi));
853063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d: local index %" PetscInt_FMT " (gid %" PetscInt_FMT ") owned by %" PetscInt_FMT " processes instead of %" PetscInt_FMT "!\n", PetscGlobalRank, i, gi, owned, neigh));
8531f34684f1SStefano Zampini       }
8532f34684f1SStefano Zampini     }
85339566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec2_N, &array2));
85341c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&set_error, &set_error_reduced, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
85359566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8536f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8537f34684f1SStefano Zampini       if (PetscRealPart(array[i]) > 0.0) array[i] = 1.0 / PetscRealPart(array[i]);
8538f34684f1SStefano Zampini     }
85399566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec1_N, &array));
85409566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85419566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85429566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85439566063dSJacob Faibussowitsch     PetscCall(VecSum(pcis->vec1_global, &coarsesum));
854463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT " (%lf)\n", coarse_size, (double)PetscRealPart(coarsesum)));
8545b9b85e73SStefano Zampini     if (pcbddc->dbg_flag > 1 || set_error_reduced) {
8546ca8b9ea9SStefano Zampini       PetscInt *gidxs;
8547ca8b9ea9SStefano Zampini 
85489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->local_primal_size, &gidxs));
85499566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, gidxs));
85509566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Distribution of local primal indices\n"));
85519566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
85529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d\n", PetscGlobalRank));
8553f34684f1SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
855463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "local_primal_indices[%" PetscInt_FMT "]=%" PetscInt_FMT " (%" PetscInt_FMT ",%" PetscInt_FMT ")\n", i, local_primal_indices[i], pcbddc->primal_indices_local_idxs[i], gidxs[i]));
8555f34684f1SStefano Zampini       }
85569566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
85579566063dSJacob Faibussowitsch       PetscCall(PetscFree(gidxs));
8558f34684f1SStefano Zampini     }
85599566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
85609566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
856128b400f6SJacob Faibussowitsch     PetscCheck(!set_error_reduced, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "BDDC Numbering of coarse dofs failed");
8562f34684f1SStefano Zampini   }
85636080607fSStefano Zampini 
8564f34684f1SStefano Zampini   /* get back data */
8565f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
8566f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
8567674ae819SStefano Zampini   PetscFunctionReturn(0);
8568674ae819SStefano Zampini }
8569674ae819SStefano Zampini 
85709371c9d4SSatish Balay PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis) {
8571e456f2a8SStefano Zampini   IS           localis_t;
8572a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
8573e456f2a8SStefano Zampini   PetscScalar *vals;
8574e456f2a8SStefano Zampini 
8575e456f2a8SStefano Zampini   PetscFunctionBegin;
8576a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
85779566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
85789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
8579e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
85809566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
85819566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
85829566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
85831035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
85849566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
85859566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
85861035eff8SStefano Zampini   }
85879566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
85889566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
85899566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
85909566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
8591a7dc3881SStefano Zampini   /* now compute set in local ordering */
85929566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
85939566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
85949566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
85959566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
8596a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
85979371c9d4SSatish Balay     if (PetscRealPart(vals[i]) > 0.5) { lsize++; }
8598e456f2a8SStefano Zampini   }
85999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
8600a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
86019371c9d4SSatish Balay     if (PetscRealPart(vals[i]) > 0.5) { idxs[lsize++] = i; }
8602e456f2a8SStefano Zampini   }
86039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
86049566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
8605e456f2a8SStefano Zampini   *localis = localis_t;
8606e456f2a8SStefano Zampini   PetscFunctionReturn(0);
8607e456f2a8SStefano Zampini }
8608906d46d4SStefano Zampini 
86099371c9d4SSatish Balay PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr) {
86107c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
86117c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
86127c625d9fSStefano Zampini   PC_IS   *pcisf;
86137c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
86147c625d9fSStefano Zampini   PC       pcf;
86157c625d9fSStefano Zampini 
86167c625d9fSStefano Zampini   PetscFunctionBegin;
86177c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
86187c625d9fSStefano Zampini   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)pcf));
86197c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
86207c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
86217c625d9fSStefano Zampini 
86227c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
862332fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
862432fe681dSStefano Zampini 
86257c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
86267c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
86277c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
86287c625d9fSStefano Zampini   pcisf->n          = pcis->n;
86297c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
86307c625d9fSStefano Zampini 
86317c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
863232fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
86337c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
863432fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
863532fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
863632fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
863732fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
863832fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
863932fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
86407c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
864132fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
864232fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
864332fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
86447c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
864532fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
864632fe681dSStefano Zampini 
864732fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
86487c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
86497c625d9fSStefano Zampini 
86507c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
86517c625d9fSStefano 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));
86527c625d9fSStefano 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));
86537c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
86547c625d9fSStefano Zampini 
865532fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
86567c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
865732fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
865832fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
865932fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
866032fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
86617c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
86627c625d9fSStefano Zampini   PetscFunctionReturn(0);
86637c625d9fSStefano Zampini }
86647c625d9fSStefano Zampini 
86659371c9d4SSatish Balay PetscErrorCode PCBDDCSetUpSubSchurs(PC pc) {
8666a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
8667b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
8668b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
8669a64f4aa4SStefano Zampini   Mat             S_j;
8670b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
8671b96c3477SStefano Zampini   PetscBool       free_used_adj;
8672b96c3477SStefano Zampini 
8673b96c3477SStefano Zampini   PetscFunctionBegin;
86749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
8675b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
8676b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
867708122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
8678b96c3477SStefano Zampini     used_xadj   = NULL;
8679b96c3477SStefano Zampini     used_adjncy = NULL;
8680b96c3477SStefano Zampini   } else {
868108122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
868208122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
868308122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
868408122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
8685b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
8686b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
8687b96c3477SStefano Zampini     } else {
86882fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
8689b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
8690b96c3477SStefano Zampini       PetscInt        nvtxs;
8691b96c3477SStefano Zampini 
86929566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
86932fffb893SStefano Zampini       if (flg_row) {
86949566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
86959566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
86969566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
8697b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
86982fffb893SStefano Zampini       } else {
86992fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
87002fffb893SStefano Zampini         used_xadj                 = NULL;
87012fffb893SStefano Zampini         used_adjncy               = NULL;
87022fffb893SStefano Zampini       }
87039566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
8704b96c3477SStefano Zampini     }
8705b96c3477SStefano Zampini   }
8706d5574798SStefano Zampini 
8707d5574798SStefano Zampini   /* setup sub_schurs data */
87089566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
8709df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
8710df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
87119566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
87129566063dSJacob 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));
8713a64f4aa4SStefano Zampini   } else {
871472b8c272SStefano Zampini     Mat       change        = NULL;
87159d54b7f4SStefano Zampini     Vec       scaling       = NULL;
8716111315fdSstefano_zampini     IS        change_primal = NULL, iP;
8717111315fdSstefano_zampini     PetscInt  benign_n;
8718111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
87197ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
8720111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
8721a3df083aSStefano Zampini 
87225feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
87235feab87aSStefano Zampini       PetscInt n_vertices;
87245feab87aSStefano Zampini 
87259566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
87262034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
87275feab87aSStefano Zampini     }
8728a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
8729a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
8730ca92afb2SStefano Zampini     } else {
8731a3df083aSStefano Zampini       benign_n = 0;
8732ca92afb2SStefano Zampini     }
8733b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
8734b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
8735b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
873672b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
873722db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
87381c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
873922db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
8740b7ab4a40SStefano Zampini     }
87417c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
8742b7ab4a40SStefano Zampini     if (need_change) {
874328b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
874432fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
874588c03ad3SStefano Zampini     }
87469d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
8747111315fdSstefano_zampini 
87489566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
8749111315fdSstefano_zampini     if (iP) {
8750d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
87519566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
8752d0609cedSBarry Smith       PetscOptionsEnd();
8753111315fdSstefano_zampini     }
8754111315fdSstefano_zampini     if (discrete_harmonic) {
8755111315fdSstefano_zampini       Mat A;
87569566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
87579566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
87589566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
87599371c9d4SSatish 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,
87609371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
87619566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
8762111315fdSstefano_zampini     } else {
87639371c9d4SSatish 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,
87649371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
8765111315fdSstefano_zampini     }
87669566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
87679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
8768ca92afb2SStefano Zampini   }
87699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
8770b96c3477SStefano Zampini 
8771b96c3477SStefano Zampini   /* free adjacency */
87721baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
87739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
8774b96c3477SStefano Zampini   PetscFunctionReturn(0);
8775b96c3477SStefano Zampini }
8776b96c3477SStefano Zampini 
87779371c9d4SSatish Balay PetscErrorCode PCBDDCInitSubSchurs(PC pc) {
8778b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
8779b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
8780b96c3477SStefano Zampini   PCBDDCGraph graph;
8781b96c3477SStefano Zampini 
8782b96c3477SStefano Zampini   PetscFunctionBegin;
8783b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
878408122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
87853301b35fSStefano Zampini     IS       verticesIS, verticescomm;
87863301b35fSStefano Zampini     PetscInt vsize, *idxs;
8787b96c3477SStefano Zampini 
87889566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
87899566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
87909566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
87919566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
87929566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
87939566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
87949566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
87959566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
87969566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
87979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
87989566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
8799b96c3477SStefano Zampini   } else {
8800b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
8801b96c3477SStefano Zampini   }
8802e4d548c7SStefano Zampini   /* print some info */
88035c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
8804e4d548c7SStefano Zampini     IS       vertices;
8805e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
88069566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
88079566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
88089566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
88099566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
88109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
881163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
881263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
881363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
88149566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
88159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
88169566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
8817e4d548c7SStefano Zampini   }
8818b96c3477SStefano Zampini 
8819b96c3477SStefano Zampini   /* sub_schurs init */
8820*48a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
882132fe681dSStefano 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));
8822a64f4aa4SStefano Zampini 
8823b96c3477SStefano Zampini   /* free graph struct */
8824*48a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
8825b96c3477SStefano Zampini   PetscFunctionReturn(0);
8826b96c3477SStefano Zampini }
8827fa34dd3eSStefano Zampini 
88289371c9d4SSatish Balay PetscErrorCode PCBDDCCheckOperator(PC pc) {
8829fa34dd3eSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
8830fa34dd3eSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
8831fa34dd3eSStefano Zampini 
8832fa34dd3eSStefano Zampini   PetscFunctionBegin;
8833fa34dd3eSStefano Zampini   if (pcbddc->n_vertices == pcbddc->local_primal_size) {
8834fa34dd3eSStefano Zampini     IS           zerodiag = NULL;
88354f1b2e48SStefano Zampini     Mat          S_j, B0_B = NULL;
8836fa34dd3eSStefano Zampini     Vec          dummy_vec = NULL, vec_check_B, vec_scale_P;
88374f1b2e48SStefano Zampini     PetscScalar *p0_check, *array, *array2;
883875c01103SStefano Zampini     PetscReal    norm;
8839fa34dd3eSStefano Zampini     PetscInt     i;
8840fa34dd3eSStefano Zampini 
8841fa34dd3eSStefano Zampini     /* B0 and B0_B */
8842fa34dd3eSStefano Zampini     if (zerodiag) {
8843fa34dd3eSStefano Zampini       IS dummy;
8844fa34dd3eSStefano Zampini 
88459566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &dummy));
88469566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
88479566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(B0_B, NULL, &dummy_vec));
88489566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&dummy));
8849fa34dd3eSStefano Zampini     }
8850fa34dd3eSStefano Zampini     /* I need a primal vector to scale primal nodes since BDDC sums contibutions */
88519566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_P, &vec_scale_P));
88529566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 1.0));
88539566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
88549566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
88559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, vec_scale_P, INSERT_VALUES, SCATTER_REVERSE));
88569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, vec_scale_P, INSERT_VALUES, SCATTER_REVERSE));
88579566063dSJacob Faibussowitsch     PetscCall(VecReciprocal(vec_scale_P));
8858fa34dd3eSStefano Zampini     /* S_j */
88599566063dSJacob Faibussowitsch     PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
88609566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
8861fa34dd3eSStefano Zampini 
8862fa34dd3eSStefano Zampini     /* mimic vector in \widetilde{W}_\Gamma */
88639566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec1_N, NULL));
8864fa34dd3eSStefano Zampini     /* continuous in primal space */
88659566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcbddc->coarse_vec, NULL));
88669566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
88679566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
88689566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
88699566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcbddc->benign_n, &p0_check));
88704f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) p0_check[i] = array[pcbddc->local_primal_size - pcbddc->benign_n + i];
88719566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, pcbddc->local_primal_size, pcbddc->local_primal_ref_node, array, INSERT_VALUES));
88729566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
88739566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
88749566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
88759566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_N, pcis->vec2_B, INSERT_VALUES, SCATTER_FORWARD));
88769566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_N, pcis->vec2_B, INSERT_VALUES, SCATTER_FORWARD));
88779566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec2_B, &vec_check_B));
88789566063dSJacob Faibussowitsch     PetscCall(VecCopy(pcis->vec2_B, vec_check_B));
8879fa34dd3eSStefano Zampini 
8880fa34dd3eSStefano Zampini     /* assemble rhs for coarse problem */
8881fa34dd3eSStefano Zampini     /* widetilde{S}_\Gamma w_\Gamma + \widetilde{B0}^T_B p0 */
8882fa34dd3eSStefano Zampini     /* local with Schur */
88839566063dSJacob Faibussowitsch     PetscCall(MatMult(S_j, pcis->vec2_B, pcis->vec1_B));
8884fa34dd3eSStefano Zampini     if (zerodiag) {
88859566063dSJacob Faibussowitsch       PetscCall(VecGetArray(dummy_vec, &array));
88864f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) array[i] = p0_check[i];
88879566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(dummy_vec, &array));
88889566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(B0_B, dummy_vec, pcis->vec1_B, pcis->vec1_B));
8889fa34dd3eSStefano Zampini     }
8890fa34dd3eSStefano Zampini     /* sum on primal nodes the local contributions */
88919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
88929566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
88939566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec1_N, &array));
88949566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array2));
8895fa34dd3eSStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) array2[i] = array[pcbddc->local_primal_ref_node[i]];
88969566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array2));
88979566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec1_N, &array));
88989566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->coarse_vec, 0.));
88999566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89009566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89019566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89029566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89039566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
8904fa34dd3eSStefano Zampini     /* scale primal nodes (BDDC sums contibutions) */
89059566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(pcbddc->vec1_P, vec_scale_P, pcbddc->vec1_P));
89069566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, pcbddc->local_primal_size, pcbddc->local_primal_ref_node, array, INSERT_VALUES));
89079566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
89089566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
89099566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
89109566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
89119566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
8912fa34dd3eSStefano Zampini     /* global: \widetilde{B0}_B w_\Gamma */
8913fa34dd3eSStefano Zampini     if (zerodiag) {
89149566063dSJacob Faibussowitsch       PetscCall(MatMult(B0_B, pcis->vec2_B, dummy_vec));
89159566063dSJacob Faibussowitsch       PetscCall(VecGetArray(dummy_vec, &array));
89164f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = array[i];
89179566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(dummy_vec, &array));
8918fa34dd3eSStefano Zampini     }
8919fa34dd3eSStefano Zampini     /* BDDC */
89209566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_D, 0.));
89219566063dSJacob Faibussowitsch     PetscCall(PCBDDCApplyInterfacePreconditioner(pc, PETSC_FALSE));
8922fa34dd3eSStefano Zampini 
89239566063dSJacob Faibussowitsch     PetscCall(VecCopy(pcis->vec1_B, pcis->vec2_B));
89249566063dSJacob Faibussowitsch     PetscCall(VecAXPY(pcis->vec1_B, -1.0, vec_check_B));
89259566063dSJacob Faibussowitsch     PetscCall(VecNorm(pcis->vec1_B, NORM_INFINITY, &norm));
892663a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] BDDC local error is %1.4e\n", PetscGlobalRank, (double)norm));
8927*48a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] BDDC p0[%" PetscInt_FMT "] error is %1.4e\n", PetscGlobalRank, i, (double)PetscAbsScalar(pcbddc->benign_p0[i] - p0_check[i])));
89289566063dSJacob Faibussowitsch     PetscCall(PetscFree(p0_check));
89299566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec_scale_P));
89309566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec_check_B));
89319566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&dummy_vec));
89329566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&S_j));
89339566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
8934fa34dd3eSStefano Zampini   }
8935fa34dd3eSStefano Zampini   PetscFunctionReturn(0);
8936fa34dd3eSStefano Zampini }
89371e0482f5SStefano Zampini 
89381e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
89399371c9d4SSatish Balay PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B) {
89401e0482f5SStefano Zampini   Mat         At;
89411e0482f5SStefano Zampini   IS          rows;
89421e0482f5SStefano Zampini   PetscInt    rst, ren;
89431e0482f5SStefano Zampini   PetscLayout rmap;
89441e0482f5SStefano Zampini 
89451e0482f5SStefano Zampini   PetscFunctionBegin;
89461e0482f5SStefano Zampini   rst = ren = 0;
89471e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
89489566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
89499566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
89509566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
89519566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
89529566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
89531e0482f5SStefano Zampini   }
89549566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
89559566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
89569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
89571e0482f5SStefano Zampini 
89581e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
89591e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
89601e0482f5SStefano Zampini     IS          from, to;
89611e0482f5SStefano Zampini     Vec         gvec;
89621e0482f5SStefano Zampini     PetscInt    lsize;
89631e0482f5SStefano Zampini 
89649566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
89659566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
89669566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
89679566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&((*B)->rmap)));
89689566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
89691e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
89701e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
89719566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
89729566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
89739566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
89749566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
89751e0482f5SStefano Zampini     b->A = a->A;
89761e0482f5SStefano Zampini     b->B = a->B;
89771e0482f5SStefano Zampini 
89781e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
89791e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
89800a545947SLisandro Dalcin     b->rowindices   = NULL;
89810a545947SLisandro Dalcin     b->rowvalues    = NULL;
89821e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
89831e0482f5SStefano Zampini 
89841e0482f5SStefano Zampini     (*B)->rmap         = rmap;
89851e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
89861e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
89871e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
89881e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
89891e0482f5SStefano Zampini 
89901e0482f5SStefano Zampini     if (a->colmap) {
89911e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
89929566063dSJacob Faibussowitsch       PetscCall(PetscTableCreateCopy(a->colmap, &b->colmap));
89931e0482f5SStefano Zampini #else
89949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
89959566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)*B, At->cmap->N * sizeof(PetscInt)));
89969566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
89971e0482f5SStefano Zampini #endif
89980a545947SLisandro Dalcin     } else b->colmap = NULL;
89991e0482f5SStefano Zampini     if (a->garray) {
90001e0482f5SStefano Zampini       PetscInt len;
90011e0482f5SStefano Zampini       len = a->B->cmap->n;
90029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
90039566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)(*B), len * sizeof(PetscInt)));
90049566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
90050a545947SLisandro Dalcin     } else b->garray = NULL;
90061e0482f5SStefano Zampini 
90079566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
90081e0482f5SStefano Zampini     b->lvec = a->lvec;
90099566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)*B, (PetscObject)b->lvec));
90101e0482f5SStefano Zampini 
90111e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
90129566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
90139566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
90149566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
90159566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
90169566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
90179566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)*B, (PetscObject)b->Mvctx));
90189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
90199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
90209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
90211e0482f5SStefano Zampini   }
90229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
90231e0482f5SStefano Zampini   PetscFunctionReturn(0);
90241e0482f5SStefano Zampini }
9025