xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision aaa8cc7d2a5c3913edcbb923e20f154fe9c4aa65)
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) */
15d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B)
16d71ae5a4SJacob Faibussowitsch {
17a13144ffSStefano Zampini   PetscScalar *uwork, *data, *U, ds = 0.;
18a13144ffSStefano Zampini   PetscReal   *sing;
19a13144ffSStefano Zampini   PetscBLASInt bM, bN, lwork, lierr, di = 1;
20a13144ffSStefano Zampini   PetscInt     ulw, i, nr, nc, n;
21abee2b68SSebastian Grimberg #if defined(PETSC_USE_COMPLEX)
22abee2b68SSebastian Grimberg   PetscReal *rwork2;
23abee2b68SSebastian Grimberg #endif
24a13144ffSStefano Zampini 
25a13144ffSStefano Zampini   PetscFunctionBegin;
269566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
273ba16761SJacob Faibussowitsch   if (!nr || !nc) PetscFunctionReturn(PETSC_SUCCESS);
28a13144ffSStefano Zampini 
29a13144ffSStefano Zampini   /* workspace */
30a13144ffSStefano Zampini   if (!work) {
31a13144ffSStefano Zampini     ulw = PetscMax(PetscMax(1, 5 * PetscMin(nr, nc)), 3 * PetscMin(nr, nc) + PetscMax(nr, nc));
329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ulw, &uwork));
33a13144ffSStefano Zampini   } else {
34a13144ffSStefano Zampini     ulw   = lw;
35a13144ffSStefano Zampini     uwork = work;
36a13144ffSStefano Zampini   }
37a13144ffSStefano Zampini   n = PetscMin(nr, nc);
38a13144ffSStefano Zampini   if (!rwork) {
399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &sing));
40a13144ffSStefano Zampini   } else {
41a13144ffSStefano Zampini     sing = rwork;
42a13144ffSStefano Zampini   }
43a13144ffSStefano Zampini 
44a13144ffSStefano Zampini   /* SVD */
459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nr, &U));
469566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nr, &bM));
479566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nc, &bN));
489566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(ulw, &lwork));
499566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(A, &data));
509566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
51abee2b68SSebastian Grimberg #if !defined(PETSC_USE_COMPLEX)
52792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, &lierr));
53abee2b68SSebastian Grimberg #else
549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(5 * n, &rwork2));
55792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, rwork2, &lierr));
569566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork2));
57abee2b68SSebastian Grimberg #endif
589566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPop());
5928b400f6SJacob Faibussowitsch   PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
609566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(A, &data));
619371c9d4SSatish Balay   for (i = 0; i < n; i++)
629371c9d4SSatish Balay     if (sing[i] < PETSC_SMALL) break;
6348a46eb9SPierre Jolivet   if (!rwork) PetscCall(PetscFree(sing));
6448a46eb9SPierre Jolivet   if (!work) PetscCall(PetscFree(uwork));
65a13144ffSStefano Zampini   /* create B */
66f498cd09SStefano Zampini   if (!range) {
679566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, nr - i, NULL, B));
689566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
699566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U + nr * i, (nr - i) * nr));
70f498cd09SStefano Zampini   } else {
719566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, i, NULL, B));
729566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
739566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U, i * nr));
74f498cd09SStefano Zampini   }
759566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(*B, &data));
769566063dSJacob Faibussowitsch   PetscCall(PetscFree(U));
773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
78a13144ffSStefano Zampini }
79a13144ffSStefano Zampini 
801e0482f5SStefano Zampini /* TODO REMOVE */
811e0482f5SStefano Zampini #if defined(PRINT_GDET)
821e0482f5SStefano Zampini static int inc = 0;
831e0482f5SStefano Zampini static int lev = 0;
841e0482f5SStefano Zampini #endif
851e0482f5SStefano Zampini 
86d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNedelecChangeEdge(Mat lG, IS edge, IS extrow, IS extcol, IS corners, Mat *Gins, Mat *GKins, PetscScalar cvals[2], PetscScalar *work, PetscReal *rwork)
87d71ae5a4SJacob Faibussowitsch {
88a13144ffSStefano Zampini   Mat          GE, GEd;
89a13144ffSStefano Zampini   PetscInt     rsize, csize, esize;
90a13144ffSStefano Zampini   PetscScalar *ptr;
91a13144ffSStefano Zampini 
92a13144ffSStefano Zampini   PetscFunctionBegin;
939566063dSJacob Faibussowitsch   PetscCall(ISGetSize(edge, &esize));
943ba16761SJacob Faibussowitsch   if (!esize) PetscFunctionReturn(PETSC_SUCCESS);
959566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extrow, &rsize));
969566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extcol, &csize));
97a13144ffSStefano Zampini 
98a13144ffSStefano Zampini   /* gradients */
99a13144ffSStefano Zampini   ptr = work + 5 * esize;
1009566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, extrow, extcol, MAT_INITIAL_MATRIX, &GE));
1019566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, rsize, csize, ptr, Gins));
1029566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, Gins));
1039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
104a13144ffSStefano Zampini 
105a13144ffSStefano Zampini   /* constants */
106a13144ffSStefano Zampini   ptr += rsize * csize;
1079566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, esize, csize, ptr, &GEd));
1089566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, edge, extcol, MAT_INITIAL_MATRIX, &GE));
1099566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, &GEd));
1109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
1119566063dSJacob Faibussowitsch   PetscCall(MatDenseOrthogonalRangeOrComplement(GEd, PETSC_FALSE, 5 * esize, work, rwork, GKins));
1129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GEd));
1131e0482f5SStefano Zampini 
1141e0482f5SStefano Zampini   if (corners) {
1151e0482f5SStefano Zampini     Mat                GEc;
1161683a169SBarry Smith     const PetscScalar *vals;
1171683a169SBarry Smith     PetscScalar        v;
1181e0482f5SStefano Zampini 
1199566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(lG, edge, corners, MAT_INITIAL_MATRIX, &GEc));
1209566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(GEc, *GKins, MAT_INITIAL_MATRIX, 1.0, &GEd));
1219566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(GEd, &vals));
122637e8532SStefano Zampini     /* v    = PetscAbsScalar(vals[0]) */;
123637e8532SStefano Zampini     v        = 1.;
1241e0482f5SStefano Zampini     cvals[0] = vals[0] / v;
1251e0482f5SStefano Zampini     cvals[1] = vals[1] / v;
1269566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(GEd, &vals));
1279566063dSJacob Faibussowitsch     PetscCall(MatScale(*GKins, 1. / v));
1281e0482f5SStefano Zampini #if defined(PRINT_GDET)
1291e0482f5SStefano Zampini     {
1301e0482f5SStefano Zampini       PetscViewer viewer;
1311e0482f5SStefano Zampini       char        filename[256];
132a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "Gdet_l%d_r%d_cc%d.m", lev, PetscGlobalRank, inc++));
1339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &viewer));
1349566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
1359566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEc, "GEc"));
1369566063dSJacob Faibussowitsch       PetscCall(MatView(GEc, viewer));
1379566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)(*GKins), "GK"));
1389566063dSJacob Faibussowitsch       PetscCall(MatView(*GKins, viewer));
1399566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEd, "Gproj"));
1409566063dSJacob Faibussowitsch       PetscCall(MatView(GEd, viewer));
1419566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
1421e0482f5SStefano Zampini     }
1431e0482f5SStefano Zampini #endif
1449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEd));
1459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEc));
1461e0482f5SStefano Zampini   }
1471e0482f5SStefano Zampini 
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149a13144ffSStefano Zampini }
150a13144ffSStefano Zampini 
151d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNedelecSupport(PC pc)
152d71ae5a4SJacob Faibussowitsch {
153a13144ffSStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
154a13144ffSStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
1550569b399SStefano Zampini   Mat                    G, T, conn, lG, lGt, lGis, lGall, lGe, lGinit;
156eee23b56SStefano Zampini   Vec                    tvec;
157a13144ffSStefano Zampini   PetscSF                sfv;
1581e0482f5SStefano Zampini   ISLocalToGlobalMapping el2g, vl2g, fl2g, al2g;
159a13144ffSStefano Zampini   MPI_Comm               comm;
160c2151214SStefano Zampini   IS                     lned, primals, allprimals, nedfieldlocal;
161c2151214SStefano Zampini   IS                    *eedges, *extrows, *extcols, *alleedges;
1627d871cd7SStefano Zampini   PetscBT                btv, bte, btvc, btb, btbd, btvcand, btvi, btee, bter;
163a13144ffSStefano Zampini   PetscScalar           *vals, *work;
164a13144ffSStefano Zampini   PetscReal             *rwork;
165a13144ffSStefano Zampini   const PetscInt        *idxs, *ii, *jj, *iit, *jjt;
1661e0482f5SStefano Zampini   PetscInt               ne, nv, Lv, order, n, field;
167a13144ffSStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
168eee23b56SStefano Zampini   PetscInt               i, j, extmem, cum, maxsize, nee;
169b03ebc13SStefano Zampini   PetscInt              *extrow, *extrowcum, *marks, *vmarks, *gidxs;
170a13144ffSStefano Zampini   PetscInt              *sfvleaves, *sfvroots;
171b03ebc13SStefano Zampini   PetscInt              *corners, *cedges;
172637e8532SStefano Zampini   PetscInt              *ecount, **eneighs, *vcount, **vneighs;
173b03ebc13SStefano Zampini   PetscInt              *emarks;
174213b8bfaSStefano Zampini   PetscBool              print, eerr, done, lrc[2], conforming, global, singular, setprimal;
175a13144ffSStefano Zampini 
176a13144ffSStefano Zampini   PetscFunctionBegin;
177213b8bfaSStefano Zampini   /* If the discrete gradient is defined for a subset of dofs and global is true,
178213b8bfaSStefano Zampini      it assumes G is given in global ordering for all the dofs.
179213b8bfaSStefano Zampini      Otherwise, the ordering is global for the Nedelec field */
180213b8bfaSStefano Zampini   order      = pcbddc->nedorder;
181213b8bfaSStefano Zampini   conforming = pcbddc->conforming;
182213b8bfaSStefano Zampini   field      = pcbddc->nedfield;
183213b8bfaSStefano Zampini   global     = pcbddc->nedglobal;
184213b8bfaSStefano Zampini   setprimal  = PETSC_FALSE;
185a13144ffSStefano Zampini   print      = PETSC_FALSE;
186213b8bfaSStefano Zampini   singular   = PETSC_FALSE;
187a13144ffSStefano Zampini 
188213b8bfaSStefano Zampini   /* Command line customization */
189d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC Nedelec options", "PC");
1909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_field_primal", "All edge dofs set as primals: Toselli's algorithm C", NULL, setprimal, &setprimal, NULL));
1919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_singular", "Infer nullspace from discrete gradient", NULL, singular, &singular, NULL));
1929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bddc_nedelec_order", "Test variable order code (to be removed)", NULL, order, &order, NULL));
193213b8bfaSStefano Zampini   /* print debug info TODO: to be removed */
1949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_nedelec_print", "Print debug info", NULL, print, &print, NULL));
195d0609cedSBarry Smith   PetscOptionsEnd();
196213b8bfaSStefano Zampini 
197213b8bfaSStefano Zampini   /* Return if there are no edges in the decomposition and the problem is not singular */
1989566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &al2g, NULL));
1999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(al2g, &n));
2009566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
201213b8bfaSStefano Zampini   if (!singular) {
2029566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
203a13144ffSStefano Zampini     lrc[0] = PETSC_FALSE;
204c2151214SStefano Zampini     for (i = 0; i < n; i++) {
205a13144ffSStefano Zampini       if (PetscRealPart(vals[i]) > 2.) {
206a13144ffSStefano Zampini         lrc[0] = PETSC_TRUE;
207a13144ffSStefano Zampini         break;
208a13144ffSStefano Zampini       }
209a13144ffSStefano Zampini     }
2109566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2111c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lrc[0], &lrc[1], 1, MPIU_BOOL, MPI_LOR, comm));
2123ba16761SJacob Faibussowitsch     if (!lrc[1]) PetscFunctionReturn(PETSC_SUCCESS);
213213b8bfaSStefano Zampini   }
214a13144ffSStefano Zampini 
215213b8bfaSStefano Zampini   /* Get Nedelec field */
21663a3b9bcSJacob 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);
217213b8bfaSStefano Zampini   if (pcbddc->n_ISForDofsLocal && field >= 0) {
2189566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofsLocal[field]));
219c2151214SStefano Zampini     nedfieldlocal = pcbddc->ISForDofsLocal[field];
2209566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nedfieldlocal, &ne));
221213b8bfaSStefano Zampini   } else if (!pcbddc->n_ISForDofsLocal && field != PETSC_DECIDE) {
222213b8bfaSStefano Zampini     ne            = n;
223213b8bfaSStefano Zampini     nedfieldlocal = NULL;
224213b8bfaSStefano Zampini     global        = PETSC_TRUE;
225213b8bfaSStefano Zampini   } else if (field == PETSC_DECIDE) {
226213b8bfaSStefano Zampini     PetscInt rst, ren, *idx;
227213b8bfaSStefano Zampini 
2289566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_leafdata, n));
2299566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
2309566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(pcbddc->discretegradient, &rst, &ren));
231213b8bfaSStefano Zampini     for (i = rst; i < ren; i++) {
232213b8bfaSStefano Zampini       PetscInt nc;
233213b8bfaSStefano Zampini 
2349566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
235213b8bfaSStefano Zampini       if (nc > 1) matis->sf_rootdata[i - rst] = 1;
2369566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->discretegradient, i, &nc, NULL, NULL));
237213b8bfaSStefano Zampini     }
2389566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2399566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &idx));
2419371c9d4SSatish Balay     for (i = 0, ne = 0; i < n; i++)
2429371c9d4SSatish Balay       if (matis->sf_leafdata[i]) idx[ne++] = i;
2439566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, ne, idx, PETSC_OWN_POINTER, &nedfieldlocal));
244213b8bfaSStefano Zampini   } else {
245213b8bfaSStefano Zampini     SETERRQ(comm, PETSC_ERR_USER, "When multiple fields are present, the Nedelec field has to be specified");
246213b8bfaSStefano Zampini   }
247213b8bfaSStefano Zampini 
248213b8bfaSStefano Zampini   /* Sanity checks */
2497827d75bSBarry Smith   PetscCheck(order || conforming, comm, PETSC_ERR_SUP, "Variable order and non-conforming spaces are not supported at the same time");
25028b400f6SJacob Faibussowitsch   PetscCheck(!pcbddc->user_ChangeOfBasisMatrix, comm, PETSC_ERR_SUP, "Cannot generate Nedelec support with user defined change of basis");
25163a3b9bcSJacob 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);
252213b8bfaSStefano Zampini 
253213b8bfaSStefano Zampini   /* Just set primal dofs and return */
2541e0482f5SStefano Zampini   if (setprimal) {
255eee23b56SStefano Zampini     IS        enedfieldlocal;
256eee23b56SStefano Zampini     PetscInt *eidxs;
257eee23b56SStefano Zampini 
2589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &eidxs));
2599566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(matis->counter, (const PetscScalar **)&vals));
260213b8bfaSStefano Zampini     if (nedfieldlocal) {
2619566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
262eee23b56SStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
263ad540459SPierre Jolivet         if (PetscRealPart(vals[idxs[i]]) > 2.) eidxs[cum++] = idxs[i];
264eee23b56SStefano Zampini       }
2659566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
266213b8bfaSStefano Zampini     } else {
267213b8bfaSStefano Zampini       for (i = 0, cum = 0; i < ne; i++) {
268ad540459SPierre Jolivet         if (PetscRealPart(vals[i]) > 2.) eidxs[cum++] = i;
269213b8bfaSStefano Zampini       }
270213b8bfaSStefano Zampini     }
2719566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(matis->counter, (const PetscScalar **)&vals));
2729566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, eidxs, PETSC_COPY_VALUES, &enedfieldlocal));
2739566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, enedfieldlocal));
2749566063dSJacob Faibussowitsch     PetscCall(PetscFree(eidxs));
2759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nedfieldlocal));
2769566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&enedfieldlocal));
2773ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2781e0482f5SStefano Zampini   }
279a13144ffSStefano Zampini 
280213b8bfaSStefano Zampini   /* Compute some l2g maps */
281213b8bfaSStefano Zampini   if (nedfieldlocal) {
282c2151214SStefano Zampini     IS is;
283c2151214SStefano Zampini 
284c2151214SStefano Zampini     /* need to map from the local Nedelec field to local numbering */
2859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(nedfieldlocal, &fl2g));
2861e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering for the whole dofs*/
2879566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(al2g, nedfieldlocal, &is));
2889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &al2g));
2891e0482f5SStefano Zampini     /* need to map from the local Nedelec field to global numbering (for Nedelec only) */
2901e0482f5SStefano Zampini     if (global) {
2919566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)al2g));
2921e0482f5SStefano Zampini       el2g = al2g;
2931e0482f5SStefano Zampini     } else {
2941e0482f5SStefano Zampini       IS gis;
2951e0482f5SStefano Zampini 
2969566063dSJacob Faibussowitsch       PetscCall(ISRenumber(is, NULL, NULL, &gis));
2979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(gis, &el2g));
2989566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&gis));
2991e0482f5SStefano Zampini     }
3009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
301c2151214SStefano Zampini   } else {
3021e0482f5SStefano Zampini     /* restore default */
3031e0482f5SStefano Zampini     pcbddc->nedfield = -1;
3041e0482f5SStefano Zampini     /* one ref for the destruction of al2g, one for el2g */
3059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3069566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3071e0482f5SStefano Zampini     el2g = al2g;
308c2151214SStefano Zampini     fl2g = NULL;
309c2151214SStefano Zampini   }
310a13144ffSStefano Zampini 
311213b8bfaSStefano Zampini   /* Start communication to drop connections for interior edges (for cc analysis only) */
3129566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
3139566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
314c2151214SStefano Zampini   if (nedfieldlocal) {
3159566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
316c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[idxs[i]] = 1;
3179566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
318c2151214SStefano Zampini   } else {
319c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[i] = 1;
320c2151214SStefano Zampini   }
3219566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
3229566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
323213b8bfaSStefano Zampini 
324213b8bfaSStefano Zampini   if (!singular) { /* drop connections with interior edges to avoid unneeded communications and memory movements */
3259566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(pcbddc->discretegradient, MAT_COPY_VALUES, &G));
3269566063dSJacob Faibussowitsch     PetscCall(MatSetOption(G, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3271e0482f5SStefano Zampini     if (global) {
3281e0482f5SStefano Zampini       PetscInt rst;
3291e0482f5SStefano Zampini 
3309566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(G, &rst, NULL));
331c2151214SStefano Zampini       for (i = 0, cum = 0; i < pc->pmat->rmap->n; i++) {
332ad540459SPierre Jolivet         if (matis->sf_rootdata[i] < 2) matis->sf_rootdata[cum++] = i + rst;
333c2151214SStefano Zampini       }
3349566063dSJacob Faibussowitsch       PetscCall(MatSetOption(G, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE));
3359566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, matis->sf_rootdata, 0., NULL, NULL));
3361e0482f5SStefano Zampini     } else {
3371e0482f5SStefano Zampini       PetscInt *tbz;
3381e0482f5SStefano Zampini 
3399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ne, &tbz));
3409566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3419566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3429566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
3431e0482f5SStefano Zampini       for (i = 0, cum = 0; i < ne; i++)
3449371c9d4SSatish Balay         if (matis->sf_leafdata[idxs[i]] == 1) tbz[cum++] = i;
3459566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
3469566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(el2g, cum, tbz, tbz));
3479566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, tbz, 0., NULL, NULL));
3489566063dSJacob Faibussowitsch       PetscCall(PetscFree(tbz));
3491e0482f5SStefano Zampini     }
350213b8bfaSStefano Zampini   } else { /* we need the entire G to infer the nullspace */
3519566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->discretegradient));
352213b8bfaSStefano Zampini     G = pcbddc->discretegradient;
353213b8bfaSStefano Zampini   }
354a13144ffSStefano Zampini 
355a13144ffSStefano Zampini   /* Extract subdomain relevant rows of G */
3569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(el2g, &idxs));
3579566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, ne, idxs, PETSC_USE_POINTER, &lned));
3589566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(G, lned, NULL, MAT_INITIAL_MATRIX, &lGall));
3599566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(el2g, &idxs));
3609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&lned));
3619566063dSJacob Faibussowitsch   PetscCall(MatConvert(lGall, MATIS, MAT_INITIAL_MATRIX, &lGis));
3629566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGall));
3639566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(lGis, &lG));
364a13144ffSStefano Zampini 
365213b8bfaSStefano Zampini   /* SF for nodal dofs communications */
3669566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(G, NULL, &Lv));
3679566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(lGis, NULL, &vl2g));
3689566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)vl2g));
3699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(vl2g, &nv));
3709566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sfv));
3719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(vl2g, &idxs));
3729566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sfv, lGis->cmap, nv, NULL, PETSC_OWN_POINTER, idxs));
3739566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(vl2g, &idxs));
374213b8bfaSStefano Zampini   i = singular ? 2 : 1;
3759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i * nv, &sfvleaves, i * Lv, &sfvroots));
376a13144ffSStefano Zampini 
3771e0482f5SStefano Zampini   /* Destroy temporary G created in MATIS format and modified G */
3789566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)lG));
3799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGis));
3809566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&G));
381a13144ffSStefano Zampini 
382213b8bfaSStefano Zampini   if (print) {
3839566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "initial_lG"));
3849566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
385213b8bfaSStefano Zampini   }
386213b8bfaSStefano Zampini 
387213b8bfaSStefano Zampini   /* Save lG for values insertion in change of basis */
3889566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGinit));
3890569b399SStefano Zampini 
390a13144ffSStefano Zampini   /* Analyze the edge-nodes connections (duplicate lG) */
3919566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGe));
3929566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGe, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3939566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btv));
3949566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &bte));
3959566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btb));
3969566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btbd));
3979566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvcand));
398a13144ffSStefano Zampini   /* need to import the boundary specification to ensure the
399a13144ffSStefano Zampini      proper detection of coarse edges' endpoints */
400a13144ffSStefano Zampini   if (pcbddc->DirichletBoundariesLocal) {
401c2151214SStefano Zampini     IS is;
402c2151214SStefano Zampini 
403c2151214SStefano Zampini     if (fl2g) {
4049566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->DirichletBoundariesLocal, &is));
405c2151214SStefano Zampini     } else {
406c2151214SStefano Zampini       is = pcbddc->DirichletBoundariesLocal;
407c2151214SStefano Zampini     }
4089566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
410a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
411a13144ffSStefano Zampini       if (idxs[i] >= 0) {
4129566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btb, idxs[i]));
4139566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btbd, idxs[i]));
414a13144ffSStefano Zampini       }
415a13144ffSStefano Zampini     }
4169566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
41748a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
418a13144ffSStefano Zampini   }
419a13144ffSStefano Zampini   if (pcbddc->NeumannBoundariesLocal) {
420c2151214SStefano Zampini     IS is;
421c2151214SStefano Zampini 
422c2151214SStefano Zampini     if (fl2g) {
4239566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->NeumannBoundariesLocal, &is));
424c2151214SStefano Zampini     } else {
425c2151214SStefano Zampini       is = pcbddc->NeumannBoundariesLocal;
426c2151214SStefano Zampini     }
4279566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4289566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
429a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
43048a46eb9SPierre Jolivet       if (idxs[i] >= 0) PetscCall(PetscBTSet(btb, idxs[i]));
431a13144ffSStefano Zampini     }
4329566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
43348a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
434c2151214SStefano Zampini   }
435c2151214SStefano Zampini 
436213b8bfaSStefano Zampini   /* Count neighs per dof */
4379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, &ecount, &eneighs));
4389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, &vcount, &vneighs));
439637e8532SStefano Zampini 
4407d871cd7SStefano Zampini   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
4417d871cd7SStefano Zampini      for proper detection of coarse edges' endpoints */
4429566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btee));
44362b0c6f7SStefano Zampini   for (i = 0; i < ne; i++) {
44448a46eb9SPierre Jolivet     if ((ecount[i] > 2 && !PetscBTLookup(btbd, i)) || (ecount[i] == 2 && PetscBTLookup(btb, i))) PetscCall(PetscBTSet(btee, i));
44562b0c6f7SStefano Zampini   }
4469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ne, &marks));
44762b0c6f7SStefano Zampini   if (!conforming) {
4489566063dSJacob Faibussowitsch     PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
4499566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
45062b0c6f7SStefano Zampini   }
4519566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
4529566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGe, &vals));
45362b0c6f7SStefano Zampini   cum = 0;
454a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
455dec27d64SStefano Zampini     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
45662b0c6f7SStefano Zampini     if (!PetscBTLookup(btee, i)) {
457a13144ffSStefano Zampini       marks[cum++] = i;
458dec27d64SStefano Zampini       continue;
459dec27d64SStefano Zampini     }
460dec27d64SStefano Zampini     /* set badly connected edge dofs as primal */
46162b0c6f7SStefano Zampini     if (!conforming) {
46262b0c6f7SStefano Zampini       if (ii[i + 1] - ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
463a13144ffSStefano Zampini         marks[cum++] = i;
4649566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(bte, i));
46548a46eb9SPierre Jolivet         for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
46662b0c6f7SStefano Zampini       } else {
467*aaa8cc7dSPierre Jolivet         /* every edge dofs should be connected through a certain number of nodal dofs
46862b0c6f7SStefano Zampini            to other edge dofs belonging to coarse edges
46962b0c6f7SStefano Zampini            - at most 2 endpoints
47062b0c6f7SStefano Zampini            - order-1 interior nodal dofs
47162b0c6f7SStefano Zampini            - no undefined nodal dofs (nconn < order)
47262b0c6f7SStefano Zampini         */
47362b0c6f7SStefano Zampini         PetscInt ends = 0, ints = 0, undef = 0;
47462b0c6f7SStefano Zampini         for (j = ii[i]; j < ii[i + 1]; j++) {
47562b0c6f7SStefano Zampini           PetscInt v     = jj[j], k;
47662b0c6f7SStefano Zampini           PetscInt nconn = iit[v + 1] - iit[v];
4779371c9d4SSatish Balay           for (k = iit[v]; k < iit[v + 1]; k++)
4789371c9d4SSatish Balay             if (!PetscBTLookup(btee, jjt[k])) nconn--;
47962b0c6f7SStefano Zampini           if (nconn > order) ends++;
48062b0c6f7SStefano Zampini           else if (nconn == order) ints++;
48162b0c6f7SStefano Zampini           else undef++;
48262b0c6f7SStefano Zampini         }
48362b0c6f7SStefano Zampini         if (undef || ends > 2 || ints != order - 1) {
48462b0c6f7SStefano Zampini           marks[cum++] = i;
4859566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(bte, i));
48648a46eb9SPierre Jolivet           for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
48762b0c6f7SStefano Zampini         }
48862b0c6f7SStefano Zampini       }
489a13144ffSStefano Zampini     }
490dec27d64SStefano Zampini     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
491dec27d64SStefano Zampini     if (!order && ii[i + 1] != ii[i]) {
492dec27d64SStefano Zampini       PetscScalar val = 1. / (ii[i + 1] - ii[i] - 1);
493dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vals[j] = val;
494a13144ffSStefano Zampini     }
495dec27d64SStefano Zampini   }
4969566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btee));
4979566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGe, &vals));
4989566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
49962b0c6f7SStefano Zampini   if (!conforming) {
5009566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
5019566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lGt));
50262b0c6f7SStefano Zampini   }
5039566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGe, cum, marks, 0., NULL, NULL));
504637e8532SStefano Zampini 
505b03ebc13SStefano Zampini   /* identify splitpoints and corner candidates */
5069566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
507a13144ffSStefano Zampini   if (print) {
5089566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGe, "edgerestr_lG"));
5099566063dSJacob Faibussowitsch     PetscCall(MatView(lGe, NULL));
5109566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "edgerestr_lGt"));
5119566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
512a13144ffSStefano Zampini   }
5139566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5149566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGt, &vals));
515a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
516637e8532SStefano Zampini     PetscInt  ord = order, test = ii[i + 1] - ii[i], vc = vcount[i];
5177d871cd7SStefano Zampini     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
518b03ebc13SStefano Zampini     if (!order) { /* variable order */
519dec27d64SStefano Zampini       PetscReal vorder = 0.;
520dec27d64SStefano Zampini 
521dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vorder += PetscRealPart(vals[j]);
522dec27d64SStefano Zampini       test = PetscFloorReal(vorder + 10. * PETSC_SQRT_MACHINE_EPSILON);
52363a3b9bcSJacob Faibussowitsch       PetscCheck(vorder - test <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected value for vorder: %g (%" PetscInt_FMT ")", (double)vorder, test);
524dec27d64SStefano Zampini       ord = 1;
525dec27d64SStefano Zampini     }
5266bdcaf15SBarry 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);
527637e8532SStefano Zampini     for (j = ii[i]; j < ii[i + 1] && sneighs; j++) {
5287d871cd7SStefano Zampini       if (PetscBTLookup(btbd, jj[j])) {
5297d871cd7SStefano Zampini         bdir = PETSC_TRUE;
5307d871cd7SStefano Zampini         break;
5317d871cd7SStefano Zampini       }
532637e8532SStefano Zampini       if (vc != ecount[jj[j]]) {
533637e8532SStefano Zampini         sneighs = PETSC_FALSE;
534637e8532SStefano Zampini       } else {
535637e8532SStefano Zampini         PetscInt k, *vn = vneighs[i], *en = eneighs[jj[j]];
536637e8532SStefano Zampini         for (k = 0; k < vc; k++) {
537637e8532SStefano Zampini           if (vn[k] != en[k]) {
538637e8532SStefano Zampini             sneighs = PETSC_FALSE;
539637e8532SStefano Zampini             break;
540637e8532SStefano Zampini           }
541637e8532SStefano Zampini         }
542637e8532SStefano Zampini       }
543637e8532SStefano Zampini     }
5447d871cd7SStefano Zampini     if (!sneighs || test >= 3 * ord || bdir) { /* splitpoints */
5453ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "SPLITPOINT %" PetscInt_FMT " (%s %s %s)\n", i, PetscBools[!sneighs], PetscBools[test >= 3 * ord], PetscBools[bdir]));
5469566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
547dec27d64SStefano Zampini     } else if (test == ord) {
548b03ebc13SStefano Zampini       if (order == 1 || (!order && ii[i + 1] - ii[i] == 1)) {
5493ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINT %" PetscInt_FMT "\n", i));
5509566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btv, i));
551a13144ffSStefano Zampini       } else {
5523ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "CORNER CANDIDATE %" PetscInt_FMT "\n", i));
5539566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btvcand, i));
554a13144ffSStefano Zampini       }
555a13144ffSStefano Zampini     }
556a13144ffSStefano Zampini   }
5579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(el2g, NULL, &ecount, &eneighs));
5589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(vl2g, NULL, &vcount, &vneighs));
5599566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btbd));
560b03ebc13SStefano Zampini 
561b03ebc13SStefano Zampini   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
562b03ebc13SStefano Zampini   if (order != 1) {
5633ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "INSPECTING CANDIDATES\n"));
5649566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
565b03ebc13SStefano Zampini     for (i = 0; i < nv; i++) {
566b03ebc13SStefano Zampini       if (PetscBTLookup(btvcand, i)) {
567b03ebc13SStefano Zampini         PetscBool found = PETSC_FALSE;
568b03ebc13SStefano Zampini         for (j = ii[i]; j < ii[i + 1] && !found; j++) {
569b03ebc13SStefano Zampini           PetscInt k, e = jj[j];
570b03ebc13SStefano Zampini           if (PetscBTLookup(bte, e)) continue;
571b03ebc13SStefano Zampini           for (k = iit[e]; k < iit[e + 1]; k++) {
572b03ebc13SStefano Zampini             PetscInt v = jjt[k];
573b03ebc13SStefano Zampini             if (v != i && PetscBTLookup(btvcand, v)) {
574b03ebc13SStefano Zampini               found = PETSC_TRUE;
575b03ebc13SStefano Zampini               break;
576b03ebc13SStefano Zampini             }
577b03ebc13SStefano Zampini           }
578b03ebc13SStefano Zampini         }
579b03ebc13SStefano Zampini         if (!found) {
5803ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " CLEARED\n", i));
5819566063dSJacob Faibussowitsch           PetscCall(PetscBTClear(btvcand, i));
582b03ebc13SStefano Zampini         } else {
5833ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " ACCEPTED\n", i));
584b03ebc13SStefano Zampini         }
585b03ebc13SStefano Zampini       }
586b03ebc13SStefano Zampini     }
5879566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
588b03ebc13SStefano Zampini   }
5899566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGt, &vals));
5909566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGe));
592a13144ffSStefano Zampini 
593a13144ffSStefano Zampini   /* Get the local G^T explicitly */
5949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
5959566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
5969566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGt, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
597a13144ffSStefano Zampini 
5984e64d54eSstefano_zampini   /* Mark interior nodal dofs */
5999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
6009566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvi));
601a13144ffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
60248a46eb9SPierre Jolivet     for (j = 0; j < n_shared[i]; j++) PetscCall(PetscBTSet(btvi, shared[i][j]));
603a13144ffSStefano Zampini   }
6049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(vl2g, &n_neigh, &neigh, &n_shared, &shared));
605a13144ffSStefano Zampini 
606a13144ffSStefano Zampini   /* communicate corners and splitpoints */
6079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nv, &vmarks));
6089566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvleaves, nv));
6099566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvroots, Lv));
6109371c9d4SSatish Balay   for (i = 0; i < nv; i++)
6119371c9d4SSatish Balay     if (PetscUnlikely(PetscBTLookup(btv, i))) sfvleaves[i] = 1;
612a13144ffSStefano Zampini 
613a13144ffSStefano Zampini   if (print) {
614a13144ffSStefano Zampini     IS tbz;
615a13144ffSStefano Zampini 
616a13144ffSStefano Zampini     cum = 0;
617a13144ffSStefano Zampini     for (i = 0; i < nv; i++)
6189371c9d4SSatish Balay       if (sfvleaves[i]) vmarks[cum++] = i;
619a13144ffSStefano Zampini 
6209566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6219566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_local"));
6229566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
624a13144ffSStefano Zampini   }
625a13144ffSStefano Zampini 
6269566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6279566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
6289566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
6299566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
630a13144ffSStefano Zampini 
6314e64d54eSstefano_zampini   /* Zero rows of lGt corresponding to identified corners
6324e64d54eSstefano_zampini      and interior nodal dofs */
633a13144ffSStefano Zampini   cum = 0;
634a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
635a13144ffSStefano Zampini     if (sfvleaves[i]) {
636a13144ffSStefano Zampini       vmarks[cum++] = i;
6379566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
638a13144ffSStefano Zampini     }
6394e64d54eSstefano_zampini     if (!PetscBTLookup(btvi, i)) vmarks[cum++] = i;
640a13144ffSStefano Zampini   }
6419566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvi));
642a13144ffSStefano Zampini   if (print) {
643a13144ffSStefano Zampini     IS tbz;
644a13144ffSStefano Zampini 
6459566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
6469566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_with_interior"));
6479566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
6489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
649a13144ffSStefano Zampini   }
6509566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGt, cum, vmarks, 0., NULL, NULL));
6519566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmarks));
6529566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfv));
6539566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sfvleaves, sfvroots));
654a13144ffSStefano Zampini 
655a13144ffSStefano Zampini   /* Recompute G */
6569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
6579566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGt, MAT_INITIAL_MATRIX, &lG));
658a13144ffSStefano Zampini   if (print) {
6599566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "used_lG"));
6609566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
6619566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "used_lGt"));
6629566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
663a13144ffSStefano Zampini   }
664a13144ffSStefano Zampini 
665a13144ffSStefano Zampini   /* Get primal dofs (if any) */
666a13144ffSStefano Zampini   cum = 0;
667a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
668a13144ffSStefano Zampini     if (PetscUnlikely(PetscBTLookup(bte, i))) marks[cum++] = i;
669a13144ffSStefano Zampini   }
6701baa6e33SBarry Smith   if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, marks, marks));
6719566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, cum, marks, PETSC_COPY_VALUES, &primals));
672a13144ffSStefano Zampini   if (print) {
6739566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "prescribed_primal_dofs"));
6749566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
675a13144ffSStefano Zampini   }
6769566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bte));
677c2151214SStefano Zampini   /* TODO: what if the user passed in some of them ?  */
6789566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
6799566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&primals));
680a13144ffSStefano Zampini 
681a13144ffSStefano Zampini   /* Compute edge connectivity */
6829566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lG, "econn_"));
6834222ddf1SHong Zhang 
6844222ddf1SHong Zhang   /* Symbolic conn = lG*lGt */
6859566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(lG, lGt, NULL, &conn));
6869566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(conn, MATPRODUCT_AB));
6879566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(conn, "default"));
6889566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(conn, PETSC_DEFAULT));
6899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)conn, "econn_"));
6909566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(conn));
6919566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(conn));
6924222ddf1SHong Zhang 
6939566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
694c2151214SStefano Zampini   if (fl2g) {
695c2151214SStefano Zampini     PetscBT   btf;
696c2151214SStefano Zampini     PetscInt *iia, *jja, *iiu, *jju;
697c2151214SStefano Zampini     PetscBool rest = PETSC_FALSE, free = PETSC_FALSE;
698c2151214SStefano Zampini 
699c2151214SStefano Zampini     /* create CSR for all local dofs */
7009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &iia));
701c2151214SStefano Zampini     if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
70263a3b9bcSJacob 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);
703c2151214SStefano Zampini       iiu = pcbddc->mat_graph->xadj;
704c2151214SStefano Zampini       jju = pcbddc->mat_graph->adjncy;
705c2151214SStefano Zampini     } else if (pcbddc->use_local_adj) {
706c2151214SStefano Zampini       rest = PETSC_TRUE;
7079566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
708c2151214SStefano Zampini     } else {
709c2151214SStefano Zampini       free = PETSC_TRUE;
7109566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n + 1, &iiu, n, &jju));
711c2151214SStefano Zampini       iiu[0] = 0;
712c2151214SStefano Zampini       for (i = 0; i < n; i++) {
713c2151214SStefano Zampini         iiu[i + 1] = i + 1;
714c2151214SStefano Zampini         jju[i]     = -1;
715d904f53bSStefano Zampini       }
716c2151214SStefano Zampini     }
717c2151214SStefano Zampini 
718c2151214SStefano Zampini     /* import sizes of CSR */
719c2151214SStefano Zampini     iia[0] = 0;
720c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] = iiu[i + 1] - iiu[i];
721c2151214SStefano Zampini 
722c2151214SStefano Zampini     /* overwrite entries corresponding to the Nedelec field */
7239566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(n, &btf));
7249566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
725c2151214SStefano Zampini     for (i = 0; i < ne; i++) {
7269566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btf, idxs[i]));
727c2151214SStefano Zampini       iia[idxs[i] + 1] = ii[i + 1] - ii[i];
728c2151214SStefano Zampini     }
729c2151214SStefano Zampini 
730c2151214SStefano Zampini     /* iia in CSR */
731c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] += iia[i];
732c2151214SStefano Zampini 
733c2151214SStefano Zampini     /* jja in CSR */
7349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(iia[n], &jja));
735c2151214SStefano Zampini     for (i = 0; i < n; i++)
736c2151214SStefano Zampini       if (!PetscBTLookup(btf, i))
7379371c9d4SSatish Balay         for (j = 0; j < iiu[i + 1] - iiu[i]; j++) jja[iia[i] + j] = jju[iiu[i] + j];
738c2151214SStefano Zampini 
739c2151214SStefano Zampini     /* map edge dofs connectivity */
7401e0482f5SStefano Zampini     if (jj) {
7419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, ii[ne], jj, (PetscInt *)jj));
742c2151214SStefano Zampini       for (i = 0; i < ne; i++) {
743c2151214SStefano Zampini         PetscInt e = idxs[i];
744c2151214SStefano Zampini         for (j = 0; j < ii[i + 1] - ii[i]; j++) jja[iia[e] + j] = jj[ii[i] + j];
745c2151214SStefano Zampini       }
7461e0482f5SStefano Zampini     }
7479566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
7489566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, iia, jja, PETSC_OWN_POINTER));
74948a46eb9SPierre Jolivet     if (rest) PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
7501baa6e33SBarry Smith     if (free) PetscCall(PetscFree2(iiu, jju));
7519566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&btf));
752c2151214SStefano Zampini   } else {
7539566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, ii, jj, PETSC_USE_POINTER));
754c2151214SStefano Zampini   }
755c2151214SStefano Zampini 
756a13144ffSStefano Zampini   /* Analyze interface for edge dofs */
7579566063dSJacob Faibussowitsch   PetscCall(PCBDDCAnalyzeInterface(pc));
758213b8bfaSStefano Zampini   pcbddc->mat_graph->twodim = PETSC_FALSE;
759a13144ffSStefano Zampini 
760a13144ffSStefano Zampini   /* Get coarse edges in the edge space */
7619566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
7629566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
763a13144ffSStefano Zampini 
764c2151214SStefano Zampini   if (fl2g) {
7659566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
7669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee, &eedges));
76748a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
768c2151214SStefano Zampini   } else {
769c2151214SStefano Zampini     eedges  = alleedges;
770c2151214SStefano Zampini     primals = allprimals;
771c2151214SStefano Zampini   }
772c2151214SStefano Zampini 
773a13144ffSStefano Zampini   /* Mark fine edge dofs with their coarse edge id */
7749566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(marks, ne));
7759566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
7769566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
777c2151214SStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = nee + 1;
7789566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
779c2151214SStefano Zampini   if (print) {
7809566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs"));
7819566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
782c2151214SStefano Zampini   }
783c2151214SStefano Zampini 
784c2151214SStefano Zampini   maxsize = 0;
785a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
786a13144ffSStefano Zampini     PetscInt size, mark = i + 1;
787a13144ffSStefano Zampini 
7889566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
7899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
790a13144ffSStefano Zampini     for (j = 0; j < size; j++) marks[idxs[j]] = mark;
7919566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
792a13144ffSStefano Zampini     maxsize = PetscMax(maxsize, size);
793a13144ffSStefano Zampini   }
794a13144ffSStefano Zampini 
795a13144ffSStefano Zampini   /* Find coarse edge endpoints */
7969566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
7979566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
798a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
799a13144ffSStefano Zampini     PetscInt mark = i + 1, size;
800a13144ffSStefano Zampini 
8019566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
8021e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
80363a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
805a13144ffSStefano Zampini     if (print) {
80663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINTS ANALYSIS EDGE %" PetscInt_FMT "\n", i));
8079566063dSJacob Faibussowitsch       PetscCall(ISView(eedges[i], NULL));
808a13144ffSStefano Zampini     }
809a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
810a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
8113ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  idx %" PetscInt_FMT "\n", ee));
812a13144ffSStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
8133ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    inspect %" PetscInt_FMT "\n", jj[k]));
814a13144ffSStefano Zampini         if (PetscBTLookup(btv, jj[k])) {
8153ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      corner found (already set) %" PetscInt_FMT "\n", jj[k]));
816a13144ffSStefano Zampini         } else if (PetscBTLookup(btvcand, jj[k])) { /* is it ok? */
817a13144ffSStefano Zampini           PetscInt  k2;
818a13144ffSStefano Zampini           PetscBool corner = PETSC_FALSE;
819a13144ffSStefano Zampini           for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) {
8203ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        INSPECTING %" PetscInt_FMT ": mark %" PetscInt_FMT " (ref mark %" PetscInt_FMT "), boundary %d\n", jjt[k2], marks[jjt[k2]], mark, (int)!!PetscBTLookup(btb, jjt[k2])));
821c2151214SStefano Zampini             /* it's a corner if either is connected with an edge dof belonging to a different cc or
822c2151214SStefano Zampini                if the edge dof lie on the natural part of the boundary */
823c2151214SStefano Zampini             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb, jjt[k2]))) {
824a13144ffSStefano Zampini               corner = PETSC_TRUE;
825a13144ffSStefano Zampini               break;
826a13144ffSStefano Zampini             }
827a13144ffSStefano Zampini           }
828a13144ffSStefano Zampini           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
8293ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        corner found %" PetscInt_FMT "\n", jj[k]));
8309566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
831a13144ffSStefano Zampini           } else {
8323ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        no corners found\n"));
833a13144ffSStefano Zampini           }
834a13144ffSStefano Zampini         }
835a13144ffSStefano Zampini       }
836a13144ffSStefano Zampini     }
8379566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
838a13144ffSStefano Zampini   }
8399566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
8409566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8419566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btb));
842a13144ffSStefano Zampini 
843a13144ffSStefano Zampini   /* Reset marked primal dofs */
8449566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
8459566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
846a13144ffSStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = 0;
8479566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
848a13144ffSStefano Zampini 
8490569b399SStefano Zampini   /* Now use the initial lG */
8509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
8519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
8520569b399SStefano Zampini   lG = lGinit;
8539566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
8540569b399SStefano Zampini 
855a13144ffSStefano Zampini   /* Compute extended cols indices */
8569566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvc));
8579566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nee, &bter));
8589566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
8599566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lG, &i));
860a13144ffSStefano Zampini   i *= maxsize;
8619566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extcols));
8629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i, &extrow, i, &gidxs));
863a13144ffSStefano Zampini   eerr = PETSC_FALSE;
864a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
865b03ebc13SStefano Zampini     PetscInt size, found = 0;
866a13144ffSStefano Zampini 
867a13144ffSStefano Zampini     cum = 0;
8689566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
8691e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
87063a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
8719566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
8729566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
873a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
874a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
875b03ebc13SStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
876b03ebc13SStefano Zampini         PetscInt vv = jj[k];
877b03ebc13SStefano Zampini         if (!PetscBTLookup(btv, vv)) extrow[cum++] = vv;
878b03ebc13SStefano Zampini         else if (!PetscBTLookupSet(btvc, vv)) found++;
879b03ebc13SStefano Zampini       }
880a13144ffSStefano Zampini     }
8819566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
8829566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
8839566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
8849566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
8859566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
886a13144ffSStefano Zampini     /* it may happen that endpoints are not defined at this point
887a13144ffSStefano Zampini        if it is the case, mark this edge for a second pass */
888b03ebc13SStefano Zampini     if (cum != size - 1 || found != 2) {
8899566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(bter, i));
890a13144ffSStefano Zampini       if (print) {
8919566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge"));
8929566063dSJacob Faibussowitsch         PetscCall(ISView(eedges[i], NULL));
8939566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol"));
8949566063dSJacob Faibussowitsch         PetscCall(ISView(extcols[i], NULL));
895a13144ffSStefano Zampini       }
896a13144ffSStefano Zampini       eerr = PETSC_TRUE;
897a13144ffSStefano Zampini     }
898a13144ffSStefano Zampini   }
89928b400f6SJacob Faibussowitsch   /* PetscCheck(!eerr,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
9001c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&eerr, &done, 1, MPIU_BOOL, MPI_LOR, comm));
901a13144ffSStefano Zampini   if (done) {
902a13144ffSStefano Zampini     PetscInt *newprimals;
903a13144ffSStefano Zampini 
9049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &newprimals));
9059566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(primals, &cum));
9069566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(primals, &idxs));
9079566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(newprimals, idxs, cum));
9089566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(primals, &idxs));
9099566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9103ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOING SECOND PASS (eerr %s)\n", PetscBools[eerr]));
911a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
912b03ebc13SStefano Zampini       PetscBool has_candidates = PETSC_FALSE;
913b03ebc13SStefano Zampini       if (PetscBTLookup(bter, i)) {
914a13144ffSStefano Zampini         PetscInt size, mark = i + 1;
915a13144ffSStefano Zampini 
9169566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(eedges[i], &size));
9179566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(eedges[i], &idxs));
918c2151214SStefano Zampini         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
919a13144ffSStefano Zampini         for (j = 0; j < size; j++) {
920a13144ffSStefano Zampini           PetscInt k, ee = idxs[j];
9213ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Inspecting edge dof %" PetscInt_FMT " [%" PetscInt_FMT " %" PetscInt_FMT ")\n", ee, ii[ee], ii[ee + 1]));
922a13144ffSStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
923a13144ffSStefano Zampini             /* set all candidates located on the edge as corners */
924a13144ffSStefano Zampini             if (PetscBTLookup(btvcand, jj[k])) {
925a13144ffSStefano Zampini               PetscInt k2, vv = jj[k];
926b03ebc13SStefano Zampini               has_candidates = PETSC_TRUE;
9273ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Candidate set to vertex %" PetscInt_FMT "\n", vv));
9289566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(btv, vv));
929a13144ffSStefano Zampini               /* set all edge dofs connected to candidate as primals */
930a13144ffSStefano Zampini               for (k2 = iit[vv]; k2 < iit[vv + 1]; k2++) {
931a13144ffSStefano Zampini                 if (marks[jjt[k2]] == mark) {
932a13144ffSStefano Zampini                   PetscInt k3, ee2 = jjt[k2];
9333ba16761SJacob Faibussowitsch                   if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Connected edge dof set to primal %" PetscInt_FMT "\n", ee2));
934a13144ffSStefano Zampini                   newprimals[cum++] = ee2;
935a13144ffSStefano Zampini                   /* finally set the new corners */
936a13144ffSStefano Zampini                   for (k3 = ii[ee2]; k3 < ii[ee2 + 1]; k3++) {
9373ba16761SJacob Faibussowitsch                     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Connected nodal dof set to vertex %" PetscInt_FMT "\n", jj[k3]));
9389566063dSJacob Faibussowitsch                     PetscCall(PetscBTSet(btv, jj[k3]));
939a13144ffSStefano Zampini                   }
940a13144ffSStefano Zampini                 }
941a13144ffSStefano Zampini               }
942b03ebc13SStefano Zampini             } else {
9433ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Not a candidate vertex %" PetscInt_FMT "\n", jj[k]));
944a13144ffSStefano Zampini             }
945a13144ffSStefano Zampini           }
946a13144ffSStefano Zampini         }
947b03ebc13SStefano Zampini         if (!has_candidates) { /* circular edge */
948b03ebc13SStefano Zampini           PetscInt k, ee = idxs[0], *tmarks;
949b03ebc13SStefano Zampini 
9509566063dSJacob Faibussowitsch           PetscCall(PetscCalloc1(ne, &tmarks));
9513ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Circular edge %" PetscInt_FMT "\n", i));
952b03ebc13SStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
953b03ebc13SStefano Zampini             PetscInt k2;
9543ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Set to corner %" PetscInt_FMT "\n", jj[k]));
9559566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
956b03ebc13SStefano Zampini             for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) tmarks[jjt[k2]]++;
957b03ebc13SStefano Zampini           }
958b03ebc13SStefano Zampini           for (j = 0; j < size; j++) {
959b03ebc13SStefano Zampini             if (tmarks[idxs[j]] > 1) {
9603ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge dof set to primal %" PetscInt_FMT "\n", idxs[j]));
961b03ebc13SStefano Zampini               newprimals[cum++] = idxs[j];
962b03ebc13SStefano Zampini             }
963b03ebc13SStefano Zampini           }
9649566063dSJacob Faibussowitsch           PetscCall(PetscFree(tmarks));
965b03ebc13SStefano Zampini         }
9669566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(eedges[i], &idxs));
967a13144ffSStefano Zampini       }
9689566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&extcols[i]));
969a13144ffSStefano Zampini     }
9709566063dSJacob Faibussowitsch     PetscCall(PetscFree(extcols));
9719566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9729566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, newprimals));
973c2151214SStefano Zampini     if (fl2g) {
9749566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, newprimals, newprimals));
9759566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&primals));
97648a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
9779566063dSJacob Faibussowitsch       PetscCall(PetscFree(eedges));
978c2151214SStefano Zampini     }
9799566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
9809566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, newprimals, PETSC_COPY_VALUES, &primals));
9819566063dSJacob Faibussowitsch     PetscCall(PetscFree(newprimals));
9829566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
9839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
9849566063dSJacob Faibussowitsch     PetscCall(PCBDDCAnalyzeInterface(pc));
985213b8bfaSStefano Zampini     pcbddc->mat_graph->twodim = PETSC_FALSE;
9869566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
987c2151214SStefano Zampini     if (fl2g) {
9889566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
9899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nee, &eedges));
99048a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
991c2151214SStefano Zampini     } else {
992c2151214SStefano Zampini       eedges  = alleedges;
993c2151214SStefano Zampini       primals = allprimals;
994c2151214SStefano Zampini     }
9959566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nee, &extcols));
996a13144ffSStefano Zampini 
997a13144ffSStefano Zampini     /* Mark again */
9989566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(marks, ne));
999a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1000a13144ffSStefano Zampini       PetscInt size, mark = i + 1;
1001a13144ffSStefano Zampini 
10029566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10039566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1004a13144ffSStefano Zampini       for (j = 0; j < size; j++) marks[idxs[j]] = mark;
10059566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1006a13144ffSStefano Zampini     }
1007a13144ffSStefano Zampini     if (print) {
10089566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs_secondpass"));
10099566063dSJacob Faibussowitsch       PetscCall(ISView(primals, NULL));
1010a13144ffSStefano Zampini     }
1011a13144ffSStefano Zampini 
1012a13144ffSStefano Zampini     /* Recompute extended cols */
1013a13144ffSStefano Zampini     eerr = PETSC_FALSE;
1014a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1015a13144ffSStefano Zampini       PetscInt size;
1016a13144ffSStefano Zampini 
1017a13144ffSStefano Zampini       cum = 0;
10189566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
10191e0482f5SStefano Zampini       if (!size && nedfieldlocal) continue;
102063a3b9bcSJacob Faibussowitsch       PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10219566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1022a13144ffSStefano Zampini       for (j = 0; j < size; j++) {
1023a13144ffSStefano Zampini         PetscInt k, ee = idxs[j];
10249371c9d4SSatish Balay         for (k = ii[ee]; k < ii[ee + 1]; k++)
10259371c9d4SSatish Balay           if (!PetscBTLookup(btv, jj[k])) extrow[cum++] = jj[k];
1026a13144ffSStefano Zampini       }
10279566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
10289566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
10299566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
10309566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
10319566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1032a13144ffSStefano Zampini       if (cum != size - 1) {
1033a13144ffSStefano Zampini         if (print) {
10349566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge_secondpass"));
10359566063dSJacob Faibussowitsch           PetscCall(ISView(eedges[i], NULL));
10369566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol_secondpass"));
10379566063dSJacob Faibussowitsch           PetscCall(ISView(extcols[i], NULL));
1038a13144ffSStefano Zampini         }
1039a13144ffSStefano Zampini         eerr = PETSC_TRUE;
1040a13144ffSStefano Zampini       }
1041a13144ffSStefano Zampini     }
1042a13144ffSStefano Zampini   }
10439566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10449566063dSJacob Faibussowitsch   PetscCall(PetscFree2(extrow, gidxs));
10459566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bter));
10469566063dSJacob Faibussowitsch   if (print) PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, 5, PETSC_VIEWER_STDOUT_SELF));
1047a13144ffSStefano Zampini   /* an error should not occur at this point */
104828b400f6SJacob Faibussowitsch   PetscCheck(!eerr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1049a13144ffSStefano Zampini 
10504e64d54eSstefano_zampini   /* Check the number of endpoints */
10519566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * nee, &corners));
10539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &cedges));
10544e64d54eSstefano_zampini   for (i = 0; i < nee; i++) {
1055b03ebc13SStefano Zampini     PetscInt size, found = 0, gc[2];
10564e64d54eSstefano_zampini 
1057b03ebc13SStefano Zampini     /* init with defaults */
1058b03ebc13SStefano Zampini     cedges[i] = corners[i * 2] = corners[i * 2 + 1] = -1;
10599566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
10601e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
106163a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10629566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
10639566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
10644e64d54eSstefano_zampini     for (j = 0; j < size; j++) {
10654e64d54eSstefano_zampini       PetscInt k, ee = idxs[j];
10664e64d54eSstefano_zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
10674e64d54eSstefano_zampini         PetscInt vv = jj[k];
10684e64d54eSstefano_zampini         if (PetscBTLookup(btv, vv) && !PetscBTLookupSet(btvc, vv)) {
106963a3b9bcSJacob Faibussowitsch           PetscCheck(found != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more then two corners for edge %" PetscInt_FMT, i);
1070b03ebc13SStefano Zampini           corners[i * 2 + found++] = vv;
10714e64d54eSstefano_zampini         }
10724e64d54eSstefano_zampini       }
10734e64d54eSstefano_zampini     }
1074b03ebc13SStefano Zampini     if (found != 2) {
1075b03ebc13SStefano Zampini       PetscInt e;
1076b03ebc13SStefano Zampini       if (fl2g) {
10779566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, 1, idxs, &e));
1078b03ebc13SStefano Zampini       } else {
1079b03ebc13SStefano Zampini         e = idxs[0];
1080b03ebc13SStefano Zampini       }
108163a3b9bcSJacob 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]);
1082b03ebc13SStefano Zampini     }
1083eee23b56SStefano Zampini 
1084eee23b56SStefano Zampini     /* get primal dof index on this coarse edge */
10859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, 2, corners + 2 * i, gc));
1086b03ebc13SStefano Zampini     if (gc[0] > gc[1]) {
1087b03ebc13SStefano Zampini       PetscInt swap      = corners[2 * i];
1088b03ebc13SStefano Zampini       corners[2 * i]     = corners[2 * i + 1];
1089b03ebc13SStefano Zampini       corners[2 * i + 1] = swap;
1090b03ebc13SStefano Zampini     }
1091eee23b56SStefano Zampini     cedges[i] = idxs[size - 1];
10929566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
10933ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "EDGE %" PetscInt_FMT ": ce %" PetscInt_FMT ", corners (%" PetscInt_FMT ",%" PetscInt_FMT ")\n", i, cedges[i], corners[2 * i], corners[2 * i + 1]));
10944e64d54eSstefano_zampini   }
10959566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
10969566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvc));
10974e64d54eSstefano_zampini 
109876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
1099a13144ffSStefano Zampini     /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1100a13144ffSStefano Zampini      not interfere with neighbouring coarse edges */
11019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee + 1, &emarks));
11029566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
1103a13144ffSStefano Zampini     for (i = 0; i < nv; i++) {
1104a13144ffSStefano Zampini       PetscInt emax = 0, eemax = 0;
1105a13144ffSStefano Zampini 
1106a13144ffSStefano Zampini       if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
11079566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(emarks, nee + 1));
1108a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) emarks[marks[jj[j]]]++;
1109a13144ffSStefano Zampini       for (j = 1; j < nee + 1; j++) {
1110a13144ffSStefano Zampini         if (emax < emarks[j]) {
1111a13144ffSStefano Zampini           emax  = emarks[j];
1112a13144ffSStefano Zampini           eemax = j;
1113a13144ffSStefano Zampini         }
1114a13144ffSStefano Zampini       }
1115a13144ffSStefano Zampini       /* not relevant for edges */
1116a13144ffSStefano Zampini       if (!eemax) continue;
1117a13144ffSStefano Zampini 
1118a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
11197a46b595SBarry 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]);
1120a13144ffSStefano Zampini       }
1121a13144ffSStefano Zampini     }
11229566063dSJacob Faibussowitsch     PetscCall(PetscFree(emarks));
11239566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
112476bd3646SJed Brown   }
1125a13144ffSStefano Zampini 
1126a13144ffSStefano Zampini   /* Compute extended rows indices for edge blocks of the change of basis */
11279566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11289566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lGt, &extmem));
1129a13144ffSStefano Zampini   extmem *= maxsize;
11309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(extmem * nee, &extrow));
11319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &extrows));
11329566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extrowcum));
1133a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
1134a13144ffSStefano Zampini     PetscInt mark = 0, size, start;
1135213b8bfaSStefano Zampini 
1136a13144ffSStefano Zampini     if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
1137a13144ffSStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++)
11389371c9d4SSatish Balay       if (marks[jj[j]] && !mark) mark = marks[jj[j]];
1139a13144ffSStefano Zampini 
1140a13144ffSStefano Zampini     /* not relevant */
1141a13144ffSStefano Zampini     if (!mark) continue;
1142a13144ffSStefano Zampini 
1143a13144ffSStefano Zampini     /* import extended row */
1144a13144ffSStefano Zampini     mark--;
1145a13144ffSStefano Zampini     start = mark * extmem + extrowcum[mark];
1146a13144ffSStefano Zampini     size  = ii[i + 1] - ii[i];
114763a3b9bcSJacob Faibussowitsch     PetscCheck(extrowcum[mark] + size <= extmem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not enough memory allocated %" PetscInt_FMT " > %" PetscInt_FMT, extrowcum[mark] + size, extmem);
11489566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(extrow + start, jj + ii[i], size));
1149a13144ffSStefano Zampini     extrowcum[mark] += size;
1150a13144ffSStefano Zampini   }
11519566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
11539566063dSJacob Faibussowitsch   PetscCall(PetscFree(marks));
1154213b8bfaSStefano Zampini 
1155213b8bfaSStefano Zampini   /* Compress extrows */
1156a13144ffSStefano Zampini   cum = 0;
1157a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1158a13144ffSStefano Zampini     PetscInt size = extrowcum[i], *start = extrow + i * extmem;
11599566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&size, start));
11609566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, start, PETSC_USE_POINTER, &extrows[i]));
1161a13144ffSStefano Zampini     cum = PetscMax(cum, size);
1162a13144ffSStefano Zampini   }
11639566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrowcum));
11649566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btv));
11659566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvcand));
1166a13144ffSStefano Zampini 
1167a13144ffSStefano Zampini   /* Workspace for lapack inner calls and VecSetValues */
11689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2((5 + cum + maxsize) * maxsize, &work, maxsize, &rwork));
1169a13144ffSStefano Zampini 
1170a13144ffSStefano Zampini   /* Create change of basis matrix (preallocation can be improved) */
11719566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
1172d0609cedSBarry Smith   PetscCall(MatSetSizes(T, pc->pmat->rmap->n, pc->pmat->rmap->n, pc->pmat->rmap->N, pc->pmat->rmap->N));
11739566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
11749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(T, 10, NULL));
11759566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(T, 10, NULL, 10, NULL));
11769566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
11779566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
11789566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
11799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1180a13144ffSStefano Zampini 
1181a13144ffSStefano Zampini   /* Defaults to identity */
11829566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &tvec, NULL));
11839566063dSJacob Faibussowitsch   PetscCall(VecSet(tvec, 1.0));
11849566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(T, tvec, INSERT_VALUES));
11859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&tvec));
1186a13144ffSStefano Zampini 
11871e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
11889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
11899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
11901e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
11911e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
11921e0482f5SStefano Zampini     IS                     wis, gwis;
11931e0482f5SStefano Zampini     PetscInt               cnv, cne;
11941e0482f5SStefano Zampini 
11959566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
11961e0482f5SStefano Zampini     if (fl2g) {
11979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
11981e0482f5SStefano Zampini     } else {
11999566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
12001e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
12011e0482f5SStefano Zampini     }
12029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
12039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12049566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
12059566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
12069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12079566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12081e0482f5SStefano Zampini 
12099566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
12109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
12119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12129566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
12139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
12149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
12159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
12161e0482f5SStefano Zampini 
12179566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
12189566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
12199566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
12209566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
12219566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
12229566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
12239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
12249566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
12251e0482f5SStefano Zampini   }
12269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
12271e0482f5SStefano Zampini 
12281e0482f5SStefano Zampini #if defined(PRINT_GDET)
12291e0482f5SStefano Zampini   inc = 0;
12301e0482f5SStefano Zampini   lev = pcbddc->current_level;
12311e0482f5SStefano Zampini #endif
1232213b8bfaSStefano Zampini 
1233213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1234a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1235a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
12361e0482f5SStefano Zampini     IS          cornersis = NULL;
12371e0482f5SStefano Zampini     PetscScalar cvals[2];
1238a13144ffSStefano Zampini 
123948a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
12409566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1241a13144ffSStefano Zampini     if (Gins && GKins) {
12421683a169SBarry Smith       const PetscScalar *data;
1243a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1244a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1245a13144ffSStefano Zampini 
12469566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1247a13144ffSStefano Zampini       /* H1 */
12489566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
12499566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
12509566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
12519566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
12529566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
12539566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1254a13144ffSStefano Zampini       /* complement */
12559566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
125663a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
125763a3b9bcSJacob 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);
125863a3b9bcSJacob 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);
12599566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
12609566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
12619566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
12621e0482f5SStefano Zampini 
12631e0482f5SStefano Zampini       /* coarse discrete gradient */
12641e0482f5SStefano Zampini       if (pcbddc->nedcG) {
12651e0482f5SStefano Zampini         PetscInt cols[2];
12661e0482f5SStefano Zampini 
12671e0482f5SStefano Zampini         cols[0] = 2 * i;
12681e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
12699566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
12701e0482f5SStefano Zampini       }
12719566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1272a13144ffSStefano Zampini     }
12739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
12749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
12759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
12769566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
12779566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1278a13144ffSStefano Zampini   }
12799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1280a13144ffSStefano Zampini 
1281a13144ffSStefano Zampini   /* Start assembling */
12829566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
12831baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1284a13144ffSStefano Zampini 
1285a13144ffSStefano Zampini   /* Free */
1286c2151214SStefano Zampini   if (fl2g) {
12879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
128848a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
12899566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1290c2151214SStefano Zampini   }
1291eee23b56SStefano Zampini 
1292eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1293eee23b56SStefano Zampini   {
1294eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1295eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1296eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1297eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1298eee23b56SStefano Zampini 
1299eee23b56SStefano Zampini     /* find first primal edge */
1300eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
13019566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1302eee23b56SStefano Zampini     } else {
13031baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1304eee23b56SStefano Zampini       idxs = cedges;
1305eee23b56SStefano Zampini     }
1306eee23b56SStefano Zampini     cum = 0;
1307eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1308eee23b56SStefano Zampini 
1309eee23b56SStefano Zampini     /* adapt connected components */
13109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1311eee23b56SStefano Zampini     graph->cptr[0] = 0;
1312eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1313eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1314eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1315eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1316eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1317eee23b56SStefano Zampini         ncc++;
1318eee23b56SStefano Zampini         lc--;
1319eee23b56SStefano Zampini         cum++;
1320eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1321eee23b56SStefano Zampini       }
1322eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1323eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1324eee23b56SStefano Zampini       ncc++;
1325eee23b56SStefano Zampini     }
1326eee23b56SStefano Zampini     graph->ncc = ncc;
132748a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
13289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1329eee23b56SStefano Zampini   }
13309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
13319566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
13329566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
13339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
1334eee23b56SStefano Zampini 
13359566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
13369566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
13379566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
13389566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
13399566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
13409566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
13419566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
13429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1343a13144ffSStefano Zampini 
1344a13144ffSStefano Zampini   /* Complete assembling */
13459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
13461e0482f5SStefano Zampini   if (pcbddc->nedcG) {
13479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
13481e0482f5SStefano Zampini #if 0
13499566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->nedcG,"coarse_G"));
13509566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->nedcG,NULL));
13511e0482f5SStefano Zampini #endif
13521e0482f5SStefano Zampini   }
1353a13144ffSStefano Zampini 
1354a13144ffSStefano Zampini   /* set change of basis */
13559566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, singular));
13569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
1357a13144ffSStefano Zampini 
13583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1359a13144ffSStefano Zampini }
1360a13144ffSStefano Zampini 
1361d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1362d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1363d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
1364d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1365d71ae5a4SJacob Faibussowitsch {
1366d8203eabSStefano Zampini   PetscInt i;
1367d8203eabSStefano Zampini 
1368d8203eabSStefano Zampini   PetscFunctionBegin;
1369d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1370d8203eabSStefano Zampini     PetscInt first, last;
1371d8203eabSStefano Zampini 
13729566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
13737827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1374d8203eabSStefano Zampini     if (i >= first && i < last) {
1375d8203eabSStefano Zampini       PetscScalar *data;
13769566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1377d8203eabSStefano Zampini       if (!has_const) {
1378d8203eabSStefano Zampini         data[i - first] = 1.;
1379d8203eabSStefano Zampini       } else {
138086fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
138186fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1382d8203eabSStefano Zampini       }
13839566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1384d8203eabSStefano Zampini     }
13859566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1386d8203eabSStefano Zampini   }
13879566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1388d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1389d8203eabSStefano Zampini     PetscInt first, last;
13909566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
13919566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1392d8203eabSStefano Zampini     if (i >= first && i < last) {
1393d8203eabSStefano Zampini       PetscScalar *data;
13949566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1395d8203eabSStefano Zampini       if (!has_const) {
1396d8203eabSStefano Zampini         data[i - first] = 0.;
1397d8203eabSStefano Zampini       } else {
139886fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
139986fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1400d8203eabSStefano Zampini       }
14019566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1402d8203eabSStefano Zampini     }
14039566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
14049566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1405d8203eabSStefano Zampini   }
14063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1407d8203eabSStefano Zampini }
1408d8203eabSStefano Zampini 
1409d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1410d71ae5a4SJacob Faibussowitsch {
1411a198735bSStefano Zampini   Mat                    loc_divudotp;
1412fa23a32eSStefano Zampini   Vec                    p, v, vins, quad_vec, *quad_vecs;
14138ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
1414669cc0f4SStefano Zampini   PetscScalar           *vals;
1415669cc0f4SStefano Zampini   const PetscScalar     *array;
14160f04eeffSStefano Zampini   PetscInt               i, maxneighs = 0, maxsize, *gidxs;
1417a040e873SStefano Zampini   PetscInt               n_neigh, *neigh, *n_shared, **shared;
14181ae86dd6SStefano Zampini   PetscMPIInt            rank;
1419669cc0f4SStefano Zampini 
1420669cc0f4SStefano Zampini   PetscFunctionBegin;
14219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14220f04eeffSStefano Zampini   for (i = 0; i < n_neigh; i++) maxneighs = PetscMax(graph->count[shared[i][0]] + 1, maxneighs);
14231c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &maxneighs, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)A)));
14248037d520SStefano Zampini   if (!maxneighs) {
14259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14268037d520SStefano Zampini     *nnsp = NULL;
14273ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1428669cc0f4SStefano Zampini   }
1429669cc0f4SStefano Zampini   maxsize = 0;
1430a040e873SStefano Zampini   for (i = 0; i < n_neigh; i++) maxsize = PetscMax(n_shared[i], maxsize);
14319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxsize, &gidxs, maxsize, &vals));
1432669cc0f4SStefano Zampini   /* create vectors to hold quadrature weights */
14339566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
14348ae0ca82SStefano Zampini   if (!transpose) {
14359566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
14368ae0ca82SStefano Zampini   } else {
14379566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
14388ae0ca82SStefano Zampini   }
14399566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(quad_vec, maxneighs, &quad_vecs));
14409566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&quad_vec));
14419566063dSJacob Faibussowitsch   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, maxneighs, quad_vecs, nnsp));
144248a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecLockReadPop(quad_vecs[i]));
1443d8203eabSStefano Zampini 
1444669cc0f4SStefano Zampini   /* compute local quad vec */
14459566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
14468ae0ca82SStefano Zampini   if (!transpose) {
14479566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
14488ae0ca82SStefano Zampini   } else {
14499566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
14508ae0ca82SStefano Zampini   }
14519566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
14528ae0ca82SStefano Zampini   if (!transpose) {
14539566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
14548ae0ca82SStefano Zampini   } else {
14559566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
14568ae0ca82SStefano Zampini   }
1457fa23a32eSStefano Zampini   if (vl2l) {
1458187c917aSStefano Zampini     Mat        lA;
1459187c917aSStefano Zampini     VecScatter sc;
1460187c917aSStefano Zampini 
14619566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
14629566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
14639566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
14649566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14659566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
14669566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
1467fa23a32eSStefano Zampini   } else {
1468fa23a32eSStefano Zampini     vins = v;
1469fa23a32eSStefano Zampini   }
14709566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(vins, &array));
14719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&p));
14729a962809SStefano Zampini 
14731ae86dd6SStefano Zampini   /* insert in global quadrature vecs */
14749566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
14750f04eeffSStefano Zampini   for (i = 1; i < n_neigh; i++) {
1476669cc0f4SStefano Zampini     const PetscInt *idxs;
1477669cc0f4SStefano Zampini     PetscInt        idx, nn, j;
1478669cc0f4SStefano Zampini 
1479a040e873SStefano Zampini     idxs = shared[i];
1480a040e873SStefano Zampini     nn   = n_shared[i];
1481669cc0f4SStefano Zampini     for (j = 0; j < nn; j++) vals[j] = array[idxs[j]];
14829566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(rank, graph->count[idxs[0]], graph->neighbours_set[idxs[0]], &idx));
1483669cc0f4SStefano Zampini     idx = -(idx + 1);
148463a3b9bcSJacob Faibussowitsch     PetscCheck(idx >= 0 && idx < maxneighs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid index %" PetscInt_FMT " not in [0,%" PetscInt_FMT ")", idx, maxneighs);
14859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(map, nn, idxs, gidxs));
14869566063dSJacob Faibussowitsch     PetscCall(VecSetValues(quad_vecs[idx], nn, gidxs, vals, INSERT_VALUES));
1487669cc0f4SStefano Zampini   }
14889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
14899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(vins, &array));
149048a46eb9SPierre Jolivet   if (vl2l) PetscCall(VecDestroy(&vins));
14919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
14929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(gidxs, vals));
1493669cc0f4SStefano Zampini 
1494669cc0f4SStefano Zampini   /* assemble near null space */
149548a46eb9SPierre Jolivet   for (i = 0; i < maxneighs; i++) PetscCall(VecAssemblyBegin(quad_vecs[i]));
1496669cc0f4SStefano Zampini   for (i = 0; i < maxneighs; i++) {
14979566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(quad_vecs[i]));
14989566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(quad_vecs[i], NULL, "-pc_bddc_quad_vecs_view"));
14999566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1500669cc0f4SStefano Zampini   }
15019566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(maxneighs, &quad_vecs));
15023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1503669cc0f4SStefano Zampini }
1504669cc0f4SStefano Zampini 
1505d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1506d71ae5a4SJacob Faibussowitsch {
15077620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
15087620a527SStefano Zampini 
15097620a527SStefano Zampini   PetscFunctionBegin;
15107620a527SStefano Zampini   if (primalv) {
15117620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
15127620a527SStefano Zampini       IS list[2], newp;
15137620a527SStefano Zampini 
15147620a527SStefano Zampini       list[0] = primalv;
15157620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
15169566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
15179566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
15189566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
15197620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
15207620a527SStefano Zampini     } else {
15219566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
15227620a527SStefano Zampini     }
15237620a527SStefano Zampini   }
15243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15257620a527SStefano Zampini }
1526669cc0f4SStefano Zampini 
1527d71ae5a4SJacob Faibussowitsch static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1528d71ae5a4SJacob Faibussowitsch {
15291c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
15301c7a958bSStefano Zampini 
15311c7a958bSStefano Zampini   PetscFunctionBegin;
15321c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
15333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15341c7a958bSStefano Zampini }
1535674ae819SStefano Zampini 
1536d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1537d71ae5a4SJacob Faibussowitsch {
15381f4df5f7SStefano Zampini   Vec       local, global;
15391f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
15401f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
15415c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
15421f4df5f7SStefano Zampini 
15431f4df5f7SStefano Zampini   PetscFunctionBegin;
1544d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
15459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1546d0609cedSBarry Smith   PetscOptionsEnd();
15471f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
15489566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
15499566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
15509566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
15519566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
15526a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
155348a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
15546a8fc67bSStefano Zampini     goto boundary;
15556a8fc67bSStefano Zampini   }
15565c5e10d6SStefano Zampini 
15571f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
15581f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
15591f4df5f7SStefano Zampini       PetscInt i;
15600c85b387SStefano Zampini 
15619566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
15621f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
15630c85b387SStefano Zampini         PetscInt bs;
15640c85b387SStefano Zampini 
15659566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
15669566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
15679566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15689566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
15691f4df5f7SStefano Zampini       }
15701f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
15711f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
15729566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
15731f4df5f7SStefano Zampini     }
15741f4df5f7SStefano Zampini   } else {
157521ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
157621ef3d20SStefano Zampini       DM dm;
157721ef3d20SStefano Zampini 
15789566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
157948a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
158021ef3d20SStefano Zampini       if (dm) {
158121ef3d20SStefano Zampini         IS      *fields;
158221ef3d20SStefano Zampini         PetscInt nf, i;
15830c85b387SStefano Zampini 
15849566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
15859566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
158621ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
15870c85b387SStefano Zampini           PetscInt bs;
15880c85b387SStefano Zampini 
15899566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
15909566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
15919566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
15929566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
159321ef3d20SStefano Zampini         }
15949566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
159521ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
159621ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
159721ef3d20SStefano Zampini         PetscContainer c;
159821ef3d20SStefano Zampini 
15999566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
160021ef3d20SStefano Zampini         if (c) {
160121ef3d20SStefano Zampini           MatISLocalFields lf;
16029566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
16039566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
160421ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
16051f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
16069566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
160721ef3d20SStefano Zampini           if (i > 1) {
1608986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
16099566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
161048a46eb9SPierre 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]));
16111f4df5f7SStefano Zampini           }
161221ef3d20SStefano Zampini         }
161321ef3d20SStefano Zampini       }
16147a0e7b2cSstefano_zampini     } else {
16157a0e7b2cSstefano_zampini       PetscInt i;
161648a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
16171f4df5f7SStefano Zampini     }
1618986cdee1SStefano Zampini   }
16191f4df5f7SStefano Zampini 
16205c5e10d6SStefano Zampini boundary:
16211f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
16229566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
16237a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
16249566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
16251f4df5f7SStefano Zampini   }
16261f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
16279566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
16287a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
16299566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
16301f4df5f7SStefano Zampini   }
163148a46eb9SPierre 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));
16329566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
16339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
16347620a527SStefano Zampini   /* detect local disconnected subdomains if requested (use matis->A) */
16357620a527SStefano Zampini   if (pcbddc->detect_disconnected) {
16367620a527SStefano Zampini     IS        primalv = NULL;
16377620a527SStefano Zampini     PetscInt  i;
16388361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
16397a0e7b2cSstefano_zampini 
164048a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
16419566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
16429566063dSJacob Faibussowitsch     PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
16439566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
16449566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
16457620a527SStefano Zampini   }
16467620a527SStefano Zampini   /* early stage corner detection */
16477620a527SStefano Zampini   {
16487620a527SStefano Zampini     DM dm;
16497620a527SStefano Zampini 
16509566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
165148a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
16527620a527SStefano Zampini     if (dm) {
16537620a527SStefano Zampini       PetscBool isda;
16547620a527SStefano Zampini 
16559566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
16567620a527SStefano Zampini       if (isda) {
16577620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
16587620a527SStefano Zampini         IS                     corners;
16597620a527SStefano Zampini         Mat                    lA;
16604f819b78SStefano Zampini         PetscBool              gl, lo;
16617620a527SStefano Zampini 
16624f819b78SStefano Zampini         {
16634f819b78SStefano Zampini           Vec                cvec;
16644f819b78SStefano Zampini           const PetscScalar *coords;
16654f819b78SStefano Zampini           PetscInt           dof, n, cdim;
16664f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
16674f819b78SStefano Zampini 
16689566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
16699566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
16709566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
16719566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
16724f819b78SStefano Zampini           n /= cdim;
16739566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
16749566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
16759566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
16764f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
16774f819b78SStefano Zampini           memc = PETSC_FALSE;
16784f819b78SStefano Zampini #endif
16794f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
16804f819b78SStefano Zampini           if (memc) {
16819566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
16824f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
16834f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
16844f819b78SStefano Zampini             PetscInt   i, b, d;
16854f819b78SStefano Zampini 
16864f819b78SStefano Zampini             for (i = 0; i < n; i++) {
16874f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
1688ad540459SPierre Jolivet                 for (d = 0; d < cdim; d++) bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]);
16894f819b78SStefano Zampini               }
16904f819b78SStefano Zampini             }
16914f819b78SStefano Zampini           }
16929566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
16934f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
16944f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
16954f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
16964f819b78SStefano Zampini         }
16979566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
16989566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
16999566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
17009566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
17014f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
17021c2dc1cbSBarry Smith         PetscCall(MPIU_Allreduce(&lo, &gl, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
17034f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
17047620a527SStefano Zampini           const PetscInt *idx;
170572ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
17067620a527SStefano Zampini 
17079566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
17089566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
17099566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
17109566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
171172ed36d8SStefano Zampini           if (bs == dof) {
17129566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
17139566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
171472ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
171572ed36d8SStefano Zampini             PetscInt i, d;
171672ed36d8SStefano Zampini 
17179566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
17189371c9d4SSatish Balay             for (i = 0; i < n; i++)
17199371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
17209566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
172172ed36d8SStefano Zampini 
172272ed36d8SStefano Zampini             bs = 1;
172372ed36d8SStefano Zampini             n *= dof;
172472ed36d8SStefano Zampini           }
17259566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
17269566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17279566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
17289566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
17299566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
17301c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
17314f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
17324f819b78SStefano Zampini         }
173348a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
17347620a527SStefano Zampini       }
17357620a527SStefano Zampini     }
17367620a527SStefano Zampini   }
17371c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
17381c7a958bSStefano Zampini     DM dm;
17391c7a958bSStefano Zampini 
17409566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
174148a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
17424f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
17431c7a958bSStefano Zampini       Vec          vcoords;
17441c7a958bSStefano Zampini       PetscSection section;
17451c7a958bSStefano Zampini       PetscReal   *coords;
17461c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
17471c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
174851ab8ad6SStefano Zampini       /* debug coordinates */
174951ab8ad6SStefano Zampini       PetscViewer       viewer;
175051ab8ad6SStefano Zampini       PetscBool         flg;
175151ab8ad6SStefano Zampini       PetscViewerFormat format;
175251ab8ad6SStefano Zampini       const char       *prefix;
17531c7a958bSStefano Zampini 
17549566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
17559566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
17569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
17579566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
17589566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
17599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
17609566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
17619566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
17621c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
17631c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
176451ab8ad6SStefano Zampini 
176551ab8ad6SStefano Zampini       /* debug coordinates */
176651ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
176751ab8ad6SStefano Zampini       PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
176851ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
17691c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
17701c7a958bSStefano Zampini         PetscInt           i;
17711c7a958bSStefano Zampini         const PetscScalar *v;
177251ab8ad6SStefano Zampini         char               name[16];
17731c7a958bSStefano Zampini 
17741c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
177551ab8ad6SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%d", (int)d));
177651ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
17779566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
177851ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
17799566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
17801c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
17819566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
17821c7a958bSStefano Zampini       }
17839566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
17849566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
17859566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
17869566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
17879566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
178851ab8ad6SStefano Zampini       if (flg) {
178951ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
179051ab8ad6SStefano Zampini         PetscCall(PetscViewerDestroy(&viewer));
179151ab8ad6SStefano Zampini       }
17921c7a958bSStefano Zampini     }
17931c7a958bSStefano Zampini   }
17943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17957a0e7b2cSstefano_zampini }
17967a0e7b2cSstefano_zampini 
1797d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
1798d71ae5a4SJacob Faibussowitsch {
17997a0e7b2cSstefano_zampini   Mat_IS         *matis = (Mat_IS *)(pc->pmat->data);
18007a0e7b2cSstefano_zampini   IS              nis;
18017a0e7b2cSstefano_zampini   const PetscInt *idxs;
18027a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
18037a0e7b2cSstefano_zampini 
18047a0e7b2cSstefano_zampini   PetscFunctionBegin;
18057827d75bSBarry Smith   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)(pc)), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
18067a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
18077a0e7b2cSstefano_zampini     /* init rootdata with true */
18081bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
18097a0e7b2cSstefano_zampini   } else {
18109566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
18117a0e7b2cSstefano_zampini   }
18129566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
18139566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
18149566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
18157a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
18169371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
18179566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
18189566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18199566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
18209566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18219566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18227a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
18239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
18247a0e7b2cSstefano_zampini   } else {
18259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
18267a0e7b2cSstefano_zampini   }
18277a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
18289371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
18299566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(*is)), nnd, nidxs, PETSC_OWN_POINTER, &nis));
18309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
18317a0e7b2cSstefano_zampini   *is = nis;
18323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18331f4df5f7SStefano Zampini }
18341f4df5f7SStefano Zampini 
1835d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z)
1836d71ae5a4SJacob Faibussowitsch {
18373e589ea0SStefano Zampini   PC_IS   *pcis   = (PC_IS *)(pc->data);
18383e589ea0SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)(pc->data);
18393e589ea0SStefano Zampini 
18403e589ea0SStefano Zampini   PetscFunctionBegin;
18413ba16761SJacob Faibussowitsch   if (!pcbddc->benign_have_null) PetscFunctionReturn(PETSC_SUCCESS);
18423e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
18433e589ea0SStefano Zampini     Vec swap;
18443e589ea0SStefano Zampini 
18459566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
18463e589ea0SStefano Zampini     swap                = pcbddc->work_change;
18473e589ea0SStefano Zampini     pcbddc->work_change = r;
18483e589ea0SStefano Zampini     r                   = swap;
18493e589ea0SStefano Zampini   }
18509566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18519566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
18529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18539566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
18549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
18559566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
18569566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
18579566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18589566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
18593e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
1860f913dca9SStefano Zampini     pcbddc->work_change = r;
18619566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
18629566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
18633e589ea0SStefano Zampini   }
18643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18653e589ea0SStefano Zampini }
18663e589ea0SStefano Zampini 
1867d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
1868d71ae5a4SJacob Faibussowitsch {
1869a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1870a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
1871a3df083aSStefano Zampini 
1872a3df083aSStefano Zampini   PetscFunctionBegin;
18739566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
1874a3df083aSStefano Zampini   if (transpose) {
1875a3df083aSStefano Zampini     apply_right = ctx->apply_left;
1876a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
1877a3df083aSStefano Zampini   } else {
1878a3df083aSStefano Zampini     apply_right = ctx->apply_right;
1879a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
1880a3df083aSStefano Zampini   }
1881a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
1882a3df083aSStefano Zampini   if (apply_right) {
1883a3df083aSStefano Zampini     const PetscScalar *ax;
1884a3df083aSStefano Zampini     PetscInt           nl, i;
1885a3df083aSStefano Zampini 
18869566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
18879566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
18889566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
18899566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
1890a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1891a3df083aSStefano Zampini       PetscScalar     sum, val;
1892a3df083aSStefano Zampini       const PetscInt *idxs;
1893a3df083aSStefano Zampini       PetscInt        nz, j;
18949566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
18959566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1896a3df083aSStefano Zampini       sum = 0.;
1897a3df083aSStefano Zampini       if (ctx->apply_p0) {
1898a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
1899a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1900a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
1901a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
1902a3df083aSStefano Zampini         }
1903a3df083aSStefano Zampini       } else {
1904ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) sum += ctx->work[idxs[j]];
1905a3df083aSStefano Zampini       }
1906a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
19079566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1908a3df083aSStefano Zampini     }
19099566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
1910a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
1911a3df083aSStefano Zampini   }
1912a3df083aSStefano Zampini   if (transpose) {
19139566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
1914a3df083aSStefano Zampini   } else {
19159566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
1916a3df083aSStefano Zampini   }
19171baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
1918a3df083aSStefano Zampini   if (apply_left) {
1919a3df083aSStefano Zampini     PetscScalar *ay;
1920a3df083aSStefano Zampini     PetscInt     i;
1921a3df083aSStefano Zampini 
19229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
1923a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
1924a3df083aSStefano Zampini       PetscScalar     sum, val;
1925a3df083aSStefano Zampini       const PetscInt *idxs;
1926a3df083aSStefano Zampini       PetscInt        nz, j;
19279566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
19289566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
1929a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
1930a3df083aSStefano Zampini       if (ctx->apply_p0) {
1931a3df083aSStefano Zampini         sum = 0.;
1932a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
1933a3df083aSStefano Zampini           sum += ay[idxs[j]];
1934a3df083aSStefano Zampini           ay[idxs[j]] += val;
1935a3df083aSStefano Zampini         }
1936a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
1937a3df083aSStefano Zampini       } else {
1938ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) ay[idxs[j]] += val;
1939a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
1940a3df083aSStefano Zampini       }
19419566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
1942a3df083aSStefano Zampini     }
19439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
1944a3df083aSStefano Zampini   }
19453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1946a3df083aSStefano Zampini }
1947a3df083aSStefano Zampini 
1948d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
1949d71ae5a4SJacob Faibussowitsch {
1950a3df083aSStefano Zampini   PetscFunctionBegin;
19519566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
19523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1953a3df083aSStefano Zampini }
1954a3df083aSStefano Zampini 
1955d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
1956d71ae5a4SJacob Faibussowitsch {
1957a3df083aSStefano Zampini   PetscFunctionBegin;
19589566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
19593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1960a3df083aSStefano Zampini }
1961a3df083aSStefano Zampini 
1962d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
1963d71ae5a4SJacob Faibussowitsch {
1964a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
1965a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
1966a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1967a3df083aSStefano Zampini 
1968a3df083aSStefano Zampini   PetscFunctionBegin;
1969a3df083aSStefano Zampini   if (!restore) {
19701dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
1971a3df083aSStefano Zampini     PetscScalar       *work;
1972b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
1973a3df083aSStefano Zampini 
197428b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
19753ba16761SJacob Faibussowitsch     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(PETSC_SUCCESS);
19769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
19779566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
19789566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
19799566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
19809566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (void (*)(void))PCBDDCBenignMatMult_Private));
19819566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (void (*)(void))PCBDDCBenignMatMultTranspose_Private));
19829566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
19839566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
1984a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
1985a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
1986a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
1987a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
1988059032f7SStefano Zampini     if (reuse) {
1989a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
19901dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
1991059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
1992059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
1993059032f7SStefano Zampini       PetscInt               i;
1994059032f7SStefano Zampini 
19959566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
19969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
199748a46eb9SPierre 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]));
19989566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
19991dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
2000059032f7SStefano Zampini     }
2001a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
2002a3df083aSStefano Zampini     ctx->work = work;
20039566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
20049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
20059566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
2006a3df083aSStefano Zampini     pcis->A_IB = A_IB;
2007a3df083aSStefano Zampini 
2008a3df083aSStefano Zampini     /* A_BI as A_IB^T */
20099566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
2010a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
2011a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
2012a3df083aSStefano Zampini   } else {
20133ba16761SJacob Faibussowitsch     if (!pcbddc->benign_original_mat) PetscFunctionReturn(PETSC_SUCCESS);
20149566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
20159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2016a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
20171dd7afcfSStefano Zampini     ctx->A     = NULL;
20189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
20191dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
20201dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
20211dd7afcfSStefano Zampini     if (ctx->free) {
2022059032f7SStefano Zampini       PetscInt i;
202348a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
20249566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2025059032f7SStefano Zampini     }
20269566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
20279566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2028a3df083aSStefano Zampini   }
20293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2030a3df083aSStefano Zampini }
2031a3df083aSStefano Zampini 
2032a3df083aSStefano Zampini /* used just in bddc debug mode */
2033d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2034d71ae5a4SJacob Faibussowitsch {
2035a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2036a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2037a3df083aSStefano Zampini   Mat      An;
2038a3df083aSStefano Zampini 
2039a3df083aSStefano Zampini   PetscFunctionBegin;
20409566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
20419566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2042a3df083aSStefano Zampini   if (is1) {
20439566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
20449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2045a3df083aSStefano Zampini   } else {
2046a3df083aSStefano Zampini     *B = An;
2047a3df083aSStefano Zampini   }
20483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2049a3df083aSStefano Zampini }
2050a3df083aSStefano Zampini 
20511cf9b237SStefano Zampini /* TODO: add reuse flag */
2052d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2053d71ae5a4SJacob Faibussowitsch {
20541cf9b237SStefano Zampini   Mat             Bt;
20551cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
20561cf9b237SStefano Zampini   const PetscInt *ii, *ij;
20571cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
20581cf9b237SStefano Zampini   PetscBool       flg_row;
20591cf9b237SStefano Zampini 
20601cf9b237SStefano Zampini   PetscFunctionBegin;
20619566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
20629566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20639566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
20641cf9b237SStefano Zampini   nnz = n;
20651cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
20661cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
20671cf9b237SStefano Zampini   }
20689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
20699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
20709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
20711cf9b237SStefano Zampini   nnz    = 0;
20721cf9b237SStefano Zampini   bii[0] = 0;
20731cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
20741cf9b237SStefano Zampini     PetscInt j;
20751cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
20761cf9b237SStefano Zampini       PetscScalar entry = a[j];
20773272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
20781cf9b237SStefano Zampini         bij[nnz]   = ij[j];
20791cf9b237SStefano Zampini         bdata[nnz] = entry;
20801cf9b237SStefano Zampini         nnz++;
20811cf9b237SStefano Zampini       }
20821cf9b237SStefano Zampini     }
20831cf9b237SStefano Zampini     bii[i + 1] = nnz;
20841cf9b237SStefano Zampini   }
20859566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
20869566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
20879566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
20881cf9b237SStefano Zampini   {
20891cf9b237SStefano Zampini     Mat_SeqAIJ *b = (Mat_SeqAIJ *)(Bt->data);
20901cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
20911cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
20921cf9b237SStefano Zampini   }
209348a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
20941cf9b237SStefano Zampini   *B = Bt;
20953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20961cf9b237SStefano Zampini }
20971cf9b237SStefano Zampini 
2098d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv)
2099d71ae5a4SJacob Faibussowitsch {
2100c80a6c00SStefano Zampini   Mat                    B = NULL;
2101c80a6c00SStefano Zampini   DM                     dm;
21024f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
21034f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
21044f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2105c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
21064f1b2e48SStefano Zampini   PetscInt               i, n;
21074f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2108c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
21094f1b2e48SStefano Zampini 
21104f1b2e48SStefano Zampini   PetscFunctionBegin;
2111a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2112a2eca866SStefano Zampini   if (cc) *cc = NULL;
2113a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
21149566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
21159566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
211648a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
211748a46eb9SPierre Jolivet   if (dm) PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isplex));
21188361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
21198361f951SStefano Zampini 
2120c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2121c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2122c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2123c80a6c00SStefano Zampini     IS              cellNumbering;
2124c80a6c00SStefano Zampini     const PetscInt *cellNum;
2125c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2126c80a6c00SStefano Zampini     PetscSection    section;
2127c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2128c80a6c00SStefano Zampini     PetscSF         sfPoint;
2129c80a6c00SStefano Zampini 
21309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
21319566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
21329566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2133c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
21349566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
21359566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
21369566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2137c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
21389566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
21399566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
21409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
21419566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2142c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2143c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
21449371c9d4SSatish Balay       if (nroots > 0) {
21459371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21469371c9d4SSatish Balay       }
2147c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
21489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2149c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2150c80a6c00SStefano Zampini         const PetscInt point = adj[a];
21515cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2152c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
21539566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
21549566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2155c80a6c00SStefano Zampini           *pBuf = point;
2156c80a6c00SStefano Zampini         }
2157c80a6c00SStefano Zampini       }
2158c80a6c00SStefano Zampini       n++;
2159c80a6c00SStefano Zampini     }
21609566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2161c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
21629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
21639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
21649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2165c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
21669371c9d4SSatish Balay       if (nroots > 0) {
21679371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
21689371c9d4SSatish Balay       }
21699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &(xadj[idx++])));
2170c80a6c00SStefano Zampini     }
2171c80a6c00SStefano Zampini     xadj[n] = size;
21729566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2173c80a6c00SStefano Zampini     /* Clean up */
21749566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
21759566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
21769566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2177c80a6c00SStefano Zampini     graph->xadj   = xadj;
2178c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2179c80a6c00SStefano Zampini   } else {
2180c80a6c00SStefano Zampini     Mat       A;
21818361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2182c80a6c00SStefano Zampini 
21839566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
218463c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
21859566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
21863ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
218763c961adSStefano Zampini     }
21889566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
21894f1b2e48SStefano Zampini     if (!isseqaij && filter) {
21901cf9b237SStefano Zampini       PetscBool isseqdense;
21911cf9b237SStefano Zampini 
21929566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
21931cf9b237SStefano Zampini       if (!isseqdense) {
21949566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
21951cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
21961cf9b237SStefano Zampini         PetscScalar *array;
21971cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
21981cf9b237SStefano Zampini 
21999566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
22009566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
22019566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
22021cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
22031cf9b237SStefano Zampini           PetscInt j;
22041cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
22051cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
22061cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
22071cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
22081cf9b237SStefano Zampini           }
22091cf9b237SStefano Zampini         }
22109566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
22119566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
22121cf9b237SStefano Zampini       }
22134f1b2e48SStefano Zampini     } else {
22149566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
22154f1b2e48SStefano Zampini       B = A;
22164f1b2e48SStefano Zampini     }
22179566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22184f1b2e48SStefano Zampini 
22194f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
22204f1b2e48SStefano Zampini     if (filter) {
22214f1b2e48SStefano Zampini       PetscScalar *data;
22224f1b2e48SStefano Zampini       PetscInt     j, cum;
22234f1b2e48SStefano Zampini 
22249566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
22259566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
22264f1b2e48SStefano Zampini       cum = 0;
22274f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
22284f1b2e48SStefano Zampini         PetscInt t;
22294f1b2e48SStefano Zampini 
22304f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
2231ad540459SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) continue;
22324f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
22334f1b2e48SStefano Zampini         }
22344f1b2e48SStefano Zampini         t                = xadj_filtered[i];
22354f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
22364f1b2e48SStefano Zampini         cum += t;
22374f1b2e48SStefano Zampini       }
22389566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
22394f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
22404f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
22414f1b2e48SStefano Zampini     } else {
22424f1b2e48SStefano Zampini       graph->xadj   = xadj;
22434f1b2e48SStefano Zampini       graph->adjncy = adjncy;
22444f1b2e48SStefano Zampini     }
2245c80a6c00SStefano Zampini   }
2246c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
22479566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
22489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
22499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
22509566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_MAX_INT));
22519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
22529566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
22539566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2254c80a6c00SStefano Zampini 
22554f1b2e48SStefano Zampini   /* partial clean up */
22569566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2257c80a6c00SStefano Zampini   if (B) {
2258c80a6c00SStefano Zampini     PetscBool flg_row;
22599566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
22609566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
22614f1b2e48SStefano Zampini   }
2262c80a6c00SStefano Zampini   if (isplex) {
22639566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
22649566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2265c80a6c00SStefano Zampini   }
22664f1b2e48SStefano Zampini 
22674f1b2e48SStefano Zampini   /* get back data */
2268c80a6c00SStefano Zampini   if (isplex) {
2269c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2270c80a6c00SStefano Zampini     if (cc || primalv) {
2271c80a6c00SStefano Zampini       Mat          A;
2272c80a6c00SStefano Zampini       PetscBT      btv, btvt;
2273c80a6c00SStefano Zampini       PetscSection subSection;
2274c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2275c80a6c00SStefano Zampini 
22769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
22779566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
22789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
22799566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
22809566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2281c80a6c00SStefano Zampini 
2282c80a6c00SStefano Zampini       cids[0] = 0;
2283c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2284c80a6c00SStefano Zampini         PetscInt j;
2285c80a6c00SStefano Zampini 
22869566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2287c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2288c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2289c80a6c00SStefano Zampini 
22909566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2291c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
229220c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2293c80a6c00SStefano Zampini 
22949566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
22959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
22969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2297c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2298c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2299e432b41dSStefano Zampini               if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2300e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2301c80a6c00SStefano Zampini             }
23029566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
230320c3699dSStefano Zampini             if (pp != p) {
23049566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
23059566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
23069566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
230720c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
230820c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2309e432b41dSStefano Zampini                 if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2310e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
231120c3699dSStefano Zampini               }
231220c3699dSStefano Zampini             }
2313c80a6c00SStefano Zampini           }
23149566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2315c80a6c00SStefano Zampini         }
2316c80a6c00SStefano Zampini         cids[i + 1] = cum;
2317c80a6c00SStefano Zampini         /* mark dofs as already assigned */
231848a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2319c80a6c00SStefano Zampini       }
2320c80a6c00SStefano Zampini       if (cc) {
23219566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
232248a46eb9SPierre 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]));
2323c80a6c00SStefano Zampini         *cc = cc_n;
2324c80a6c00SStefano Zampini       }
23251baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
23269566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
23279566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
23289566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2329c80a6c00SStefano Zampini     }
2330c80a6c00SStefano Zampini   } else {
23311cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
23321cf9b237SStefano Zampini     if (cc) {
23339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
233448a46eb9SPierre 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]));
23354f1b2e48SStefano Zampini       *cc = cc_n;
23361cf9b237SStefano Zampini     }
2337c80a6c00SStefano Zampini   }
23384f1b2e48SStefano Zampini   /* clean up graph */
23390a545947SLisandro Dalcin   graph->xadj   = NULL;
23400a545947SLisandro Dalcin   graph->adjncy = NULL;
23419566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
23423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23434f1b2e48SStefano Zampini }
23444f1b2e48SStefano Zampini 
2345d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2346d71ae5a4SJacob Faibussowitsch {
23475408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
23485408967cSStefano Zampini   PC_IS   *pcis   = (PC_IS *)(pc->data);
2349dee84bffSStefano Zampini   IS       dirIS  = NULL;
23504f1b2e48SStefano Zampini   PetscInt i;
23515408967cSStefano Zampini 
23525408967cSStefano Zampini   PetscFunctionBegin;
23539566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
23545408967cSStefano Zampini   if (zerodiag) {
23555408967cSStefano Zampini     Mat             A;
23565408967cSStefano Zampini     Vec             vec3_N;
23575408967cSStefano Zampini     PetscScalar    *vals;
23585408967cSStefano Zampini     const PetscInt *idxs;
2359d12d3064SStefano Zampini     PetscInt        nz, *count;
23605408967cSStefano Zampini 
23615408967cSStefano Zampini     /* p0 */
23629566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
23639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
23649566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
23659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
23664f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
23679566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
23689566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
23699566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
23705408967cSStefano Zampini     /* v_I */
23719566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
23725408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
23739566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
23749566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
23759566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
23765408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
23779566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
23789566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
23795408967cSStefano Zampini     if (dirIS) {
23805408967cSStefano Zampini       PetscInt n;
23815408967cSStefano Zampini 
23829566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
23839566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
23845408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
23859566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
23869566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
23875408967cSStefano Zampini     }
23889566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
23899566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
23909566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
23919566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
23929566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
23939566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
23949566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
23957827d75bSBarry 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]));
23969566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
23979566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2398d12d3064SStefano Zampini 
2399d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
24009566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
24019566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2402d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
24039566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
24049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
240563a3b9bcSJacob 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]);
24069566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
24079566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
24085408967cSStefano Zampini   }
24099566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
24105408967cSStefano Zampini 
24115408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
24129566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
24134f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
24149566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
24154f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
24169566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2417f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2418f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
241963a3b9bcSJacob 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));
2420f2a566d8SStefano Zampini   }
24213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24225408967cSStefano Zampini }
24235408967cSStefano Zampini 
2424d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal)
2425d71ae5a4SJacob Faibussowitsch {
2426339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2427e432b41dSStefano Zampini   Mat_IS   *matis     = (Mat_IS *)(pc->pmat->data);
24283b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
24293b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
24304edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
24314edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2432339f8db1SStefano Zampini 
2433339f8db1SStefano Zampini   PetscFunctionBegin;
24343b03f7bbSStefano Zampini   if (reuse) goto project_b0;
24359566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
24369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
243748a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
24389566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
24393b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
24403b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
24413b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
24423b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
24434f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
24444f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
24451ae86dd6SStefano Zampini      since the local Schur complements are already SPD
24464f1b2e48SStefano Zampini   */
244740fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
24487fbe2174Sstefano_zampini     IS        iP = NULL;
24493b03f7bbSStefano Zampini     PetscInt  p, *pp;
24503b03f7bbSStefano Zampini     PetscBool flg;
24514f1b2e48SStefano Zampini 
24529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
24533b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2454d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
24559566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
2456d0609cedSBarry Smith     PetscOptionsEnd();
24573b03f7bbSStefano Zampini     if (!flg) {
24583b03f7bbSStefano Zampini       n     = 1;
24593b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
24603b03f7bbSStefano Zampini     }
24613b03f7bbSStefano Zampini 
24623b03f7bbSStefano Zampini     bsp = 0;
24633b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
24643b03f7bbSStefano Zampini       PetscInt bs;
24653b03f7bbSStefano Zampini 
246663a3b9bcSJacob 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]);
24679566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
24683b03f7bbSStefano Zampini       bsp += bs;
24693b03f7bbSStefano Zampini     }
24709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
24713b03f7bbSStefano Zampini     bsp = 0;
24723b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
24733b03f7bbSStefano Zampini       const PetscInt *idxs;
24743b03f7bbSStefano Zampini       PetscInt        b, bs, npl, *bidxs;
24753b03f7bbSStefano Zampini 
24769566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
24779566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
24789566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
24799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
24803b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
24813b03f7bbSStefano Zampini         PetscInt i;
24823b03f7bbSStefano Zampini 
24833b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
24849566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
24853b03f7bbSStefano Zampini         bsp++;
24863b03f7bbSStefano Zampini       }
24879566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
24889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
24893b03f7bbSStefano Zampini     }
24909566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
24913b03f7bbSStefano Zampini 
24927fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
24939566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
24947fbe2174Sstefano_zampini     if (iP) {
24957fbe2174Sstefano_zampini       IS newpressures;
24967fbe2174Sstefano_zampini 
24979566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
24989566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
24997fbe2174Sstefano_zampini       pressures = newpressures;
25007fbe2174Sstefano_zampini     }
25019566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
250248a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
25039566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
250440fa8d13SStefano Zampini   }
25053b03f7bbSStefano Zampini 
250697d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
25079566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
250827b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
25099566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
25109566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
251148a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
25129566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
25134edc6404Sstefano_zampini   zerodiag_save = zerodiag;
25149566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
25154f1b2e48SStefano Zampini   if (!nz) {
25164f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
25174f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
25189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
251940fa8d13SStefano Zampini   }
25204f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
25213b03f7bbSStefano Zampini 
25224f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
25234f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
25243b03f7bbSStefano Zampini   benign_n        = 0;
25251f4df5f7SStefano Zampini   n_interior_dofs = 0;
25261f4df5f7SStefano Zampini   interior_dofs   = NULL;
25274edc6404Sstefano_zampini   nneu            = 0;
252848a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
25293369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
25304edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
25311f4df5f7SStefano Zampini     PetscInt  n, i, j;
25321f4df5f7SStefano Zampini     PetscInt  n_neigh, *neigh, *n_shared, **shared;
25331f4df5f7SStefano Zampini     PetscInt *iwork;
25341f4df5f7SStefano Zampini 
25359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &n));
25369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
25379566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &iwork));
25389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
253990648384SStefano Zampini     for (i = 1; i < n_neigh; i++)
25409371c9d4SSatish Balay       for (j = 0; j < n_shared[i]; j++) iwork[shared[i][j]] += 1;
25411f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
25429371c9d4SSatish Balay       if (!iwork[i]) interior_dofs[n_interior_dofs++] = i;
25439566063dSJacob Faibussowitsch     PetscCall(PetscFree(iwork));
25449566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(matis->rmapping, &n_neigh, &neigh, &n_shared, &shared));
25451f4df5f7SStefano Zampini   }
25464f1b2e48SStefano Zampini   if (has_null_pressures) {
25474f1b2e48SStefano Zampini     IS             *subs;
25484edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
25491f4df5f7SStefano Zampini     const PetscInt *idxs;
25501f4df5f7SStefano Zampini     PetscScalar    *array;
25511f4df5f7SStefano Zampini     Vec            *work;
25524f1b2e48SStefano Zampini 
25534f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
25544f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
25551f4df5f7SStefano 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) */
25564edc6404Sstefano_zampini     if (checkb) {
25579566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
25589566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
25599566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
25601f4df5f7SStefano Zampini       /* work[0] = 1_p */
25619566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
25629566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
25631f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
25649566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
25651f4df5f7SStefano Zampini       /* work[0] = 1_v */
25669566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
25679566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
25681f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
25699566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
25709566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
25711f4df5f7SStefano Zampini     }
25723b03f7bbSStefano Zampini 
25733b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
25743b03f7bbSStefano Zampini       IS      *is;
25753b03f7bbSStefano Zampini       PetscInt b, totb;
25763b03f7bbSStefano Zampini 
25773b03f7bbSStefano Zampini       totb  = bsp;
25783b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
25793b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
25809566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
25813b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
25824f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
25834f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
25844f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
25854f1b2e48SStefano Zampini           PetscInt               nl;
25864f1b2e48SStefano Zampini 
25873b03f7bbSStefano Zampini           if (subs) {
25889566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
25893b03f7bbSStefano Zampini           } else {
25903b03f7bbSStefano Zampini             IS tis;
25913b03f7bbSStefano Zampini 
25929566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
25939566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
25949566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
25959566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
25963b03f7bbSStefano Zampini           }
25979566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
25989566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
25994f1b2e48SStefano Zampini           if (nl) {
26004f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
26014f1b2e48SStefano Zampini 
26024edc6404Sstefano_zampini             if (checkb) {
26039566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
26049566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
26059566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
26069566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
26071f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
26089566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
26099566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
26109566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
26119566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
26129566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
26139566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
26141f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
26151f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
26161f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
26171f4df5f7SStefano Zampini                   break;
26181f4df5f7SStefano Zampini                 }
26191f4df5f7SStefano Zampini               }
26209566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
26211f4df5f7SStefano Zampini             }
26226632bad2Sstefano_zampini             if (valid && nneu) {
26236632bad2Sstefano_zampini               const PetscInt *idxs;
26241f4df5f7SStefano Zampini               PetscInt        nzb;
26251f4df5f7SStefano Zampini 
26269566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26279566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
26289566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
26291f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
26301f4df5f7SStefano Zampini             }
26311f4df5f7SStefano Zampini             if (valid && pressures) {
26323b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
26333b03f7bbSStefano Zampini               PetscInt i1, i2;
26343b03f7bbSStefano Zampini 
26359566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
26369566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
26379566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
26389566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
26393b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
26409566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
26419566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
26424f1b2e48SStefano Zampini             }
26434f1b2e48SStefano Zampini             if (valid) {
26449566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
26453b03f7bbSStefano Zampini               benign_n++;
26463b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
26474f1b2e48SStefano Zampini           }
26489566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
26499566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
26504f1b2e48SStefano Zampini         }
26513b03f7bbSStefano Zampini       }
26524f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
26534f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
26541f4df5f7SStefano Zampini 
26556632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
265648a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
26574edc6404Sstefano_zampini       if (valid && checkb) {
26589566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
26599566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
26609566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
26611f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
26621f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
26631f4df5f7SStefano Zampini             valid = PETSC_FALSE;
26641f4df5f7SStefano Zampini             break;
26651f4df5f7SStefano Zampini           }
26661f4df5f7SStefano Zampini         }
26679566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
26681f4df5f7SStefano Zampini       }
26694f1b2e48SStefano Zampini       if (valid) {
26703b03f7bbSStefano Zampini         benign_n = 1;
26719566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
26729566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
26734f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
26744f1b2e48SStefano Zampini       }
26754f1b2e48SStefano Zampini     }
267648a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
26771f4df5f7SStefano Zampini   }
26789566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
26794f1b2e48SStefano Zampini 
26803b03f7bbSStefano Zampini   if (!benign_n) {
2681b9b0e38cSStefano Zampini     PetscInt n;
2682b9b0e38cSStefano Zampini 
26839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
26844f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
26859566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
268676a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
2687b9b0e38cSStefano Zampini   }
26884f1b2e48SStefano Zampini 
26894f1b2e48SStefano Zampini   /* final check for null pressures */
269048a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
26914f1b2e48SStefano Zampini 
26924f1b2e48SStefano Zampini   if (recompute_zerodiag) {
26939566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
26943b03f7bbSStefano Zampini     if (benign_n == 1) {
26959566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
26964f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
26974f1b2e48SStefano Zampini     } else {
26984f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
26994f1b2e48SStefano Zampini 
27004f1b2e48SStefano Zampini       nzn = 0;
27013b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
27024f1b2e48SStefano Zampini         PetscInt ns;
27039566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
27044f1b2e48SStefano Zampini         nzn += ns;
27054f1b2e48SStefano Zampini       }
27069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
27074f1b2e48SStefano Zampini       nzn = 0;
27083b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
27094f1b2e48SStefano Zampini         PetscInt ns, *idxs;
27109566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
27119566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
27129566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
27139566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
27144f1b2e48SStefano Zampini         nzn += ns;
27154f1b2e48SStefano Zampini       }
27169566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
27179566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
27184f1b2e48SStefano Zampini     }
27194f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
27204f1b2e48SStefano Zampini   }
27214f1b2e48SStefano Zampini 
27223b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
27231c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
27243b03f7bbSStefano Zampini 
2725669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
2726a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2727a198735bSStefano Zampini     Mat                    A, loc_divudotp;
2728a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
2729a198735bSStefano Zampini     IS                     row, col, isused = NULL;
2730a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
2731a198735bSStefano Zampini 
27321f4df5f7SStefano Zampini     if (pressures) {
27331f4df5f7SStefano Zampini       isused = pressures;
27341f4df5f7SStefano Zampini     } else {
27354edc6404Sstefano_zampini       isused = zerodiag_save;
27361f4df5f7SStefano Zampini     }
27379566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
27389566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
27399566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
27407827d75bSBarry 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");
2741a198735bSStefano Zampini     n_isused = 0;
274248a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
27439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
2744a198735bSStefano Zampini     st = st - n_isused;
27451ae86dd6SStefano Zampini     if (n) {
2746a198735bSStefano Zampini       const PetscInt *gidxs;
2747a198735bSStefano Zampini 
27489566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
27499566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
2750a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
27519566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
27529566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
27539566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
27541ae86dd6SStefano Zampini     } else {
27559566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
27569566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
27579566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
2758a198735bSStefano Zampini     }
27599566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
27609566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
27619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
27629566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
27639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
27649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
27659566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
27669566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
27679566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
27689566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
27699566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27709566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
27719566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
27729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
27739566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
27749566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
27751ae86dd6SStefano Zampini   }
27769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
27779566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
27783b03f7bbSStefano Zampini   if (bzerodiag) {
27793b03f7bbSStefano Zampini     PetscInt i;
2780b3afcdbeSStefano Zampini 
278148a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
27829566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
27833b03f7bbSStefano Zampini   }
27843b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
27853b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
27863b03f7bbSStefano Zampini 
27873b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
27883b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
27891c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
27903b03f7bbSStefano Zampini 
27913b03f7bbSStefano Zampini project_b0:
27929566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
2793b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
27943b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
27954f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
27964f1b2e48SStefano Zampini 
2797339f8db1SStefano Zampini     /* local change of basis for pressures */
27989566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
27999566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
28009566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
28019566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
28029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
2803aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
28044f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
2805aa0d93e9SStefano Zampini       const PetscInt *idxs;
28064f1b2e48SStefano Zampini       PetscInt        nzs, j;
28074f1b2e48SStefano Zampini 
28089566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
28099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
28104f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
28114f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
28129566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
28134f1b2e48SStefano Zampini     }
28149566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
28159566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
28169566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
2817aa0d93e9SStefano Zampini     /* set identity by default */
281848a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
28199566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
28209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
2821339f8db1SStefano Zampini     /* set change on pressures */
28224f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
28234f1b2e48SStefano Zampini       PetscScalar    *array;
2824aa0d93e9SStefano Zampini       const PetscInt *idxs;
28254f1b2e48SStefano Zampini       PetscInt        nzs;
28264f1b2e48SStefano Zampini 
28279566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
28289566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
28294f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
2830339f8db1SStefano Zampini         PetscScalar vals[2];
2831339f8db1SStefano Zampini         PetscInt    cols[2];
2832339f8db1SStefano Zampini 
2833339f8db1SStefano Zampini         cols[0] = idxs[i];
28344f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
2835339f8db1SStefano Zampini         vals[0] = 1.;
2836b0f5fe93SStefano Zampini         vals[1] = 1.;
28379566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
2838339f8db1SStefano Zampini       }
28399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
28404f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
28414f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
28429566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
28434f1b2e48SStefano Zampini       /* store local idxs for p0 */
28444f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
28459566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
28469566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
28474f1b2e48SStefano Zampini     }
28489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
28499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
28503b03f7bbSStefano Zampini 
2851a3df083aSStefano Zampini     /* project if needed */
2852a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
28531dd7afcfSStefano Zampini       Mat M;
28541dd7afcfSStefano Zampini 
28559566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
28569566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
28579566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
28589566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
2859a3df083aSStefano Zampini     }
28604f1b2e48SStefano Zampini     /* store global idxs for p0 */
28619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
2862339f8db1SStefano Zampini   }
2863339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
28643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2865339f8db1SStefano Zampini }
2866339f8db1SStefano Zampini 
2867d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
2868d71ae5a4SJacob Faibussowitsch {
2869efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
2870de9d7bd0SStefano Zampini   PetscScalar *array;
2871efc2fbd9SStefano Zampini 
2872efc2fbd9SStefano Zampini   PetscFunctionBegin;
2873efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
28749566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
28759566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
2876efc2fbd9SStefano Zampini   }
2877de9d7bd0SStefano Zampini   if (get) {
28789566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
28799566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
28809566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
28819566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
2882de9d7bd0SStefano Zampini   } else {
28839566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
28849566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
28859566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
28869566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
2887efc2fbd9SStefano Zampini   }
28883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2889efc2fbd9SStefano Zampini }
2890efc2fbd9SStefano Zampini 
2891d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
2892d71ae5a4SJacob Faibussowitsch {
2893c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2894c263805aSStefano Zampini 
2895c263805aSStefano Zampini   PetscFunctionBegin;
2896c263805aSStefano Zampini   /* TODO: add error checking
2897c263805aSStefano Zampini     - avoid nested pop (or push) calls.
2898c263805aSStefano Zampini     - cannot push before pop.
28991c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
2900c263805aSStefano Zampini   */
29013ba16761SJacob Faibussowitsch   if (!pcbddc->benign_n) PetscFunctionReturn(PETSC_SUCCESS);
2902c263805aSStefano Zampini   if (pop) {
2903a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
29044f1b2e48SStefano Zampini       IS       is_p0;
29054f1b2e48SStefano Zampini       MatReuse reuse;
2906c263805aSStefano Zampini 
2907c263805aSStefano Zampini       /* extract B_0 */
29084f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
2909ad540459SPierre Jolivet       if (pcbddc->benign_B0) reuse = MAT_REUSE_MATRIX;
29109566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
29119566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
2912c263805aSStefano Zampini       /* remove rows and cols from local problem */
29139566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
29149566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
29159566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
29169566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
2917a3df083aSStefano Zampini     } else {
2918a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
2919a3df083aSStefano Zampini       PetscScalar *vals;
2920a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
2921a3df083aSStefano Zampini 
29229566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
29239566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
2924a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
29250b5adadeSStefano Zampini         PetscInt *nnz;
29269566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
29279566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
29289566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
29299566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
2930331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
29319566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
2932331e053bSStefano Zampini           nnz[i] = n - nnz[i];
2933331e053bSStefano Zampini         }
29349566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
29359566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
29369566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
2937331e053bSStefano Zampini       }
2938a3df083aSStefano Zampini 
2939a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
2940a3df083aSStefano Zampini         PetscScalar *array;
2941a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
2942a3df083aSStefano Zampini 
29439566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
29449566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
29459566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
2946a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
29479566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
29489566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
29499566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
29509566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
29519566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
29529566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
2953a3df083aSStefano Zampini         cum = 0;
2954a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
295522db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
2956a3df083aSStefano Zampini             vals[cum]     = array[j];
2957a3df083aSStefano Zampini             idxs_ins[cum] = j;
2958a3df083aSStefano Zampini             cum++;
2959a3df083aSStefano Zampini           }
2960a3df083aSStefano Zampini         }
29619566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
29629566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
29639566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
2964a3df083aSStefano Zampini       }
29659566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
29669566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
29679566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
2968a3df083aSStefano Zampini     }
2969c263805aSStefano Zampini   } else { /* push */
29704f1b2e48SStefano Zampini 
29710fdf79fbSJacob Faibussowitsch     PetscCheck(pcbddc->benign_change_explicit, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
29720fdf79fbSJacob Faibussowitsch     for (PetscInt i = 0; i < pcbddc->benign_n; i++) {
29734f1b2e48SStefano Zampini       PetscScalar *B0_vals;
29744f1b2e48SStefano Zampini       PetscInt    *B0_cols, B0_ncol;
29754f1b2e48SStefano Zampini 
29769566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
29779566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
29789566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
29799566063dSJacob Faibussowitsch       PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
29809566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
29814f1b2e48SStefano Zampini     }
29829566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
29839566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
2984c263805aSStefano Zampini   }
29853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2986c263805aSStefano Zampini }
2987c263805aSStefano Zampini 
2988d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
2989d71ae5a4SJacob Faibussowitsch {
2990b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
299108122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
299208122e43SStefano Zampini   PetscBLASInt    B_dummyint, B_neigs, B_ierr, B_lwork;
299308122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
299408122e43SStefano Zampini   PetscScalar    *work, lwork;
299508122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
299608122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
2997bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
29981b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
299932fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
300008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
300108122e43SStefano Zampini   PetscReal *rwork;
300208122e43SStefano Zampini #endif
3003b1b3d7a2SStefano Zampini 
3004b1b3d7a2SStefano Zampini   PetscFunctionBegin;
30053ba16761SJacob Faibussowitsch   if (!pcbddc->adaptive_selection) PetscFunctionReturn(PETSC_SUCCESS);
300628b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
300732fe681dSStefano 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");
30089371c9d4SSatish 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,
30099371c9d4SSatish Balay              sub_schurs->is_posdef);
30109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
301106a4e24aSStefano Zampini 
3012fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
301332fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
30149566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
30159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
30169566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
30179566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
3018fd14bc51SStefano Zampini   }
3019fd14bc51SStefano Zampini 
302048a46eb9SPierre 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));
3021e496cd5dSStefano Zampini 
302208122e43SStefano Zampini   /* max size of subsets */
302308122e43SStefano Zampini   mss = 0;
302408122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
302508122e43SStefano Zampini     PetscInt subset_size;
3026862806e4SStefano Zampini 
30279566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
302808122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
302908122e43SStefano Zampini   }
303008122e43SStefano Zampini 
303108122e43SStefano Zampini   /* min/max and threshold */
303208122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3033f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
303408122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3035f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3036bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3037f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3038f6f667cfSStefano Zampini   }
303908122e43SStefano Zampini 
304008122e43SStefano Zampini   /* allocate lapack workspace */
304108122e43SStefano Zampini   cum = cum2 = 0;
304208122e43SStefano Zampini   maxneigs   = 0;
304308122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
304408122e43SStefano Zampini     PetscInt n, subset_size;
3045f6f667cfSStefano Zampini 
30469566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
304708122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
30489162d606SStefano Zampini     cum += subset_size;
30499162d606SStefano Zampini     cum2 += subset_size * n;
305008122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
305108122e43SStefano Zampini   }
30527ebab0bbSStefano Zampini   lwork = 0;
305308122e43SStefano Zampini   if (mss) {
30547ebab0bbSStefano Zampini     PetscScalar  sdummy  = 0.;
305508122e43SStefano Zampini     PetscBLASInt B_itype = 1;
30567ebab0bbSStefano Zampini     PetscBLASInt B_N = mss, idummy = 0;
30577ebab0bbSStefano Zampini     PetscReal    rdummy = 0., zero = 0.0;
30584c6709b3SStefano Zampini     PetscReal    eps = 0.0; /* dlamch? */
305908122e43SStefano Zampini 
30600fdf79fbSJacob Faibussowitsch     PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
306108122e43SStefano Zampini     B_lwork = -1;
30627ebab0bbSStefano Zampini     /* some implementations may complain about NULL pointers, even if we are querying */
30637ebab0bbSStefano Zampini     S       = &sdummy;
30647ebab0bbSStefano Zampini     St      = &sdummy;
30657ebab0bbSStefano Zampini     eigs    = &rdummy;
30667ebab0bbSStefano Zampini     eigv    = &sdummy;
30677ebab0bbSStefano Zampini     B_iwork = &idummy;
30687ebab0bbSStefano Zampini     B_ifail = &idummy;
3069d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
30707ebab0bbSStefano Zampini     rwork = &rdummy;
3071d1710679SStefano Zampini #endif
30728bec7fa6SStefano Zampini     thresh = 1.0;
30739566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
307408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3075792fecdfSBarry 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));
307608122e43SStefano Zampini #else
3077792fecdfSBarry 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));
307808122e43SStefano Zampini #endif
307908401ef6SPierre Jolivet     PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %d", (int)B_ierr);
30809566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
308108122e43SStefano Zampini   }
308208122e43SStefano Zampini 
308308122e43SStefano Zampini   nv = 0;
3084d62866d3SStefano 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) */
30859566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
308608122e43SStefano Zampini   }
30879566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
308848a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
30899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
309008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
30919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
309208122e43SStefano Zampini #endif
30939371c9d4SSatish 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,
30949371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
30959566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
309608122e43SStefano Zampini 
309708122e43SStefano Zampini   maxneigs = 0;
309872b8c272SStefano Zampini   cum = cumarray                           = 0;
30999162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
31009162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3101d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
310208122e43SStefano Zampini     const PetscInt *idxs;
310308122e43SStefano Zampini 
31049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
310508122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
310608122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
310708122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
310808122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
31099162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
31109162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
311108122e43SStefano Zampini     }
31129566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
311308122e43SStefano Zampini   }
311408122e43SStefano Zampini 
311508122e43SStefano Zampini   if (mss) { /* multilevel */
311632fe681dSStefano Zampini     if (sub_schurs->gdsw) {
311732fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
311832fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
311932fe681dSStefano Zampini     } else {
31209566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
31219566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
312208122e43SStefano Zampini     }
312332fe681dSStefano Zampini   }
312408122e43SStefano Zampini 
3125bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3126bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
312732fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
312808122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
312908122e43SStefano Zampini     const PetscInt *idxs;
31309d54b7f4SStefano Zampini     PetscReal       upper, lower;
3131862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
313208122e43SStefano Zampini     PetscBLASInt    B_N;
3133aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3134bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
313508122e43SStefano Zampini 
313632fe681dSStefano Zampini     if (upart) {
31379d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3138bd2a564bSStefano Zampini       lower = uthresh;
31399d54b7f4SStefano Zampini     } else {
314032fe681dSStefano Zampini       if (sub_schurs->gdsw) {
314132fe681dSStefano Zampini         upper = uthresh;
314232fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
314332fe681dSStefano Zampini       } else {
314428b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3145bd2a564bSStefano Zampini         upper = 1. / uthresh;
31469d54b7f4SStefano Zampini         lower = 0.;
31479d54b7f4SStefano Zampini       }
314832fe681dSStefano Zampini     }
31499566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
31509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
31519566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3152bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3153bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3154bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3155bd2a564bSStefano Zampini       Mat T;
3156bd2a564bSStefano Zampini 
3157bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3158bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
31599566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
31609566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
31619566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
31629566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
31639566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
31649566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3165bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3166bd2a564bSStefano Zampini             PetscInt        nz, k;
3167bd2a564bSStefano Zampini             const PetscInt *idxs;
3168bd2a564bSStefano Zampini 
31699566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
31709566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3171bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3172bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3173bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3174bd2a564bSStefano Zampini             }
31759566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3176bd2a564bSStefano Zampini           }
3177bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3178bd2a564bSStefano Zampini           break;
3179bd2a564bSStefano Zampini         }
3180bd2a564bSStefano Zampini       }
3181bd2a564bSStefano Zampini     }
3182bd2a564bSStefano Zampini 
3183f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3184bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3185aff50787SStefano Zampini         PetscInt j, k;
3186580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
31879566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
31889566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
318908122e43SStefano Zampini         }
319008122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3191aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3192aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3193aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3194aff50787SStefano Zampini           }
319508122e43SStefano Zampini         }
319608122e43SStefano Zampini       } else {
31979566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
31989566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
319908122e43SStefano Zampini       }
32008bec7fa6SStefano Zampini     } else {
3201f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3202f6f667cfSStefano Zampini       St = Starray + cumarray;
32038bec7fa6SStefano Zampini     }
3204aff50787SStefano Zampini     /* see if we can save some work */
320548a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3206aff50787SStefano Zampini 
3207b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3208aff50787SStefano Zampini       B_neigs = 0;
3209aff50787SStefano Zampini     } else {
321008122e43SStefano Zampini       PetscBLASInt B_itype = 1;
3211f6f667cfSStefano Zampini       PetscBLASInt B_IL, B_IU;
32124c6709b3SStefano Zampini       PetscReal    eps = -1.0; /* dlamch? */
32139552c7c7SStefano Zampini       PetscInt     nmin_s;
3214bd2a564bSStefano Zampini       PetscBool    compute_range;
3215bd2a564bSStefano Zampini 
32160fdf79fbSJacob Faibussowitsch       PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
32179036ceccSStefano Zampini       B_neigs       = 0;
3218bd2a564bSStefano Zampini       compute_range = (PetscBool)!same_data;
3219bd2a564bSStefano Zampini       if (nmin >= subset_size) compute_range = PETSC_FALSE;
322008122e43SStefano Zampini 
3221fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
32229036ceccSStefano Zampini         PetscInt nc = 0;
3223d16cbb6bSStefano Zampini 
322448a46eb9SPierre Jolivet         if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
32259371c9d4SSatish 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,
32269371c9d4SSatish Balay                                                      sub_schurs->n_subs, subset_size, pcbddc->mat_graph->count[idxs[0]] + 1, pcbddc->mat_graph->which_dof[idxs[0]], compute_range, nc));
3227b7ab4a40SStefano Zampini       }
3228b7ab4a40SStefano Zampini 
32299566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3230b7ab4a40SStefano Zampini       if (compute_range) {
3231d16cbb6bSStefano Zampini         /* ask for eigenvalues larger than thresh */
3232bd2a564bSStefano Zampini         if (sub_schurs->is_posdef) {
323308122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3234792fecdfSBarry 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));
323508122e43SStefano Zampini #else
3236792fecdfSBarry 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));
323708122e43SStefano Zampini #endif
32389566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3239bd2a564bSStefano Zampini         } else { /* no theory so far, but it works nicely */
32409036ceccSStefano Zampini           PetscInt  recipe = 0, recipe_m = 1;
3241bd2a564bSStefano Zampini           PetscReal bb[2];
3242bd2a564bSStefano Zampini 
32439566063dSJacob Faibussowitsch           PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3244bd2a564bSStefano Zampini           switch (recipe) {
3245bd2a564bSStefano Zampini           case 0:
32469371c9d4SSatish Balay             if (scal) {
32479371c9d4SSatish Balay               bb[0] = PETSC_MIN_REAL;
32489371c9d4SSatish Balay               bb[1] = lthresh;
32499371c9d4SSatish Balay             } else {
32509371c9d4SSatish Balay               bb[0] = uthresh;
32519371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
32529371c9d4SSatish Balay             }
3253bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3254792fecdfSBarry 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));
3255bd2a564bSStefano Zampini #else
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_neigs, eigs, eigv, &B_N, work, &B_lwork, B_iwork, B_ifail, &B_ierr));
3257bd2a564bSStefano Zampini #endif
32589566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3259bd2a564bSStefano Zampini             break;
3260d71ae5a4SJacob Faibussowitsch           case 1:
3261d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3262d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh * lthresh;
3263bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3264792fecdfSBarry 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));
3265bd2a564bSStefano Zampini #else
3266792fecdfSBarry 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));
3267bd2a564bSStefano Zampini #endif
32689566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3269bd2a564bSStefano Zampini             if (!scal) {
32709036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
3271bd2a564bSStefano Zampini 
32729371c9d4SSatish Balay               bb[0] = PetscMax(lthresh * lthresh, uthresh);
32739371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
32749566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
32759566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3276bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3277792fecdfSBarry 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));
3278bd2a564bSStefano Zampini #else
3279792fecdfSBarry 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));
3280bd2a564bSStefano Zampini #endif
32819566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3282bd2a564bSStefano Zampini               B_neigs += B_neigs2;
3283bd2a564bSStefano Zampini             }
3284bd2a564bSStefano Zampini             break;
32859036ceccSStefano Zampini           case 2:
32869036ceccSStefano Zampini             if (scal) {
32879036ceccSStefano Zampini               bb[0] = PETSC_MIN_REAL;
32889036ceccSStefano Zampini               bb[1] = 0;
32899036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3290792fecdfSBarry 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));
32919036ceccSStefano Zampini #else
3292792fecdfSBarry 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));
32939036ceccSStefano Zampini #endif
32949566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
32959036ceccSStefano Zampini             } else {
32969036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
329713bcc0bdSJacob Faibussowitsch               PetscBool    do_copy  = PETSC_FALSE;
32989036ceccSStefano Zampini 
32999036ceccSStefano Zampini               lthresh = PetscMax(lthresh, 0.0);
33009036ceccSStefano Zampini               if (lthresh > 0.0) {
33019036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
33029036ceccSStefano Zampini                 bb[1] = lthresh * lthresh;
33039036ceccSStefano Zampini 
330413bcc0bdSJacob Faibussowitsch                 do_copy = PETSC_TRUE;
33059036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3306792fecdfSBarry 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));
33079036ceccSStefano Zampini #else
3308792fecdfSBarry 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));
33099036ceccSStefano Zampini #endif
33109566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33119036ceccSStefano Zampini               }
33129036ceccSStefano Zampini               bb[0] = PetscMax(lthresh * lthresh, uthresh);
33139036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
331413bcc0bdSJacob Faibussowitsch               if (do_copy) {
33159566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33169566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
33179036ceccSStefano Zampini               }
33189036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3319792fecdfSBarry 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));
33209036ceccSStefano Zampini #else
3321792fecdfSBarry 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));
33229036ceccSStefano Zampini #endif
33239566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33249036ceccSStefano Zampini               B_neigs += B_neigs2;
33259036ceccSStefano Zampini             }
33269036ceccSStefano Zampini             break;
33279036ceccSStefano Zampini           case 3:
33289036ceccSStefano Zampini             if (scal) {
33299566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
33309036ceccSStefano Zampini             } else {
33319566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
33329036ceccSStefano Zampini             }
33339036ceccSStefano Zampini             if (!scal) {
33349036ceccSStefano Zampini               bb[0] = uthresh;
33359036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
33369036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3337792fecdfSBarry 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));
33389036ceccSStefano Zampini #else
3339792fecdfSBarry 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));
33409036ceccSStefano Zampini #endif
33419566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33429036ceccSStefano Zampini             }
33439036ceccSStefano Zampini             if (recipe_m > 0 && B_N - B_neigs > 0) {
33449036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
33459036ceccSStefano Zampini 
33469036ceccSStefano Zampini               B_IL = 1;
33479566063dSJacob Faibussowitsch               PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
33489566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33499566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
33509036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3351792fecdfSBarry 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));
33529036ceccSStefano Zampini #else
3353792fecdfSBarry 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));
33549036ceccSStefano Zampini #endif
33559566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
33569036ceccSStefano Zampini               B_neigs += B_neigs2;
33579036ceccSStefano Zampini             }
33589036ceccSStefano Zampini             break;
3359d71ae5a4SJacob Faibussowitsch           case 4:
3360d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3361d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh;
336248cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3363792fecdfSBarry 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));
336448cebe81SStefano Zampini #else
3365792fecdfSBarry 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));
336648cebe81SStefano Zampini #endif
33679566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
336848cebe81SStefano Zampini             {
336948cebe81SStefano Zampini               PetscBLASInt B_neigs2 = 0;
337048cebe81SStefano Zampini 
33719371c9d4SSatish Balay               bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
33729371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
33739566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33749566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
337548cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3376792fecdfSBarry 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));
337748cebe81SStefano Zampini #else
3378792fecdfSBarry 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));
337948cebe81SStefano Zampini #endif
33809566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
338148cebe81SStefano Zampini               B_neigs += B_neigs2;
338248cebe81SStefano Zampini             }
338348cebe81SStefano Zampini             break;
338480db8efeSStefano Zampini           case 5: /* same as before: first compute all eigenvalues, then filter */
338580db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3386792fecdfSBarry 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));
338780db8efeSStefano Zampini #else
3388792fecdfSBarry 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));
338980db8efeSStefano Zampini #endif
33909566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
339180db8efeSStefano Zampini             {
339280db8efeSStefano Zampini               PetscInt e, k, ne;
339380db8efeSStefano Zampini               for (e = 0, ne = 0; e < B_neigs; e++) {
339480db8efeSStefano Zampini                 if (eigs[e] < lthresh || eigs[e] > uthresh) {
339580db8efeSStefano Zampini                   for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
339680db8efeSStefano Zampini                   eigs[ne] = eigs[e];
339780db8efeSStefano Zampini                   ne++;
339880db8efeSStefano Zampini                 }
339980db8efeSStefano Zampini               }
34009566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(eigv, S, B_N * ne));
340180db8efeSStefano Zampini               B_neigs = ne;
340280db8efeSStefano Zampini             }
340380db8efeSStefano Zampini             break;
3404d71ae5a4SJacob Faibussowitsch           default:
3405d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3406bd2a564bSStefano Zampini           }
3407bd2a564bSStefano Zampini         }
3408bd2a564bSStefano Zampini       } else if (!same_data) { /* this is just to see all the eigenvalues */
3409d16cbb6bSStefano Zampini         B_IU = PetscMax(1, PetscMin(B_N, nmax));
3410d16cbb6bSStefano Zampini         B_IL = 1;
3411d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3412792fecdfSBarry 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));
3413d16cbb6bSStefano Zampini #else
3414792fecdfSBarry 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));
3415d16cbb6bSStefano Zampini #endif
34169566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3417b03ebc13SStefano Zampini       } else { /* same_data is true, so just get the adaptive functional requested by the user */
3418b7ab4a40SStefano Zampini         PetscInt k;
341928b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
34209566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
34219566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3422b7ab4a40SStefano Zampini         nmin = nmax;
34239566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3424b7ab4a40SStefano Zampini         for (k = 0; k < nmax; k++) {
3425b7ab4a40SStefano Zampini           eigs[k]                     = 1. / PETSC_SMALL;
3426b7ab4a40SStefano Zampini           eigv[k * (subset_size + 1)] = 1.0;
3427b7ab4a40SStefano Zampini         }
3428d16cbb6bSStefano Zampini       }
34299566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
343008122e43SStefano Zampini       if (B_ierr) {
343163a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
343263a3b9bcSJacob 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);
343363a3b9bcSJacob 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);
343408122e43SStefano Zampini       }
343508122e43SStefano Zampini 
343608122e43SStefano Zampini       if (B_neigs > nmax) {
343748a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
343832fe681dSStefano Zampini         if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
343908122e43SStefano Zampini         B_neigs = nmax;
344008122e43SStefano Zampini       }
344108122e43SStefano Zampini 
34429552c7c7SStefano Zampini       nmin_s = PetscMin(nmin, B_N);
34439552c7c7SStefano Zampini       if (B_neigs < nmin_s) {
34449036ceccSStefano Zampini         PetscBLASInt B_neigs2 = 0;
344508122e43SStefano Zampini 
344632fe681dSStefano Zampini         if (upart) {
3447bd2a564bSStefano Zampini           if (scal) {
3448bd2a564bSStefano Zampini             B_IU = nmin_s;
3449bd2a564bSStefano Zampini             B_IL = B_neigs + 1;
3450bd2a564bSStefano Zampini           } else {
3451f6f667cfSStefano Zampini             B_IL = B_N - nmin_s + 1;
34529d54b7f4SStefano Zampini             B_IU = B_N - B_neigs;
3453bd2a564bSStefano Zampini           }
34549d54b7f4SStefano Zampini         } else {
34559d54b7f4SStefano Zampini           B_IL = B_neigs + 1;
34569d54b7f4SStefano Zampini           B_IU = nmin_s;
34579d54b7f4SStefano Zampini         }
3458fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
345963a3b9bcSJacob 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));
3460fd14bc51SStefano Zampini         }
3461bd2a564bSStefano Zampini         if (sub_schurs->is_symmetric) {
34621ae86dd6SStefano Zampini           PetscInt j, k;
346308122e43SStefano Zampini           for (j = 0; j < subset_size; j++) {
34641ae86dd6SStefano Zampini             for (k = j; k < subset_size; k++) {
34651ae86dd6SStefano Zampini               S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
34661ae86dd6SStefano Zampini               St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
346708122e43SStefano Zampini             }
346808122e43SStefano Zampini           }
346908122e43SStefano Zampini         } else {
34709566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34719566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
347208122e43SStefano Zampini         }
34739566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
347408122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3475792fecdfSBarry 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));
347608122e43SStefano Zampini #else
3477792fecdfSBarry 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));
347808122e43SStefano Zampini #endif
34799566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34809566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
348108122e43SStefano Zampini         B_neigs += B_neigs2;
348208122e43SStefano Zampini       }
348308122e43SStefano Zampini       if (B_ierr) {
348463a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
348563a3b9bcSJacob 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);
348663a3b9bcSJacob 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);
348708122e43SStefano Zampini       }
3488fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
348963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
349008122e43SStefano Zampini         for (j = 0; j < B_neigs; j++) {
349132fe681dSStefano Zampini           if (!sub_schurs->gdsw) {
349208122e43SStefano Zampini             if (eigs[j] == 0.0) {
34939566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
349408122e43SStefano Zampini             } else {
349532fe681dSStefano Zampini               if (upart) {
349663a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
34979d54b7f4SStefano Zampini               } else {
349863a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1. / eigs[j + eigs_start])));
34999d54b7f4SStefano Zampini               }
3500fd14bc51SStefano Zampini             }
350132fe681dSStefano Zampini           } else {
350232fe681dSStefano Zampini             double pg = (double)eigs[j + eigs_start];
350332fe681dSStefano Zampini             if (pg < 2 * PETSC_SMALL) pg = 0.0;
350432fe681dSStefano Zampini             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
350532fe681dSStefano Zampini           }
350608122e43SStefano Zampini         }
350708122e43SStefano Zampini       }
3508aff50787SStefano Zampini     }
35096c3e6151SStefano Zampini     /* change the basis back to the original one */
35106c3e6151SStefano Zampini     if (sub_schurs->change) {
351172b8c272SStefano Zampini       Mat change, phi, phit;
35126c3e6151SStefano Zampini 
351303dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
35146c3e6151SStefano Zampini         PetscInt ii;
35156c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
351663a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
35176c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3518684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3519684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3520684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
352163a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3522684229deSStefano Zampini #else
352363a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3524684229deSStefano Zampini #endif
35256c3e6151SStefano Zampini           }
35266c3e6151SStefano Zampini         }
35276c3e6151SStefano Zampini       }
35289566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
35299566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
35309566063dSJacob Faibussowitsch       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &phi));
35319566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
35329566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
35339566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
35346c3e6151SStefano Zampini     }
35358bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
35368bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
35379162d606SStefano Zampini     if (B_neigs) {
35389566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3539fd14bc51SStefano Zampini 
3540fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
35419552c7c7SStefano Zampini         PetscInt ii;
35429552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
354363a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
35449552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3545ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3546ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3547ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
354863a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3549ac47001eSStefano Zampini #else
355063a3b9bcSJacob 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]])));
3551ac47001eSStefano Zampini #endif
35529552c7c7SStefano Zampini           }
35539552c7c7SStefano Zampini         }
3554fd14bc51SStefano Zampini       }
35559566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
35569162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
35579162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
35589162d606SStefano Zampini       cum++;
355908122e43SStefano Zampini     }
35609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
356108122e43SStefano Zampini     /* shift for next computation */
356208122e43SStefano Zampini     cumarray += subset_size * subset_size;
356308122e43SStefano Zampini   }
35641baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
356508122e43SStefano Zampini 
356608122e43SStefano Zampini   if (mss) {
356732fe681dSStefano Zampini     if (sub_schurs->gdsw) {
356832fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
356932fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
357032fe681dSStefano Zampini     } else {
35719566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
35729566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3573f6f667cfSStefano Zampini       /* destroy matrices (junk) */
35749566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
35759566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
357608122e43SStefano Zampini     }
357732fe681dSStefano Zampini   }
35781baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
35799566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
358008122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
35819566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
358208122e43SStefano Zampini #endif
358308122e43SStefano Zampini   if (pcbddc->dbg_flag) {
35841b968477SStefano Zampini     PetscInt maxneigs_r;
35851c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
358663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
358708122e43SStefano Zampini   }
35889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
35893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
359008122e43SStefano Zampini }
3591b1b3d7a2SStefano Zampini 
3592d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3593d71ae5a4SJacob Faibussowitsch {
35948629588bSStefano Zampini   PetscScalar *coarse_submat_vals;
3595c8587f34SStefano Zampini 
3596c8587f34SStefano Zampini   PetscFunctionBegin;
3597f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
35985e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
35999566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3600c8587f34SStefano Zampini 
3601684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
36020fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
36039566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3604c8587f34SStefano Zampini 
36058629588bSStefano Zampini   /*
36068629588bSStefano Zampini      Setup local correction and local part of coarse basis.
36078629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
36088629588bSStefano Zampini   */
36099566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat_vals));
36108629588bSStefano Zampini 
36118629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
36129566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat_vals));
36138629588bSStefano Zampini 
36148629588bSStefano Zampini   /* free */
36159566063dSJacob Faibussowitsch   PetscCall(PetscFree(coarse_submat_vals));
36163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3617c8587f34SStefano Zampini }
3618c8587f34SStefano Zampini 
3619d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetCustomization(PC pc)
3620d71ae5a4SJacob Faibussowitsch {
3621674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3622674ae819SStefano Zampini 
3623674ae819SStefano Zampini   PetscFunctionBegin;
36249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
36259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
36269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
36279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
36289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
36299566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
36309566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
36319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
36329566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
36339566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
36343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3635674ae819SStefano Zampini }
3636674ae819SStefano Zampini 
3637d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetTopography(PC pc)
3638d71ae5a4SJacob Faibussowitsch {
3639674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
36404f1b2e48SStefano Zampini   PetscInt i;
3641674ae819SStefano Zampini 
3642674ae819SStefano Zampini   PetscFunctionBegin;
36439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
36449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
36459566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
36469566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
36479566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
36489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
36499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
36509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
36519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
36529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
36539566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
365448a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
3655e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
36569566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
36579566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
3658c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
36598af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
36601c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
36613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3662674ae819SStefano Zampini }
3663674ae819SStefano Zampini 
3664d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetSolvers(PC pc)
3665d71ae5a4SJacob Faibussowitsch {
3666674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3667674ae819SStefano Zampini 
3668674ae819SStefano Zampini   PetscFunctionBegin;
36699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
367058da7f69SStefano Zampini   if (pcbddc->coarse_phi_B) {
3671ca92afb2SStefano Zampini     PetscScalar *array;
36729566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &array));
36739566063dSJacob Faibussowitsch     PetscCall(PetscFree(array));
367458da7f69SStefano Zampini   }
36759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
36769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
36779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
36789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
36799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
36809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
36819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
36829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
36839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
36849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
36859566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
36869566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
36879566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
36889566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
36899566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
36909566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
36919566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
36929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
36939566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
36949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
36959566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
36969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
36979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
36989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
36999566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
37009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
37019566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
3702ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
3703ca92afb2SStefano Zampini     PetscInt i;
370448a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
37059566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
3706ca92afb2SStefano Zampini   }
37079566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
37083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3709674ae819SStefano Zampini }
3710674ae819SStefano Zampini 
3711d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
3712d71ae5a4SJacob Faibussowitsch {
37136bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
37146bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
37156bfb1811SStefano Zampini   VecType  impVecType;
37164f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
37176bfb1811SStefano Zampini 
37186bfb1811SStefano Zampini   PetscFunctionBegin;
37194f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3720b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
37219566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
3722e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
3723e7b262bdSStefano Zampini   /* R nodes */
3724e7b262bdSStefano Zampini   old_size = -1;
372548a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
3726e7b262bdSStefano Zampini   if (n_R != old_size) {
37279566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
37289566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
37299566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
37309566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
37319566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
37329566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
3733e7b262bdSStefano Zampini   }
3734e7b262bdSStefano Zampini   /* local primal dofs */
3735e7b262bdSStefano Zampini   old_size = -1;
373648a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
3737e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
37389566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
37399566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
37409566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
37419566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
3742e7b262bdSStefano Zampini   }
3743e7b262bdSStefano Zampini   /* local explicit constraints */
3744e7b262bdSStefano Zampini   old_size = -1;
374548a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
3746e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
37479566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
37489566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
37499566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
37509566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
375183b7ccabSStefano Zampini   }
37523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37536bfb1811SStefano Zampini }
37546bfb1811SStefano Zampini 
3755d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpCorrection(PC pc, PetscScalar **coarse_submat_vals_n)
3756d71ae5a4SJacob Faibussowitsch {
375725084f0cSStefano Zampini   /* pointers to pcis and pcbddc */
375888ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
375988ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
3760d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
376125084f0cSStefano Zampini   /* submatrices of local problem */
376280677318SStefano Zampini   Mat A_RV, A_VR, A_VV, local_auxmat2_R;
376306656605SStefano Zampini   /* submatrices of local coarse problem */
376406656605SStefano Zampini   Mat S_VV, S_CV, S_VC, S_CC;
376525084f0cSStefano Zampini   /* working matrices */
376606656605SStefano Zampini   Mat C_CR;
376725084f0cSStefano Zampini   /* additional working stuff */
376806656605SStefano Zampini   PC           pc_R;
3769c58f9fdbSStefano Zampini   Mat          F, Brhs = NULL;
37705cbda25cSStefano Zampini   Vec          dummy_vec;
37717ebab0bbSStefano Zampini   PetscBool    isLU, isCHOL, need_benign_correction, sparserhs;
377225084f0cSStefano Zampini   PetscScalar *coarse_submat_vals; /* TODO: use a PETSc matrix */
377306656605SStefano Zampini   PetscScalar *work;
377406656605SStefano Zampini   PetscInt    *idx_V_B;
3775ffd830a3SStefano Zampini   PetscInt     lda_rhs, n, n_vertices, n_constraints, *p0_lidx_I;
377606656605SStefano Zampini   PetscInt     i, n_R, n_D, n_B;
377706656605SStefano Zampini   PetscScalar  one = 1.0, m_one = -1.0;
377888ebb749SStefano Zampini 
377988ebb749SStefano Zampini   PetscFunctionBegin;
37807827d75bSBarry 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");
37819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
3782ffd830a3SStefano Zampini 
3783ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
3784b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
37854f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
3786b371cd4fSStefano Zampini   n_B           = pcis->n_B;
3787b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
378888ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
378988ebb749SStefano Zampini 
379088ebb749SStefano Zampini   /* vertices in boundary numbering */
37919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
37929566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
379363a3b9bcSJacob 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);
379488ebb749SStefano Zampini 
379506656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
37969566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pcbddc->local_primal_size * pcbddc->local_primal_size, &coarse_submat_vals));
37979566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_vertices, coarse_submat_vals, &S_VV));
37989566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VV, pcbddc->local_primal_size));
37999566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_vertices, coarse_submat_vals + n_vertices, &S_CV));
38009566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CV, pcbddc->local_primal_size));
38019566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_vertices, n_constraints, coarse_submat_vals + pcbddc->local_primal_size * n_vertices, &S_VC));
38029566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_VC, pcbddc->local_primal_size));
38039566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_constraints, n_constraints, coarse_submat_vals + (pcbddc->local_primal_size + 1) * n_vertices, &S_CC));
38049566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(S_CC, pcbddc->local_primal_size));
380506656605SStefano Zampini 
380606656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
38079566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
38089566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
38099566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
38109566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
3811ffd830a3SStefano Zampini   lda_rhs                = n_R;
3812a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
38137ebab0bbSStefano Zampini   if (isLU || isCHOL) {
38149566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
3815b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
3816df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3817d62866d3SStefano Zampini     MatFactorType      type;
3818d62866d3SStefano Zampini 
3819df4d28bfSStefano Zampini     F = reuse_solver->F;
38209566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
3821d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
38227ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
38239566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
382422db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
38257ebab0bbSStefano Zampini   } else F = NULL;
382606656605SStefano Zampini 
3827c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
3828c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
3829c58f9fdbSStefano Zampini   if (F) {
3830ea799195SBarry Smith     MatSolverType solver;
3831c58f9fdbSStefano Zampini 
38329566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
38339566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
3834c58f9fdbSStefano Zampini   }
3835c58f9fdbSStefano Zampini 
3836ffd830a3SStefano Zampini   /* allocate workspace */
3837ffd830a3SStefano Zampini   n = 0;
3838ad540459SPierre Jolivet   if (n_constraints) n += lda_rhs * n_constraints;
3839ffd830a3SStefano Zampini   if (n_vertices) {
3840ffd830a3SStefano Zampini     n = PetscMax(2 * lda_rhs * n_vertices, n);
3841ffd830a3SStefano Zampini     n = PetscMax((lda_rhs + n_B) * n_vertices, n);
3842ffd830a3SStefano Zampini   }
3843ad540459SPierre Jolivet   if (!pcbddc->symmetric_primal) n = PetscMax(2 * lda_rhs * pcbddc->local_primal_size, n);
38449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &work));
3845ffd830a3SStefano Zampini 
38465cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
38475cbda25cSStefano Zampini   dummy_vec = NULL;
38485cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
38499566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
38509566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
38519566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
38525cbda25cSStefano Zampini   }
38535cbda25cSStefano Zampini 
38549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
38559566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
38567ebab0bbSStefano Zampini 
385788ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
385888ebb749SStefano Zampini   if (n_constraints) {
3859837cedc9SStefano Zampini     Mat M3, C_B;
386006656605SStefano Zampini     IS  is_aux;
386106656605SStefano Zampini 
386225084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
38639566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_aux));
38649566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
38659566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_aux, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
386688ebb749SStefano Zampini 
386780677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
386880677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
3869c58f9fdbSStefano Zampini     if (!sparserhs) {
38709566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(work, lda_rhs * n_constraints));
387188ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
387206656605SStefano Zampini         const PetscScalar *row_cmat_values;
387306656605SStefano Zampini         const PetscInt    *row_cmat_indices;
387406656605SStefano Zampini         PetscInt           size_of_constraint, j;
387588ebb749SStefano Zampini 
38769566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
3877ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) work[row_cmat_indices[j] + i * lda_rhs] = -row_cmat_values[j];
38789566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
387906656605SStefano Zampini       }
38809566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &Brhs));
3881c58f9fdbSStefano Zampini     } else {
3882c58f9fdbSStefano Zampini       Mat tC_CR;
3883c58f9fdbSStefano Zampini 
38849566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
3885c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
3886c58f9fdbSStefano Zampini         PetscScalar *aa;
3887c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
3888c58f9fdbSStefano Zampini         PetscBool    done;
3889c58f9fdbSStefano Zampini 
38909566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
389128b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
38929566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
38939566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
38949566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
389528b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
3896c58f9fdbSStefano Zampini       } else {
38979566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
3898c58f9fdbSStefano Zampini         tC_CR = C_CR;
3899c58f9fdbSStefano Zampini       }
39009566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
39019566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
3902c58f9fdbSStefano Zampini     }
39039566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, NULL, &local_auxmat2_R));
390406656605SStefano Zampini     if (F) {
3905a3df083aSStefano Zampini       if (need_benign_correction) {
3906df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3907a3df083aSStefano Zampini 
390872b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
39099566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
3910a3df083aSStefano Zampini       }
39119566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
3912a3df083aSStefano Zampini       if (need_benign_correction) {
3913a3df083aSStefano Zampini         PetscScalar       *marr;
3914df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
3915a3df083aSStefano Zampini 
39169566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
39175cbda25cSStefano Zampini         if (lda_rhs != n_R) {
39185cbda25cSStefano Zampini           for (i = 0; i < n_constraints; i++) {
39199566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
39209566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
39219566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
39225cbda25cSStefano Zampini           }
39235cbda25cSStefano Zampini         } else {
3924a3df083aSStefano Zampini           for (i = 0; i < n_constraints; i++) {
39259566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
39269566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
39279566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
3928a3df083aSStefano Zampini           }
39295cbda25cSStefano Zampini         }
39309566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
3931a3df083aSStefano Zampini       }
393206656605SStefano Zampini     } else {
393380677318SStefano Zampini       PetscScalar *marr;
393480677318SStefano Zampini 
39359566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
393606656605SStefano Zampini       for (i = 0; i < n_constraints; i++) {
39379566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
39389566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
39399566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
39409566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
39419566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
39429566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
394306656605SStefano Zampini       }
39449566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
394506656605SStefano Zampini     }
39461baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
39479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
394880677318SStefano Zampini     if (!pcbddc->switch_static) {
39499566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_constraints, NULL, &pcbddc->local_auxmat2));
395080677318SStefano Zampini       for (i = 0; i < n_constraints; i++) {
3951ab2d12f3SJunchao Zhang         Vec r, b;
39529566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
39539566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
39549566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
39559566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
39569566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
39579566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
395880677318SStefano Zampini       }
39599566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
396080677318SStefano Zampini     } else {
3961ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
3962ffd830a3SStefano Zampini         IS dummy;
3963ffd830a3SStefano Zampini 
39649566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &dummy));
39659566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(local_auxmat2_R, dummy, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
39669566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
3967ffd830a3SStefano Zampini       } else {
39689566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
396980677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
3970ffd830a3SStefano Zampini       }
39719566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &M3));
397280677318SStefano Zampini     }
39739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
397480677318SStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
39759566063dSJacob Faibussowitsch     PetscCall(MatScale(M3, m_one));
397680677318SStefano Zampini     if (isCHOL) {
39779566063dSJacob Faibussowitsch       PetscCall(MatCholeskyFactor(M3, NULL, NULL));
397880677318SStefano Zampini     } else {
39799566063dSJacob Faibussowitsch       PetscCall(MatLUFactor(M3, NULL, NULL, NULL));
398080677318SStefano Zampini     }
39819566063dSJacob Faibussowitsch     PetscCall(MatSeqDenseInvertFactors_Private(M3));
398280677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
39839566063dSJacob Faibussowitsch     PetscCall(MatMatMult(M3, C_B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->local_auxmat1));
39849566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
39859566063dSJacob Faibussowitsch     PetscCall(MatCopy(M3, S_CC, SAME_NONZERO_PATTERN)); /* S_CC can have a different LDA, MatMatSolve doesn't support it */
39869566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M3));
3987f4ddd8eeSStefano Zampini   }
3988fc227af8SStefano Zampini 
3989fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
399088ebb749SStefano Zampini   if (n_vertices) {
39917ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
39927ebab0bbSStefano Zampini     PetscBool oldpin;
39937ebab0bbSStefano Zampini #endif
39947ebab0bbSStefano Zampini     PetscBool isaij;
399506656605SStefano Zampini     IS        is_aux;
39963a50541eSStefano Zampini 
3997b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
39986816873aSStefano Zampini       IS tis;
39996816873aSStefano Zampini 
40009566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
40019566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
40029566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
40039566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
40046816873aSStefano Zampini     } else {
40059566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
40066816873aSStefano Zampini     }
40077ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4008b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
40097ebab0bbSStefano Zampini #endif
40109566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
40119566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
40129566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
40139566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A_VR, MATSEQAIJ, &isaij));
40147ebab0bbSStefano Zampini     if (!isaij) { /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
40159566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
40167ebab0bbSStefano Zampini     }
40179566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
40187ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
40199566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
40207ebab0bbSStefano Zampini #endif
40219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
402288ebb749SStefano Zampini   }
402388ebb749SStefano Zampini 
402488ebb749SStefano Zampini   /* Matrix of coarse basis functions (local) */
4025f4ddd8eeSStefano Zampini   if (pcbddc->coarse_phi_B) {
402606656605SStefano Zampini     PetscInt on_B, on_primal, on_D = n_D;
402748a46eb9SPierre Jolivet     if (pcbddc->coarse_phi_D) PetscCall(MatGetSize(pcbddc->coarse_phi_D, &on_D, NULL));
40289566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pcbddc->coarse_phi_B, &on_B, &on_primal));
402906656605SStefano Zampini     if (on_B != n_B || on_primal != pcbddc->local_primal_size || on_D != n_D) {
403006656605SStefano Zampini       PetscScalar *marray;
403106656605SStefano Zampini 
40329566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &marray));
40339566063dSJacob Faibussowitsch       PetscCall(PetscFree(marray));
40349566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
40359566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
40369566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
40379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
4038f4ddd8eeSStefano Zampini     }
4039f4ddd8eeSStefano Zampini   }
404006656605SStefano Zampini 
4041f4ddd8eeSStefano Zampini   if (!pcbddc->coarse_phi_B) {
4042a6e023c1Sstefano_zampini     PetscScalar *marr;
404388ebb749SStefano Zampini 
4044a6e023c1Sstefano_zampini     /* memory size */
404506656605SStefano Zampini     n = n_B * pcbddc->local_primal_size;
4046a6e023c1Sstefano_zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) n += n_D * pcbddc->local_primal_size;
4047a6e023c1Sstefano_zampini     if (!pcbddc->symmetric_primal) n *= 2;
40489566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &marr));
40499566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_B));
4050a6e023c1Sstefano_zampini     marr += n_B * pcbddc->local_primal_size;
40518eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
40529566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_phi_D));
4053a6e023c1Sstefano_zampini       marr += n_D * pcbddc->local_primal_size;
405488ebb749SStefano Zampini     }
40553301b35fSStefano Zampini     if (!pcbddc->symmetric_primal) {
40569566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_B));
4057a6e023c1Sstefano_zampini       marr += n_B * pcbddc->local_primal_size;
405848a46eb9SPierre Jolivet       if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, marr, &pcbddc->coarse_psi_D));
405988ebb749SStefano Zampini     } else {
40609566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
4061c0553b1fSStefano Zampini       pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
40621b968477SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
40639566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
4064c0553b1fSStefano Zampini         pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
4065c0553b1fSStefano Zampini       }
406688ebb749SStefano Zampini     }
406706656605SStefano Zampini   }
4068019a44ceSStefano Zampini 
406906656605SStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
40704f1b2e48SStefano Zampini   p0_lidx_I = NULL;
40714f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4072d12edf2fSStefano Zampini     const PetscInt *idxs;
4073d12edf2fSStefano Zampini 
40749566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
40759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
407648a46eb9SPierre 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]));
40779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4078d12edf2fSStefano Zampini   }
4079d16cbb6bSStefano Zampini 
408006656605SStefano Zampini   /* vertices */
408106656605SStefano Zampini   if (n_vertices) {
4082c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
408316f15bc4SStefano Zampini 
40849566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VV, MATDENSE, MAT_INPLACE_MATRIX, &A_VV));
408504708bb6SStefano Zampini 
408616f15bc4SStefano Zampini     if (n_R) {
408714393ed6SStefano Zampini       Mat                A_RRmA_RV, A_RV_bcorr = NULL, S_VVt; /* S_VVt with LDA=N */
408806656605SStefano Zampini       PetscBLASInt       B_N, B_one            = 1;
40891683a169SBarry Smith       const PetscScalar *x;
40901683a169SBarry Smith       PetscScalar       *y;
409106656605SStefano Zampini 
40929566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
409314393ed6SStefano Zampini       if (need_benign_correction) {
409414393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
409514393ed6SStefano Zampini         IS                     is_p0;
409614393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
409714393ed6SStefano Zampini 
40989566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
40999566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
41009566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
410163a3b9bcSJacob 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);
41029566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
41039566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
41049566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
41059566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
410614393ed6SStefano Zampini       }
410714393ed6SStefano Zampini 
41089566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work, &A_RRmA_RV));
4109c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
4110ffd830a3SStefano Zampini         if (lda_rhs == n_R) {
41119566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4112ffd830a3SStefano Zampini         } else {
4113ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4114ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4115ca92afb2SStefano Zampini           PetscInt        n;
4116ca92afb2SStefano Zampini           PetscBool       flg_row;
4117ffd830a3SStefano Zampini 
4118ca92afb2SStefano Zampini           array = work + lda_rhs * n_vertices;
41199566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(array, lda_rhs * n_vertices));
41209566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
41219566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
41229566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4123ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4124ca92afb2SStefano Zampini             PetscInt j;
4125ca92afb2SStefano Zampini             for (j = xadj[i]; j < xadj[i + 1]; j++) array[lda_rhs * adjncy[j] + i] = av[j];
4126ffd830a3SStefano Zampini           }
41279566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
41289566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
41299566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, array, &A_RV));
4130ffd830a3SStefano Zampini         }
4131a3df083aSStefano Zampini         if (need_benign_correction) {
4132df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4133a3df083aSStefano Zampini           PetscScalar       *marr;
4134a3df083aSStefano Zampini 
41359566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
413614393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
413714393ed6SStefano Zampini 
413814393ed6SStefano Zampini                  | 0 0  0 | (V)
413914393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
414014393ed6SStefano Zampini                  | 0 0 -1 | (p0)
414114393ed6SStefano Zampini 
414214393ed6SStefano Zampini           */
4143df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
414414393ed6SStefano Zampini             const PetscScalar *vals;
414514393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
414614393ed6SStefano Zampini             PetscInt           n, j, nz;
414714393ed6SStefano Zampini 
41489566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
41499566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
41509566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
415114393ed6SStefano Zampini             for (j = 0; j < n; j++) {
415214393ed6SStefano Zampini               PetscScalar val = vals[j];
415314393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
415414393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
415514393ed6SStefano Zampini             }
41569566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
41579566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
415814393ed6SStefano Zampini           }
41599566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
416072b8c272SStefano Zampini         }
41619566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4162c58f9fdbSStefano Zampini         Brhs = A_RV;
4163c58f9fdbSStefano Zampini       } else {
4164c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4165c58f9fdbSStefano Zampini 
4166c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4167fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
41689566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4169c58f9fdbSStefano Zampini         } else {
4170c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
41719566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
41729566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4173c58f9fdbSStefano Zampini           A_RVT = A_VR;
4174c58f9fdbSStefano Zampini         }
4175c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4176c58f9fdbSStefano Zampini           PetscScalar *aa;
4177c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4178c58f9fdbSStefano Zampini           PetscBool    done;
4179c58f9fdbSStefano Zampini 
41809566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
418128b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
41829566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
41839566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
41849566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
418528b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4186c58f9fdbSStefano Zampini         } else {
41879566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4188c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4189c58f9fdbSStefano Zampini         }
41909566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
41919566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
41929566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4193c58f9fdbSStefano Zampini       }
419472b8c272SStefano Zampini       if (F) {
419514393ed6SStefano Zampini         /* need to correct the rhs */
419672b8c272SStefano Zampini         if (need_benign_correction) {
419772b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
419872b8c272SStefano Zampini           PetscScalar       *marr;
419972b8c272SStefano Zampini 
42009566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
42015cbda25cSStefano Zampini           if (lda_rhs != n_R) {
42025cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42039566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
42049566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
42059566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
42065cbda25cSStefano Zampini             }
42075cbda25cSStefano Zampini           } else {
4208a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42099566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
42109566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
42119566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4212a3df083aSStefano Zampini             }
42135cbda25cSStefano Zampini           }
42149566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4215a3df083aSStefano Zampini         }
42169566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
42171baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
421814393ed6SStefano Zampini         /* need to correct the solution */
4219a3df083aSStefano Zampini         if (need_benign_correction) {
4220df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4221a3df083aSStefano Zampini           PetscScalar       *marr;
4222a3df083aSStefano Zampini 
42239566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
42245cbda25cSStefano Zampini           if (lda_rhs != n_R) {
42255cbda25cSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42269566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
42279566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
42289566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
42295cbda25cSStefano Zampini             }
42305cbda25cSStefano Zampini           } else {
4231a3df083aSStefano Zampini             for (i = 0; i < n_vertices; i++) {
42329566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
42339566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
42349566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4235a3df083aSStefano Zampini             }
42365cbda25cSStefano Zampini           }
42379566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4238a3df083aSStefano Zampini         }
423906656605SStefano Zampini       } else {
42409566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(Brhs, &y));
424106656605SStefano Zampini         for (i = 0; i < n_vertices; i++) {
42429566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, y + i * lda_rhs));
42439566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * lda_rhs));
42449566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
42459566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
42469566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
42479566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
424806656605SStefano Zampini         }
42499566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(Brhs, &y));
425006656605SStefano Zampini       }
42519566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
42529566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4253ffd830a3SStefano Zampini       /* S_VV and S_CV */
425406656605SStefano Zampini       if (n_constraints) {
425506656605SStefano Zampini         Mat B;
425680677318SStefano Zampini 
42579566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(work + lda_rhs * n_vertices, n_B * n_vertices));
425880677318SStefano Zampini         for (i = 0; i < n_vertices; i++) {
42599566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * lda_rhs));
42609566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(pcis->vec1_B, work + lda_rhs * n_vertices + i * n_B));
42619566063dSJacob Faibussowitsch           PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
42629566063dSJacob Faibussowitsch           PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
42639566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcis->vec1_B));
42649566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
426580677318SStefano Zampini         }
42669566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_vertices, work + lda_rhs * n_vertices, &B));
42674222ddf1SHong Zhang         /* Reuse dense S_C = pcbddc->local_auxmat1 * B */
42689566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(pcbddc->local_auxmat1, B, NULL, S_CV));
42699566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
42709566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
42719566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
42729566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
42739566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
42744222ddf1SHong Zhang 
42759566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
42769566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_vertices, work + lda_rhs * n_vertices, &B));
42774222ddf1SHong Zhang         /* Reuse B = local_auxmat2_R * S_CV */
42789566063dSJacob Faibussowitsch         PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CV, NULL, B));
42799566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
42809566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
42819566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
42829566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
42834222ddf1SHong Zhang 
42849566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
42859566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(lda_rhs * n_vertices, &B_N));
4286792fecdfSBarry Smith         PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, work + lda_rhs * n_vertices, &B_one, work, &B_one));
42879566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
428806656605SStefano Zampini       }
4289ffd830a3SStefano Zampini       if (lda_rhs != n_R) {
42909566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RRmA_RV));
42919566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, work, &A_RRmA_RV));
42929566063dSJacob Faibussowitsch         PetscCall(MatDenseSetLDA(A_RRmA_RV, lda_rhs));
4293ffd830a3SStefano Zampini       }
42949566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VVt));
429514393ed6SStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
429614393ed6SStefano Zampini       if (need_benign_correction) {
4297df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
429814393ed6SStefano Zampini         PetscScalar       *marr, *sums;
429914393ed6SStefano Zampini 
43009566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
43019566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(S_VVt, &marr));
4302df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
430314393ed6SStefano Zampini           const PetscScalar *vals;
430414393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
430514393ed6SStefano Zampini           PetscInt           n, j, nz;
430614393ed6SStefano Zampini 
43079566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
43089566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
430914393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
431014393ed6SStefano Zampini             PetscInt k;
431114393ed6SStefano Zampini             sums[j] = 0.;
431214393ed6SStefano Zampini             for (k = 0; k < nz; k++) sums[j] += work[idxs_zero[k] + j * lda_rhs];
431314393ed6SStefano Zampini           }
43149566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
431514393ed6SStefano Zampini           for (j = 0; j < n; j++) {
431614393ed6SStefano Zampini             PetscScalar val = vals[j];
431714393ed6SStefano Zampini             PetscInt    k;
4318ad540459SPierre Jolivet             for (k = 0; k < n_vertices; k++) marr[idxs[j] + k * n_vertices] += val * sums[k];
431914393ed6SStefano Zampini           }
43209566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
43219566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
432214393ed6SStefano Zampini         }
43239566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
43249566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(S_VVt, &marr));
43259566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
432614393ed6SStefano Zampini       }
43279566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RRmA_RV));
43289566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(n_vertices * n_vertices, &B_N));
43299566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(A_VV, &x));
43309566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(S_VVt, &y));
4331792fecdfSBarry Smith       PetscCallBLAS("BLASaxpy", BLASaxpy_(&B_N, &one, x, &B_one, y, &B_one));
43329566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(A_VV, &x));
43339566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(S_VVt, &y));
43349566063dSJacob Faibussowitsch       PetscCall(MatCopy(S_VVt, S_VV, SAME_NONZERO_PATTERN));
43359566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_VVt));
4336019a44ceSStefano Zampini     } else {
43379566063dSJacob Faibussowitsch       PetscCall(MatCopy(A_VV, S_VV, SAME_NONZERO_PATTERN));
4338d16cbb6bSStefano Zampini     }
43399566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_VV));
4340d16cbb6bSStefano Zampini 
434106656605SStefano Zampini     /* coarse basis functions */
434206656605SStefano Zampini     for (i = 0; i < n_vertices; i++) {
4343ab2d12f3SJunchao Zhang       Vec         v;
4344ab2d12f3SJunchao Zhang       PetscScalar one = 1.0, zero = 0.0;
434516f15bc4SStefano Zampini 
43469566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
43479566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i, &v));
43489566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43499566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4350ab2d12f3SJunchao Zhang       if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4351ab2d12f3SJunchao Zhang         PetscMPIInt rank;
43529566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), &rank));
435308401ef6SPierre Jolivet         PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_B), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4354ab2d12f3SJunchao Zhang       }
43559566063dSJacob Faibussowitsch       PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
43569566063dSJacob Faibussowitsch       PetscCall(VecAssemblyBegin(v)); /* If v is on device, hope VecSetValues() eventually implemented by a host to device memcopy */
43579566063dSJacob Faibussowitsch       PetscCall(VecAssemblyEnd(v));
43589566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i, &v));
435906656605SStefano Zampini 
436006656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
43614f1b2e48SStefano Zampini         PetscInt j;
43624f1b2e48SStefano Zampini 
43639566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i, &v));
43649566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
43659566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
4366ab2d12f3SJunchao Zhang         if (PetscDefined(USE_DEBUG)) { /* The following VecSetValues() expects a sequential matrix */
4367ab2d12f3SJunchao Zhang           PetscMPIInt rank;
43689566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), &rank));
436908401ef6SPierre Jolivet           PetscCheck(rank <= 1, PetscObjectComm((PetscObject)pcbddc->coarse_phi_D), PETSC_ERR_PLIB, "Expected a sequential dense matrix");
4370ab2d12f3SJunchao Zhang         }
43719566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
43729566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
43739566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
43749566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i, &v));
437506656605SStefano Zampini       }
43769566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
437706656605SStefano Zampini     }
437804708bb6SStefano Zampini     /* if n_R == 0 the object is not destroyed */
43799566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_RV));
438006656605SStefano Zampini   }
43819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
438206656605SStefano Zampini 
438306656605SStefano Zampini   if (n_constraints) {
438406656605SStefano Zampini     Mat B;
438506656605SStefano Zampini 
43869566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_constraints, work, &B));
43879566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
43889566063dSJacob Faibussowitsch     PetscCall(MatProductCreateWithMat(local_auxmat2_R, S_CC, NULL, B));
43899566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
43909566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
43919566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
43929566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
4393a961b312SStefano Zampini 
43949566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
439506656605SStefano Zampini     if (n_vertices) {
439603dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
43977fb60732SBarry Smith         PetscCall(MatTransposeSetPrecursor(S_CV, S_VC));
43989566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_CV, MAT_REUSE_MATRIX, &S_VC));
439980677318SStefano Zampini       } else {
440080677318SStefano Zampini         Mat S_VCt;
440180677318SStefano Zampini 
4402ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
44039566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&B));
44049566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_constraints, work, &B));
44059566063dSJacob Faibussowitsch           PetscCall(MatDenseSetLDA(B, lda_rhs));
4406ffd830a3SStefano Zampini         }
44079566063dSJacob Faibussowitsch         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VCt));
44089566063dSJacob Faibussowitsch         PetscCall(MatCopy(S_VCt, S_VC, SAME_NONZERO_PATTERN));
44099566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCt));
441080677318SStefano Zampini       }
441106656605SStefano Zampini     }
44129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
441306656605SStefano Zampini     /* coarse basis functions */
441406656605SStefano Zampini     for (i = 0; i < n_constraints; i++) {
4415ab2d12f3SJunchao Zhang       Vec v;
441606656605SStefano Zampini 
44179566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + lda_rhs * i));
44189566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
44199566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44209566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44219566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_B, i + n_vertices, &v));
442206656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
44234f1b2e48SStefano Zampini         PetscInt    j;
4424ab2d12f3SJunchao Zhang         PetscScalar zero = 0.0;
44259566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
44269566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44279566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
44289566063dSJacob Faibussowitsch         for (j = 0; j < pcbddc->benign_n; j++) PetscCall(VecSetValues(v, 1, &p0_lidx_I[j], &zero, INSERT_VALUES));
44299566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
44309566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
44319566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_phi_D, i + n_vertices, &v));
443206656605SStefano Zampini       }
44339566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
443406656605SStefano Zampini     }
443506656605SStefano Zampini   }
443648a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&local_auxmat2_R));
44379566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
443872b8c272SStefano Zampini 
443972b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
444072b8c272SStefano Zampini   if (pcbddc->benign_n) {
444172b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
444272b8c272SStefano Zampini     IS                 is_dummy;
44431683a169SBarry Smith     const PetscScalar *data;
444472b8c272SStefano Zampini     PetscInt           j;
444572b8c272SStefano Zampini 
44469566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
44479566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
44489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
44499566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
44509566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
44519566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
445272b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
445372b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
445472b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
445572b8c272SStefano Zampini         coarse_submat_vals[primal_idx * pcbddc->local_primal_size + i] = data[i * pcbddc->benign_n + j];
445672b8c272SStefano Zampini         coarse_submat_vals[i * pcbddc->local_primal_size + primal_idx] = data[i * pcbddc->benign_n + j];
445772b8c272SStefano Zampini       }
445872b8c272SStefano Zampini     }
44599566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
44609566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
44619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
446272b8c272SStefano Zampini   }
4463019a44ceSStefano Zampini 
446406656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
44653301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
4466ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
4467ffd830a3SStefano Zampini     PetscScalar *marray;
446806656605SStefano Zampini 
446906656605SStefano Zampini     if (n_constraints) {
4470ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
447106656605SStefano Zampini 
44729566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
44739566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
44749566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_C));
44759566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
447606656605SStefano Zampini       if (n_vertices) {
4477ffd830a3SStefano Zampini         Mat S_VCT;
447806656605SStefano Zampini 
44799566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
44809566063dSJacob Faibussowitsch         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_V));
44819566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
448206656605SStefano Zampini       }
44839566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
44845b782168SStefano Zampini     } else {
44859566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
448606656605SStefano Zampini     }
448716f15bc4SStefano Zampini     if (n_vertices && n_R) {
4488ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
4489ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
4490ffd830a3SStefano Zampini       PetscInt        n;
4491ffd830a3SStefano Zampini       PetscBool       flg_row;
449206656605SStefano Zampini 
4493ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
44949566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
44959566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
44969566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
44979566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4498ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
4499ffd830a3SStefano Zampini         PetscInt j;
4500ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
4501ffd830a3SStefano Zampini       }
45029566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
45039566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
45049566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
450506656605SStefano Zampini     }
450606656605SStefano Zampini 
4507ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
4508abc8f43dSstefano_zampini     if (n_vertices) {
45099566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4510ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
45119566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
45129566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
45139566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
45149566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
45159566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
45169566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
451706656605SStefano Zampini       }
45189566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
4519abc8f43dSstefano_zampini     }
45205b782168SStefano Zampini     if (B_C) {
45219566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
4522ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
45239566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
45249566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
45259566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
45269566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
45279566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
45289566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
452906656605SStefano Zampini       }
45309566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
45315b782168SStefano Zampini     }
453206656605SStefano Zampini     /* coarse basis functions */
453306656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
4534ab2d12f3SJunchao Zhang       Vec v;
453506656605SStefano Zampini 
45369566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
45379566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
45389566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45399566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
454006656605SStefano Zampini       if (i < n_vertices) {
4541ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
45429566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
45439566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
45449566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
454506656605SStefano Zampini       }
45469566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
454706656605SStefano Zampini 
454806656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
45499566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
45509566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45519566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
45529566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
455306656605SStefano Zampini       }
45549566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
455506656605SStefano Zampini     }
45569566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
45579566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
455806656605SStefano Zampini   }
4559a6e023c1Sstefano_zampini 
4560d62866d3SStefano Zampini   /* free memory */
45619566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
45629566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VV));
45639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
45649566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
45659566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
45669566063dSJacob Faibussowitsch   PetscCall(PetscFree(work));
456748a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
456848a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
45699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
45708ead10e4SStefano Zampini 
4571da81f932SPierre Jolivet   /* Checking coarse_sub_mat and coarse basis functions */
457288ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
457388ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
4574d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
457588ebb749SStefano Zampini     Mat       coarse_sub_mat;
457625084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
457788ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
457888ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
457988ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
45808bec7fa6SStefano Zampini     Mat       C_B, CPHI;
45818bec7fa6SStefano Zampini     IS        is_dummy;
45828bec7fa6SStefano Zampini     Vec       mones;
458388ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
458488ebb749SStefano Zampini     PetscReal real_value;
458588ebb749SStefano Zampini 
4586a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
4587a3df083aSStefano Zampini       Mat A;
45889566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
45899566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
45909566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
45919566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
45929566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
45939566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
4594a3df083aSStefano Zampini     } else {
45959566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
45969566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
45979566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
45989566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
4599a3df083aSStefano Zampini     }
46009566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
46019566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
4602ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
46039566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
46049566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
460588ebb749SStefano Zampini     }
46069566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_sub_mat));
460788ebb749SStefano Zampini 
46089566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
46099566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
46109566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
4611ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
46129566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46139566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
46149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46159566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46169566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
46179566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46189566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46199566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
46209566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46219566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46229566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
46239566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
462488ebb749SStefano Zampini     } else {
46259566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
46269566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
46279566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46289566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
46299566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
46309566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
46319566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
46329566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
463388ebb749SStefano Zampini     }
46349566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
46359566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
46369566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
46379566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
46384f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
4639fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
46401683a169SBarry Smith       const PetscScalar *data2;
46411683a169SBarry Smith       PetscScalar       *data;
46424f1b2e48SStefano Zampini       PetscInt           j;
4643d12edf2fSStefano Zampini 
46449566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
46459566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
46469566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
46479566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
46489566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
46499566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
46504f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
46514f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
4652d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
46534f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
46544f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
46554f1b2e48SStefano Zampini         }
4656d12edf2fSStefano Zampini       }
46579566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
46589566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
46599566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
46609566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
46619566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
4662d12edf2fSStefano Zampini     }
4663d12edf2fSStefano Zampini #if 0
4664d12edf2fSStefano Zampini   {
4665d12edf2fSStefano Zampini     PetscViewer viewer;
4666d12edf2fSStefano Zampini     char filename[256];
4667a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level));
46689566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
46699566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
46709566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coarse_sub_mat,"computed"));
46719566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_sub_mat,viewer));
46729566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)TM1,"projected"));
46739566063dSJacob Faibussowitsch     PetscCall(MatView(TM1,viewer));
4674a7414863SStefano Zampini     if (pcbddc->coarse_phi_B) {
46759566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
46769566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
467772b8c272SStefano Zampini     }
4678ffd830a3SStefano Zampini     if (pcbddc->coarse_phi_D) {
46799566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
46809566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
4681ffd830a3SStefano Zampini     }
4682ffd830a3SStefano Zampini     if (pcbddc->coarse_psi_B) {
46839566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
46849566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
4685ffd830a3SStefano Zampini     }
468672b8c272SStefano Zampini     if (pcbddc->coarse_psi_D) {
46879566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
46889566063dSJacob Faibussowitsch       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
4689ffd830a3SStefano Zampini     }
46909566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
46919566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->local_mat,viewer));
46929566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
46939566063dSJacob Faibussowitsch     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
46949566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
46959566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_I_local,viewer));
46969566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
46979566063dSJacob Faibussowitsch     PetscCall(ISView(pcis->is_B_local,viewer));
46989566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
46999566063dSJacob Faibussowitsch     PetscCall(ISView(pcbddc->is_R_local,viewer));
47009566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
4701d12edf2fSStefano Zampini   }
4702d12edf2fSStefano Zampini #endif
47039566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, m_one, coarse_sub_mat, DIFFERENT_NONZERO_PATTERN));
47049566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
47059566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
470663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
47078bec7fa6SStefano Zampini 
47088bec7fa6SStefano Zampini     /* check constraints */
47099566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
47109566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
47114f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
47129566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
4713a00504b5SStefano Zampini     } else {
4714a00504b5SStefano Zampini       PetscScalar *data;
4715a00504b5SStefano Zampini       Mat          tmat;
47169566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
47179566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
47189566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
47199566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
47209566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
4721a00504b5SStefano Zampini     }
47229566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
47239566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
47249566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
47259566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
472663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
4727ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
47289566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
47299566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
47309566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
47319566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
473263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
473388ebb749SStefano Zampini     }
47349566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
47359566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
47369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
47379566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
47389566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
47399566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
47409566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
47419566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
47429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
47439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
47449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
47459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
47469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
47479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
47489566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
4749ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
47509566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
47519566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
475288ebb749SStefano Zampini     }
47539566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_sub_mat));
475488ebb749SStefano Zampini   }
47557ebab0bbSStefano Zampini   /* FINAL CUDA support (we cannot currently mix viennacl and cuda vectors */
47567ebab0bbSStefano Zampini   {
47577ebab0bbSStefano Zampini     PetscBool gpu;
47587ebab0bbSStefano Zampini 
47599566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcis->vec1_N, VECSEQCUDA, &gpu));
47607ebab0bbSStefano Zampini     if (gpu) {
476148a46eb9SPierre Jolivet       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
476248a46eb9SPierre Jolivet       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
476348a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
476448a46eb9SPierre Jolivet       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
476548a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
476648a46eb9SPierre Jolivet       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, MATSEQDENSECUDA, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
47677ebab0bbSStefano Zampini     }
47687ebab0bbSStefano Zampini   }
47698629588bSStefano Zampini   /* get back data */
47708629588bSStefano Zampini   *coarse_submat_vals_n = coarse_submat_vals;
47713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
477288ebb749SStefano Zampini }
477388ebb749SStefano Zampini 
4774d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B)
4775d71ae5a4SJacob Faibussowitsch {
4776d65f70fdSStefano Zampini   Mat      *work_mat;
4777d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
4778d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
4779c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
4780aa0d41d4SStefano Zampini 
4781aa0d41d4SStefano Zampini   PetscFunctionBegin;
47829566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
47839566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
47849566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
47859566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
4786aa0d41d4SStefano Zampini 
4787d65f70fdSStefano Zampini   if (!rsorted) {
4788906d46d4SStefano Zampini     const PetscInt *idxs;
4789906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
4790aa0d41d4SStefano Zampini 
47919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
47929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
4793ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_perm_r[i] = i;
47949566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
47959566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
4796ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_sorted[i] = idxs[idxs_perm_r[i]];
47979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
47989566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
4799d65f70fdSStefano Zampini   } else {
48009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
4801d65f70fdSStefano Zampini     isrow_s = isrow;
4802aa0d41d4SStefano Zampini   }
4803906d46d4SStefano Zampini 
4804d65f70fdSStefano Zampini   if (!csorted) {
4805d65f70fdSStefano Zampini     if (isrow == iscol) {
48069566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
4807d65f70fdSStefano Zampini       iscol_s = isrow_s;
4808d65f70fdSStefano Zampini     } else {
4809d65f70fdSStefano Zampini       const PetscInt *idxs;
4810d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
4811906d46d4SStefano Zampini 
48129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
48139566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
4814ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_perm_c[i] = i;
48159566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
48169566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
4817ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_sorted[i] = idxs[idxs_perm_c[i]];
48189566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
48199566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
4820d65f70fdSStefano Zampini     }
4821d65f70fdSStefano Zampini   } else {
48229566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
4823d65f70fdSStefano Zampini     iscol_s = iscol;
4824d65f70fdSStefano Zampini   }
4825d65f70fdSStefano Zampini 
48269566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
4827d65f70fdSStefano Zampini 
4828d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
4829906d46d4SStefano Zampini     Mat new_mat;
4830d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
4831906d46d4SStefano Zampini 
4832d65f70fdSStefano Zampini     if (!rsorted) {
4833d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
48349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
4835ad540459SPierre Jolivet       for (i = 0; i < rsize; i++) idxs_r[idxs_perm_r[i]] = i;
48369566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
48379566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
4838d65f70fdSStefano Zampini     } else {
48399566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
4840906d46d4SStefano Zampini     }
48419566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
4842d65f70fdSStefano Zampini 
4843d65f70fdSStefano Zampini     if (!csorted) {
4844d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
48459566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
4846d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
4847d65f70fdSStefano Zampini       } else {
4848d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
484928b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
48509566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
4851ad540459SPierre Jolivet         for (i = 0; i < csize; i++) idxs_c[idxs_perm_c[i]] = i;
48529566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
48539566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
4854d65f70fdSStefano Zampini       }
4855d65f70fdSStefano Zampini     } else {
48569566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
4857d65f70fdSStefano Zampini     }
48589566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
4859d65f70fdSStefano Zampini 
48609566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
48619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
4862d65f70fdSStefano Zampini     work_mat[0] = new_mat;
48639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
48649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
4865d65f70fdSStefano Zampini   }
4866d65f70fdSStefano Zampini 
48679566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
4868d65f70fdSStefano Zampini   *B = work_mat[0];
48699566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
48709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
48719566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
48723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4873d65f70fdSStefano Zampini }
4874d65f70fdSStefano Zampini 
4875d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
4876d71ae5a4SJacob Faibussowitsch {
4877aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
48785e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
4879022d8d2bSstefano_zampini   Mat       new_mat, lA;
48805e8657edSStefano Zampini   IS        is_local, is_global;
4881d65f70fdSStefano Zampini   PetscInt  local_size;
4882b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
4883aa0d41d4SStefano Zampini 
4884aa0d41d4SStefano Zampini   PetscFunctionBegin;
48859566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
48869566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
48879566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
48889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
48899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_local));
48909566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
48919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_global));
4892906d46d4SStefano Zampini 
4893906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
4894906d46d4SStefano Zampini     Vec       x, x_change;
4895906d46d4SStefano Zampini     PetscReal error;
4896906d46d4SStefano Zampini 
48979566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
48989566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
48999566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
49009566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
49019566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
49029566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
490388428137SStefano Zampini     if (!pcbddc->change_interior) {
490488428137SStefano Zampini       const PetscScalar *x, *y, *v;
490588428137SStefano Zampini       PetscReal          lerror = 0.;
490688428137SStefano Zampini       PetscInt           i;
490788428137SStefano Zampini 
49089566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
49099566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
49109566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
491188428137SStefano Zampini       for (i = 0; i < local_size; i++)
49129371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
49139566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
49149566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
49159566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
49161c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
4917637e8532SStefano Zampini       if (error > PETSC_SMALL) {
4918637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
491963a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
4920637e8532SStefano Zampini         } else {
492163a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
4922637e8532SStefano Zampini         }
4923637e8532SStefano Zampini       }
492488428137SStefano Zampini     }
49259566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
49269566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
49279566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
49289566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
4929637e8532SStefano Zampini     if (error > PETSC_SMALL) {
4930637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
493163a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
4932637e8532SStefano Zampini       } else {
493363a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
4934637e8532SStefano Zampini       }
4935637e8532SStefano Zampini     }
49369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
49379566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
4938906d46d4SStefano Zampini   }
4939906d46d4SStefano Zampini 
4940022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
49419566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
4942022d8d2bSstefano_zampini 
494322d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
49449566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
494522d5777bSStefano Zampini   if (isseqaij) {
49469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
49479566063dSJacob Faibussowitsch     PetscCall(MatPtAP(matis->A, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
4948022d8d2bSstefano_zampini     if (lA) {
4949022d8d2bSstefano_zampini       Mat work;
49509566063dSJacob Faibussowitsch       PetscCall(MatPtAP(lA, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
49519566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
49529566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
4953022d8d2bSstefano_zampini     }
4954aa0d41d4SStefano Zampini   } else {
4955a00504b5SStefano Zampini     Mat work_mat;
49561cf9b237SStefano Zampini 
49579566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
49589566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
49599566063dSJacob Faibussowitsch     PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
49609566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
4961022d8d2bSstefano_zampini     if (lA) {
4962022d8d2bSstefano_zampini       Mat work;
49639566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
49649566063dSJacob Faibussowitsch       PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
49659566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
49669566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
4967022d8d2bSstefano_zampini     }
4968aa0d41d4SStefano Zampini   }
4969b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
4970b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
49719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
49723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4973aa0d41d4SStefano Zampini }
4974aa0d41d4SStefano Zampini 
4975d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
4976d71ae5a4SJacob Faibussowitsch {
4977a64d13efSStefano Zampini   PC_IS          *pcis        = (PC_IS *)(pc->data);
4978a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
4979d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
498053892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
49813a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
49823a50541eSStefano Zampini   PetscInt        vbs, bs;
49836816873aSStefano Zampini   PetscBT         bitmask = NULL;
4984a64d13efSStefano Zampini 
4985a64d13efSStefano Zampini   PetscFunctionBegin;
4986b23d619eSStefano Zampini   /*
4987b23d619eSStefano Zampini     No need to setup local scatters if
4988b23d619eSStefano Zampini       - primal space is unchanged
4989b23d619eSStefano Zampini         AND
4990b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
4991b23d619eSStefano Zampini         AND
4992b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
4993b23d619eSStefano Zampini   */
49943ba16761SJacob Faibussowitsch   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) PetscFunctionReturn(PETSC_SUCCESS);
4995f4ddd8eeSStefano Zampini   /* destroy old objects */
49969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
49979566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
49989566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
4999a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
5000b371cd4fSStefano Zampini   n_B        = pcis->n_B;
5001b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
5002b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
50033a50541eSStefano Zampini 
5004a64d13efSStefano Zampini   /* Dohrmann's notation: dofs splitted in R (Remaining: all dofs but the vertices) and V (Vertices) */
50056816873aSStefano Zampini 
500653892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
5007b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
50089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
50099566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
501048a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
5011a64d13efSStefano Zampini 
5012a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
5013ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, i)) idx_R_local[n_R++] = i;
5014a64d13efSStefano Zampini     }
5015df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5016df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
50176816873aSStefano Zampini 
50189566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
50199566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
50206816873aSStefano Zampini   }
50213a50541eSStefano Zampini 
50223a50541eSStefano Zampini   /* Block code */
50233a50541eSStefano Zampini   vbs = 1;
50249566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
50253a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
50263a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
50273a50541eSStefano Zampini     PetscInt *vary;
5028b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
50299566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
50309566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
5031d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5032d3df7717SStefano 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 */
50330e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5034d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
50353a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
50363a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
50373a50541eSStefano Zampini           break;
50383a50541eSStefano Zampini         }
50393a50541eSStefano Zampini       }
50409566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5041d3df7717SStefano Zampini     } else {
5042d3df7717SStefano Zampini       /* Verify directly the R set */
5043d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5044d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5045d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5046d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5047d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5048d3df7717SStefano Zampini             break;
5049d3df7717SStefano Zampini           }
5050d3df7717SStefano Zampini         }
5051d3df7717SStefano Zampini       }
5052d3df7717SStefano Zampini     }
50533a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
50543a50541eSStefano Zampini       vbs = bs;
5055ad540459SPierre Jolivet       for (i = 0; i < n_R / vbs; i++) idx_R_local[i] = idx_R_local[vbs * i] / vbs;
50563a50541eSStefano Zampini     }
50573a50541eSStefano Zampini   }
50589566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5059b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5060df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
506153892102SStefano Zampini 
50629566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
50639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
50649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5065df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
506653892102SStefano Zampini   } else {
50679566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
506853892102SStefano Zampini   }
5069a64d13efSStefano Zampini 
5070a64d13efSStefano Zampini   /* print some info if requested */
5071a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
50729566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
50739566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
50749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
50759566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
507663a3b9bcSJacob 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));
50779371c9d4SSatish 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,
50789371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
50799566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5080a64d13efSStefano Zampini   }
5081a64d13efSStefano Zampini 
5082a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5083b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
50846816873aSStefano Zampini     IS        is_aux1, is_aux2;
50856816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
50866816873aSStefano Zampini 
50879566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
50889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
50899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
50909566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
509148a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
50929566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5093a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
5094ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5095a64d13efSStefano Zampini     }
50969566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
50979566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5098a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
5099ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, is_indices[i])) aux_array2[j++] = i;
5100a64d13efSStefano Zampini     }
51019566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
51029566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
51039566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
51049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
51059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5106a64d13efSStefano Zampini 
51078eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
51089566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5109a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
5110ad540459SPierre Jolivet         if (PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5111a64d13efSStefano Zampini       }
51129566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
51139566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
51149566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5115a64d13efSStefano Zampini     }
51169566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
51179566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5118d62866d3SStefano Zampini   } else {
5119df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
51206816873aSStefano Zampini     IS                 tis;
51216816873aSStefano Zampini     PetscInt           schur_size;
51226816873aSStefano Zampini 
51239566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
51249566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
51259566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
51269566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
51276816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
51289566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
51299566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
51309566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5131d62866d3SStefano Zampini     }
5132d62866d3SStefano Zampini   }
51333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5134a64d13efSStefano Zampini }
5135a64d13efSStefano Zampini 
5136d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B)
5137d71ae5a4SJacob Faibussowitsch {
513892cccca0SStefano Zampini   MatNullSpace   NullSpace;
513992cccca0SStefano Zampini   Mat            dmat;
514092cccca0SStefano Zampini   const Vec     *nullvecs;
514192cccca0SStefano Zampini   Vec            v, v2, *nullvecs2;
51426d9e27e4SStefano Zampini   VecScatter     sct = NULL;
5143eb06acf8SStefano Zampini   PetscContainer c;
5144eb06acf8SStefano Zampini   PetscScalar   *ddata;
5145295df10fSStefano Zampini   PetscInt       k, nnsp_size, bsiz, bsiz2, n, N, bs;
514692cccca0SStefano Zampini   PetscBool      nnsp_has_cnst;
514792cccca0SStefano Zampini 
514892cccca0SStefano Zampini   PetscFunctionBegin;
51496d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
51506d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
51516d9e27e4SStefano Zampini 
515248a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
51536d9e27e4SStefano Zampini     sct = matis->cctx;
51549566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
51556d9e27e4SStefano Zampini   } else {
51569566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
515748a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
51583ba16761SJacob Faibussowitsch     if (NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
51596d9e27e4SStefano Zampini   }
51609566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
516148a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
51623ba16761SJacob Faibussowitsch   if (!NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
51636d9e27e4SStefano Zampini 
51649566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
51659566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
516648a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
51679566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, (const Vec **)&nullvecs));
5168295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
51699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
51709566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
51719566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
51729566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
51739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
517492cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
51759566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
51769566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
51779566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
517892cccca0SStefano Zampini   }
517992cccca0SStefano Zampini   if (nnsp_has_cnst) {
51809566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
51819566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
518292cccca0SStefano Zampini   }
51839566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
51849566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5185295df10fSStefano Zampini 
51869566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
51879566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)B), &c));
51889566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ddata));
51899566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
51909566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", (PetscObject)c));
51919566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
51929566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
51939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5194eb06acf8SStefano Zampini 
519548a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
51969566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
51979566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
51989566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
51999566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
52009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
52019566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
52023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
520392cccca0SStefano Zampini }
5204304d26faSStefano Zampini 
5205d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5206d71ae5a4SJacob Faibussowitsch {
5207304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5208304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5209304d26faSStefano Zampini   PC           pc_temp;
5210304d26faSStefano Zampini   Mat          A_RR;
521192cccca0SStefano Zampini   MatNullSpace nnsp;
5212f4ddd8eeSStefano Zampini   MatReuse     reuse;
5213304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5214304d26faSStefano Zampini   PetscReal    value;
521504708bb6SStefano Zampini   PetscInt     n_D, n_R;
5216b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
52170a545947SLisandro Dalcin   void (*f)(void) = NULL;
5218312be037SStefano Zampini   char   dir_prefix[256], neu_prefix[256], str_level[16];
5219e604994aSStefano Zampini   size_t len;
5220304d26faSStefano Zampini 
5221304d26faSStefano Zampini   PetscFunctionBegin;
52229566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
52236d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
52246d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
52256d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
52266d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
52276d9e27e4SStefano Zampini 
52289566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
52299566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
52309566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
52316d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
52321c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lhas, &ghas, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
523348a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
52346d9e27e4SStefano Zampini   }
52356d9e27e4SStefano Zampini 
5236e604994aSStefano Zampini   /* compute prefixes */
5237c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(dir_prefix, "", sizeof(dir_prefix)));
5238c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(neu_prefix, "", sizeof(neu_prefix)));
5239e604994aSStefano Zampini   if (!pcbddc->current_level) {
52409566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
52419566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
52429566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
52439566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5244e604994aSStefano Zampini   } else {
52459566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)(pcbddc->current_level)));
52469566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
5247e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
5248312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
5249312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
5250a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
52519566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
52529566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
52539566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
52549566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
52559566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
52569566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
5257e604994aSStefano Zampini   }
5258e604994aSStefano Zampini 
5259304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
5260684f6988SStefano Zampini   if (dirichlet) {
5261d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5262450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
52637827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
5264450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
5265a3df083aSStefano Zampini         Mat A_IIn;
5266a3df083aSStefano Zampini 
52679566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
52689566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
5269a3df083aSStefano Zampini         pcis->A_II = A_IIn;
5270a3df083aSStefano Zampini       }
5271450f8f5eSStefano Zampini     }
5272b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5273b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
5274b94d7dedSBarry Smith 
5275ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
5276964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
527792cccca0SStefano Zampini     opts = PETSC_FALSE;
5278304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
527992cccca0SStefano Zampini       opts = PETSC_TRUE;
52809566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
52819566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
5282304d26faSStefano Zampini       /* default */
52839566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
52849566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
52859566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
52869566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
52879577ea80SStefano Zampini       if (issbaij) {
52889566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
52899577ea80SStefano Zampini       } else {
52909566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
52919577ea80SStefano Zampini       }
52929566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
529392cccca0SStefano Zampini     }
52949566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
52959566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
5296304d26faSStefano Zampini     /* Allow user's customization */
52971baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
52989566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
52996d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
53009566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
530192cccca0SStefano Zampini     }
53029566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
53039566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
53049566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
530592cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5306cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5307cd18cfedSStefano Zampini       const PetscInt *idxs;
5308cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5309cd18cfedSStefano Zampini 
53109566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
53119566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
53129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5313cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5314ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5315cd18cfedSStefano Zampini       }
53169566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
53179566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
53189566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5319cd18cfedSStefano Zampini     }
5320b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
5321df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5322d62866d3SStefano Zampini 
53239566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
5324d5574798SStefano Zampini     }
532592cccca0SStefano Zampini 
5326304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5327304d26faSStefano Zampini     if (!n_D) {
53289566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
53299566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5330304d26faSStefano Zampini     }
53319566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
5332304d26faSStefano Zampini     /* set ksp_D into pcis data */
53339566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
53349566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
5335304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
5336684f6988SStefano Zampini   }
5337304d26faSStefano Zampini 
5338304d26faSStefano Zampini   /* NEUMANN PROBLEM */
53390a545947SLisandro Dalcin   A_RR = NULL;
5340684f6988SStefano Zampini   if (neumann) {
5341d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
534204708bb6SStefano Zampini     PetscInt        ibs, mbs;
5343b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
534404708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
53450aa714b2SStefano Zampini 
53460aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
53470aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
53480aa714b2SStefano Zampini       IS iP;
53490aa714b2SStefano Zampini 
53500aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
53519566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
53520aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
53530aa714b2SStefano Zampini     }
5354f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
53559566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
5356f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
5357f4ddd8eeSStefano Zampini       PetscInt nn_R;
53589566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
53599566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
53609566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
5361f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
53629566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
53639566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5364f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5365f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5366727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
53679566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
5368f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
5369f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
5370f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
5371f4ddd8eeSStefano Zampini         }
5372f4ddd8eeSStefano Zampini       }
5373f4ddd8eeSStefano Zampini       /* last check */
5374d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
53759566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5376f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5377f4ddd8eeSStefano Zampini       }
5378f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
5379f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
5380f4ddd8eeSStefano Zampini     }
5381365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
5382365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
53839566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
53849566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
53859566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
538604708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
538704708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
53889566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
53899566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
5390af732b37SStefano Zampini       } else {
53919566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
53926816873aSStefano Zampini       }
539304708bb6SStefano Zampini     } else if (issbaij) { /* need to convert to BAIJ to get offdiagonal blocks */
539404708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
53959566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
53969566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
539704708bb6SStefano Zampini       } else {
53989566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
539904708bb6SStefano Zampini       }
540004708bb6SStefano Zampini     }
5401a00504b5SStefano Zampini     /* extract A_RR */
54020aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5403a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5404a00504b5SStefano Zampini 
5405a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
54069566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5407a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
54089566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
540916e386b8SStefano Zampini         } else {
54109566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
5411a00504b5SStefano Zampini         }
5412a00504b5SStefano Zampini       } else {
54139566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
54149566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
54159566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
5416a00504b5SStefano Zampini       }
5417a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
54189566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
541916e386b8SStefano Zampini     }
5420b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5421b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
542292cccca0SStefano Zampini     opts = PETSC_FALSE;
5423f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
542492cccca0SStefano Zampini       opts = PETSC_TRUE;
54259566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
54269566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
5427304d26faSStefano Zampini       /* default */
54289566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
54299566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
54309566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54319566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
54329577ea80SStefano Zampini       if (issbaij) {
54339566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
54349577ea80SStefano Zampini       } else {
54359566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
54369577ea80SStefano Zampini       }
54379566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
543892cccca0SStefano Zampini     }
54399566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
54409566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
544192cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
54429566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
544392cccca0SStefano Zampini     }
54449566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
54456d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
54469566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
544792cccca0SStefano Zampini     }
54489566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
54499566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54509566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
545192cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5452cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5453cd18cfedSStefano Zampini       const PetscInt *idxs;
5454cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5455cd18cfedSStefano Zampini 
54569566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
54579566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
54589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5459cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5460ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5461cd18cfedSStefano Zampini       }
54629566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
54639566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
54649566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5465cd18cfedSStefano Zampini     }
546692cccca0SStefano Zampini 
5467304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5468304d26faSStefano Zampini     if (!n_R) {
54699566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
54709566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5471304d26faSStefano Zampini     }
5472df4d28bfSStefano Zampini     /* Reuse solver if it is present */
54730aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5474df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5475d62866d3SStefano Zampini 
54769566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
5477d62866d3SStefano Zampini     }
54789566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
5479684f6988SStefano Zampini   }
5480304d26faSStefano Zampini 
5481684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
54829566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
54839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
54849566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
5485684f6988SStefano Zampini   }
54869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
5487c7017625SStefano Zampini 
5488c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
548948a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
549048a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
549148a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
5492c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
5493c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
5494684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
54959566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
54969566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
54979566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
54989566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
54999566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
55009566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
550163a3b9bcSJacob 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));
55029566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5503304d26faSStefano Zampini     }
5504684f6988SStefano Zampini     if (neumann) { /* Neumann */
55059566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
55069566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
55079566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
55089566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
55099566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
55109566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
551163a3b9bcSJacob 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));
55129566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5513304d26faSStefano Zampini     }
5514684f6988SStefano Zampini   }
55155cbda25cSStefano Zampini   /* free Neumann problem's matrix */
55169566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
55173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5518304d26faSStefano Zampini }
5519304d26faSStefano Zampini 
5520d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
5521d71ae5a4SJacob Faibussowitsch {
5522674ae819SStefano Zampini   PC_BDDC        *pcbddc       = (PC_BDDC *)(pc->data);
5523be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
5524b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
5525674ae819SStefano Zampini 
5526674ae819SStefano Zampini   PetscFunctionBegin;
552748a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
552880677318SStefano Zampini   if (!pcbddc->switch_static) {
552980677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
55309566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
55319566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
553220c7b377SStefano Zampini     }
5533b334f244SStefano Zampini     if (!reuse_solver) {
55349566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55359566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
553620c7b377SStefano Zampini     } else {
5537df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5538be83ff47SStefano Zampini 
55399566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
55409566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
554120c7b377SStefano Zampini     }
5542be83ff47SStefano Zampini   } else {
55439566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55449566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55459566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55469566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
554780677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
55489566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
55499566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
55509566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
55519566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
5552674ae819SStefano Zampini     }
5553674ae819SStefano Zampini   }
55549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
5555b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
555680677318SStefano Zampini     if (applytranspose) {
55579566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
555880677318SStefano Zampini     } else {
55599566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
556080677318SStefano Zampini     }
55619566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
5562be83ff47SStefano Zampini   } else {
5563df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5564be83ff47SStefano Zampini 
5565be83ff47SStefano Zampini     if (applytranspose) {
55669566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5567be83ff47SStefano Zampini     } else {
55689566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
5569be83ff47SStefano Zampini     }
5570be83ff47SStefano Zampini   }
55719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
55729566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
557380677318SStefano Zampini   if (!pcbddc->switch_static) {
5574b334f244SStefano Zampini     if (!reuse_solver) {
55759566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55769566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
5577be83ff47SStefano Zampini     } else {
5578df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5579be83ff47SStefano Zampini 
55809566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
55819566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
5582be83ff47SStefano Zampini     }
558380677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
55849566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
55859566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
558680677318SStefano Zampini     }
558780677318SStefano Zampini   } else {
55889566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55899566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55909566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
55919566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
559280677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
55939566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
55949566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
559580677318SStefano Zampini     }
55969566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55979566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
55989566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
55999566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
5600674ae819SStefano Zampini   }
56013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5602674ae819SStefano Zampini }
5603674ae819SStefano Zampini 
5604dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
5605d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
5606d71ae5a4SJacob Faibussowitsch {
5607674ae819SStefano Zampini   PC_BDDC          *pcbddc = (PC_BDDC *)(pc->data);
5608674ae819SStefano Zampini   PC_IS            *pcis   = (PC_IS *)(pc->data);
5609674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
5610674ae819SStefano Zampini 
5611674ae819SStefano Zampini   PetscFunctionBegin;
5612dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
56134fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5614dc359a40SStefano Zampini     if (applytranspose) {
56159566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
56169566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
5617dc359a40SStefano Zampini     } else {
56189566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
56199566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
562015aaf578SStefano Zampini     }
56214fee134fSStefano Zampini   } else {
56229566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
56234fee134fSStefano Zampini   }
5624efc2fbd9SStefano Zampini 
5625efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
56264f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
5627efc2fbd9SStefano Zampini     PetscScalar *array;
56284f1b2e48SStefano Zampini     PetscInt     j;
5629efc2fbd9SStefano Zampini 
56309566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
56314f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
56329566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5633efc2fbd9SStefano Zampini   }
5634efc2fbd9SStefano Zampini 
563512edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
56369566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
56379566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
56389566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
563912edc857SStefano Zampini 
56409f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
564112edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
564251694757SStefano Zampini     Mat          coarse_mat;
5643964fefecSStefano Zampini     Vec          rhs, sol;
564451694757SStefano Zampini     MatNullSpace nullsp;
564527b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
5646964fefecSStefano Zampini 
564727b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
564827b6a85dSStefano Zampini       PC coarse_pc;
564927b6a85dSStefano Zampini 
56509566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
56519566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
565227b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
565327b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
565427b6a85dSStefano Zampini         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)(coarse_pc->data);
565527b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
56563bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
565727b6a85dSStefano Zampini       }
565827b6a85dSStefano Zampini     }
56599566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
56609566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
56619566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
566212edc857SStefano Zampini     if (applytranspose) {
566328b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
56649566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56659566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
56669566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56679566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
56689566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
56691baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
56702701bc32SStefano Zampini     } else {
56719566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
56721f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
56732701bc32SStefano Zampini         PC coarse_pc;
56742701bc32SStefano Zampini 
56751baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
56769566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
56779566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
56789566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
56799566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
568012edc857SStefano Zampini       } else {
56819566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56829566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
56839566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
56849566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
56851baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
568612edc857SStefano Zampini       }
56872701bc32SStefano Zampini     }
56881d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
568927b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
569027b6a85dSStefano Zampini       PC       coarse_pc;
569127b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
569227b6a85dSStefano Zampini 
56939566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
569427b6a85dSStefano Zampini       coarsepcbddc                           = (PC_BDDC *)(coarse_pc->data);
569527b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
56963bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
569727b6a85dSStefano Zampini     }
569812edc857SStefano Zampini   }
5699674ae819SStefano Zampini 
5700674ae819SStefano Zampini   /* Local solution on R nodes */
570148a46eb9SPierre Jolivet   if (pcis->n && !pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
57029f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
57039566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
57049566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
5705674ae819SStefano Zampini 
57064fee134fSStefano Zampini   /* Sum contributions from the two levels */
57074fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
5708dc359a40SStefano Zampini     if (applytranspose) {
57099566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
57109566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5711dc359a40SStefano Zampini     } else {
57129566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
57139566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
5714dc359a40SStefano Zampini     }
5715efc2fbd9SStefano Zampini     /* store p0 */
57164f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5717efc2fbd9SStefano Zampini       PetscScalar *array;
57184f1b2e48SStefano Zampini       PetscInt     j;
5719efc2fbd9SStefano Zampini 
57209566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
57214f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
57229566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
5723efc2fbd9SStefano Zampini     }
57244fee134fSStefano Zampini   } else { /* expand the coarse solution */
57254fee134fSStefano Zampini     if (applytranspose) {
57269566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
57274fee134fSStefano Zampini     } else {
57289566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
57294fee134fSStefano Zampini     }
57304fee134fSStefano Zampini   }
57313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5732674ae819SStefano Zampini }
5733674ae819SStefano Zampini 
5734d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode)
5735d71ae5a4SJacob Faibussowitsch {
5736674ae819SStefano Zampini   PC_BDDC           *pcbddc = (PC_BDDC *)(pc->data);
573712edc857SStefano Zampini   Vec                from, to;
57387ebab0bbSStefano Zampini   const PetscScalar *array;
5739674ae819SStefano Zampini 
5740674ae819SStefano Zampini   PetscFunctionBegin;
574112edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
574212edc857SStefano Zampini     from = pcbddc->coarse_vec;
574312edc857SStefano Zampini     to   = pcbddc->vec1_P;
574412edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
574512edc857SStefano Zampini       Vec tvec;
574658da7f69SStefano Zampini 
57479566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
57489566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
57499566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
57509566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
57519566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
57529566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
575312edc857SStefano Zampini     }
575412edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
575512edc857SStefano Zampini     from = pcbddc->vec1_P;
575612edc857SStefano Zampini     to   = pcbddc->coarse_vec;
575712edc857SStefano Zampini   }
57589566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
57593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5760674ae819SStefano Zampini }
5761674ae819SStefano Zampini 
5762d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
5763d71ae5a4SJacob Faibussowitsch {
5764674ae819SStefano Zampini   PC_BDDC           *pcbddc = (PC_BDDC *)(pc->data);
576512edc857SStefano Zampini   Vec                from, to;
57667ebab0bbSStefano Zampini   const PetscScalar *array;
5767674ae819SStefano Zampini 
5768674ae819SStefano Zampini   PetscFunctionBegin;
576912edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
577012edc857SStefano Zampini     from = pcbddc->coarse_vec;
577112edc857SStefano Zampini     to   = pcbddc->vec1_P;
577212edc857SStefano Zampini   } else { /* from local to global -> put data in coarse right hand side */
577312edc857SStefano Zampini     from = pcbddc->vec1_P;
577412edc857SStefano Zampini     to   = pcbddc->coarse_vec;
577512edc857SStefano Zampini   }
57769566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
577712edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
577812edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
577912edc857SStefano Zampini       Vec tvec;
578058da7f69SStefano Zampini 
57819566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
57829566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
57839566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
57849566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
578558da7f69SStefano Zampini     }
578658da7f69SStefano Zampini   } else {
578758da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
57889566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
578912edc857SStefano Zampini     }
579012edc857SStefano Zampini   }
57913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5792674ae819SStefano Zampini }
5793674ae819SStefano Zampini 
5794d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
5795d71ae5a4SJacob Faibussowitsch {
5796674ae819SStefano Zampini   PC_IS   *pcis   = (PC_IS *)(pc->data);
5797674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
5798674ae819SStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
5799984c4197SStefano Zampini   /* one and zero */
5800984c4197SStefano Zampini   PetscScalar one = 1.0, zero = 0.0;
5801984c4197SStefano Zampini   /* space to store constraints and their local indices */
58029162d606SStefano Zampini   PetscScalar *constraints_data;
58039162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
58049162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
58059162d606SStefano Zampini   PetscInt    *constraints_n;
5806984c4197SStefano Zampini   /* iterators */
5807b3d85658SStefano Zampini   PetscInt i, j, k, total_counts, total_counts_cc, cum;
5808984c4197SStefano Zampini   /* BLAS integers */
5809e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
5810e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
5811c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
5812727cdba6SStefano Zampini   /* reuse */
58130e6343abSStefano Zampini   PetscInt  olocal_primal_size, olocal_primal_size_cc;
58140e6343abSStefano Zampini   PetscInt *olocal_primal_ref_node, *olocal_primal_ref_mult;
5815984c4197SStefano Zampini   /* change of basis */
5816b3d85658SStefano Zampini   PetscBool qr_needed;
58179162d606SStefano Zampini   PetscBT   change_basis, qr_needed_idx;
5818984c4197SStefano Zampini   /* auxiliary stuff */
581964efe560SStefano Zampini   PetscInt *nnz, *is_indices;
58208a0068c3SStefano Zampini   PetscInt  ncc;
5821984c4197SStefano Zampini   /* some quantities */
582245a1bb75SStefano Zampini   PetscInt  n_vertices, total_primal_vertices, valid_constraints;
5823a58a30b4SStefano Zampini   PetscInt  size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
582457715f18SStefano Zampini   PetscReal tol; /* tolerance for retaining eigenmodes */
5825984c4197SStefano Zampini 
5826674ae819SStefano Zampini   PetscFunctionBegin;
582757715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
58288e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
58299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
58309566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
58319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
5832088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
5833088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
58340e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
58359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
58369566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
58379566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
58389566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
58399566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
5840cf5a6209SStefano Zampini 
5841cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
58429162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
5843cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
5844cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
5845cf5a6209SStefano Zampini     Vec         *localnearnullsp;
5846cf5a6209SStefano Zampini     PetscScalar *array;
584732fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
5848cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
5849674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
5850b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
5851674ae819SStefano Zampini     PetscScalar *work;
5852674ae819SStefano Zampini     PetscReal   *singular_vals;
5853674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
5854674ae819SStefano Zampini     PetscReal *rwork;
5855674ae819SStefano Zampini #endif
585655080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
5857964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
5858964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
585955080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
5860674ae819SStefano Zampini 
586155080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
5862b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
586355080a34SStefano Zampini     use_pod = PETSC_TRUE;
586455080a34SStefano Zampini #endif
5865674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
58669566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
586732fe681dSStefano Zampini     o_nf       = n_ISForFaces;
586832fe681dSStefano Zampini     o_ne       = n_ISForEdges;
586932fe681dSStefano Zampini     n_vertices = 0;
587032fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
5871e4d548c7SStefano Zampini     /* print some info */
58725c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
587332fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
58749566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
58759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
58769566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
587732fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
587863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
587963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
58809566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
58819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
5882e4d548c7SStefano Zampini     }
5883e4d548c7SStefano Zampini 
588432fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
588532fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
588632fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
588770022509SStefano Zampini 
5888674ae819SStefano Zampini     /* check if near null space is attached to global mat */
58896d9e27e4SStefano Zampini     if (pcbddc->use_nnsp) {
58909566063dSJacob Faibussowitsch       PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
58916d9e27e4SStefano Zampini     } else nearnullsp = NULL;
58926d9e27e4SStefano Zampini 
5893674ae819SStefano Zampini     if (nearnullsp) {
58949566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
5895f4ddd8eeSStefano Zampini       /* remove any stored info */
58969566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
58979566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
5898f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
58999566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
5900f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
59019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
590248a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
5903984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
5904984c4197SStefano Zampini       nnsp_size     = 0;
5905674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
5906674ae819SStefano Zampini     }
5907984c4197SStefano Zampini     /* get max number of constraints on a single cc */
5908984c4197SStefano Zampini     max_constraints = nnsp_size;
5909984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
5910984c4197SStefano Zampini 
5911674ae819SStefano Zampini     /*
5912674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
59139162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
59149162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
59159162d606SStefano Zampini          There can be multiple constraints per connected component
5916674ae819SStefano Zampini                                                                                                                                                            */
59179162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
59189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
59199162d606SStefano Zampini 
59209162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
59219162d606SStefano Zampini     total_counts *= max_constraints;
5922674ae819SStefano Zampini     total_counts += n_vertices;
59239566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
59249162d606SStefano Zampini 
5925674ae819SStefano Zampini     total_counts           = 0;
5926674ae819SStefano Zampini     max_size_of_constraint = 0;
5927674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
59289162d606SStefano Zampini       IS used_is;
5929674ae819SStefano Zampini       if (i < n_ISForEdges) {
59309162d606SStefano Zampini         used_is = ISForEdges[i];
5931674ae819SStefano Zampini       } else {
59329162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
5933674ae819SStefano Zampini       }
59349566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
5935674ae819SStefano Zampini       total_counts += j;
5936674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
5937674ae819SStefano Zampini     }
59389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
59399162d606SStefano Zampini 
5940984c4197SStefano Zampini     /* get local part of global near null space vectors */
59419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
5942984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
59439566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
59449566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
59459566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
5946984c4197SStefano Zampini     }
5947674ae819SStefano Zampini 
5948242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
5949242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
5950a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
5951242a89d7SStefano Zampini 
5952984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
5953a773dcb8SStefano Zampini     if (!skip_lapack) {
5954674ae819SStefano Zampini       PetscScalar temp_work;
5955911cabfeSStefano Zampini 
595655080a34SStefano Zampini       if (use_pod) {
5957984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
59589566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
59599566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
59609566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
5961674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
59629566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
5963674ae819SStefano Zampini #endif
5964674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
59659566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
59669566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
5967674ae819SStefano Zampini         lwork = -1;
59689566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
5969674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
5970792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
5971674ae819SStefano Zampini #else
5972792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
5973674ae819SStefano Zampini #endif
59749566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
597528b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %d", (int)lierr);
597655080a34SStefano Zampini       } else {
597755080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
5978674ae819SStefano Zampini         /* SVD */
5979674ae819SStefano Zampini         PetscInt max_n, min_n;
5980674ae819SStefano Zampini         max_n = max_size_of_constraint;
5981984c4197SStefano Zampini         min_n = max_constraints;
5982984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
5983674ae819SStefano Zampini           min_n = max_size_of_constraint;
5984984c4197SStefano Zampini           max_n = max_constraints;
5985674ae819SStefano Zampini         }
59869566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
5987674ae819SStefano Zampini   #if defined(PETSC_USE_COMPLEX)
59889566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
5989674ae819SStefano Zampini   #endif
5990674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
5991674ae819SStefano Zampini         lwork = -1;
59929566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
59939566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
59949566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
59959566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
5996674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
5997792fecdfSBarry 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));
5998674ae819SStefano Zampini   #else
5999792fecdfSBarry 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));
6000674ae819SStefano Zampini   #endif
60019566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
600228b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %d", (int)lierr);
600355080a34SStefano Zampini #else
600455080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6005984c4197SStefano Zampini #endif /* on missing GESVD */
600655080a34SStefano Zampini       }
6007674ae819SStefano Zampini       /* Allocate optimal workspace */
60089566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
60099566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
6010674ae819SStefano Zampini     }
6011674ae819SStefano Zampini     /* Now we can loop on constraining sets */
6012674ae819SStefano Zampini     total_counts            = 0;
60139162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
60149162d606SStefano Zampini     constraints_data_ptr[0] = 0;
6015674ae819SStefano Zampini     /* vertices */
60169162d606SStefano Zampini     if (n_vertices) {
60179566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
60189566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
6019674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
60209162d606SStefano Zampini         constraints_n[total_counts]            = 1;
60219162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
60229162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
60239162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
6024674ae819SStefano Zampini         total_counts++;
6025674ae819SStefano Zampini       }
60269566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
6027674ae819SStefano Zampini     }
6028984c4197SStefano Zampini 
6029674ae819SStefano Zampini     /* edges and faces */
60309162d606SStefano Zampini     total_counts_cc = total_counts;
6031911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
60329162d606SStefano Zampini       IS        used_is;
60339162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
60349162d606SStefano Zampini 
6035911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
60369162d606SStefano Zampini         used_is       = ISForEdges[ncc];
6037984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
6038674ae819SStefano Zampini       } else {
60399162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6040984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6041674ae819SStefano Zampini       }
6042674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
60439162d606SStefano Zampini 
60449566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
604532fe681dSStefano Zampini       if (!size_of_constraint) continue;
60469566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6047984c4197SStefano Zampini       /* change of basis should not be performed on local periodic nodes */
6048984c4197SStefano Zampini       if (pcbddc->mat_graph->mirrors && pcbddc->mat_graph->mirrors[is_indices[0]]) boolforchange = PETSC_FALSE;
6049674ae819SStefano Zampini       if (nnsp_has_cnst) {
60505b08dc53SStefano Zampini         PetscScalar quad_value;
60519162d606SStefano Zampini 
60529566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
60539162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
60549162d606SStefano Zampini 
6055a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6056674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6057a773dcb8SStefano Zampini         } else {
6058a773dcb8SStefano Zampini           quad_value = 1.0;
6059a773dcb8SStefano Zampini         }
6060ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value;
60619162d606SStefano Zampini         temp_constraints++;
6062674ae819SStefano Zampini         total_counts++;
6063674ae819SStefano Zampini       }
6064674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6065984c4197SStefano Zampini         PetscReal    real_value;
60669162d606SStefano Zampini         PetscScalar *ptr_to_data;
60679162d606SStefano Zampini 
60689566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
60699162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
6070ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) ptr_to_data[j] = array[is_indices[j]];
60719566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6072984c4197SStefano Zampini         /* check if array is null on the connected component */
60739566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6074792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
607557715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6076674ae819SStefano Zampini           temp_constraints++;
6077674ae819SStefano Zampini           total_counts++;
60789162d606SStefano Zampini           if (!idxs_copied) {
60799566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
60809162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6081674ae819SStefano Zampini           }
6082674ae819SStefano Zampini         }
60839162d606SStefano Zampini       }
60849566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
608545a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6086eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6087a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
60889162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
60899162d606SStefano Zampini 
60909162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
60919566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6092792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6093a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6094792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6095a773dcb8SStefano Zampini         } else { /* perform SVD */
60969162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6097674ae819SStefano Zampini 
609855080a34SStefano Zampini           if (use_pod) {
6099984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6100984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6101984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6102984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6103984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6104984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6105984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
61069566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6107674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
61089566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
61099566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6110674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
611148a46eb9SPierre 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));
6112674ae819SStefano Zampini             }
6113e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
61149566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61159566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6116674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6117792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6118674ae819SStefano Zampini #else
6119792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6120674ae819SStefano Zampini #endif
61219566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
612228b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %d", (int)lierr);
6123984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6124674ae819SStefano Zampini             j = 0;
612587b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6126674ae819SStefano Zampini             total_counts      = total_counts - j;
612745a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6128e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
61299566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
61309566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61319566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
61329566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
61339566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
61349566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6135674ae819SStefano Zampini             if (j < temp_constraints) {
6136984c4197SStefano Zampini               PetscInt ii;
6137984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
61389566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6139792fecdfSBarry 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));
61409566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6141984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
6142ad540459SPierre Jolivet                 for (ii = 0; ii < size_of_constraint; ii++) ptr_to_data[k * size_of_constraint + ii] = singular_vals[temp_constraints - 1 - k] * temp_basis[(temp_constraints - 1 - k) * size_of_constraint + ii];
6143674ae819SStefano Zampini               }
6144674ae819SStefano Zampini             }
614555080a34SStefano Zampini           } else {
614655080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
61479566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
61489566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
61499566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
61509566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6151674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6152792fecdfSBarry 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));
6153674ae819SStefano Zampini   #else
6154792fecdfSBarry 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));
6155674ae819SStefano Zampini   #endif
615628b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
61579566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6158984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6159e310c8b4SStefano Zampini             k = temp_constraints;
6160e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6161674ae819SStefano Zampini             j = 0;
616287b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
616345a1bb75SStefano Zampini             valid_constraints = k - j;
6164911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
616555080a34SStefano Zampini #else
616655080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6167984c4197SStefano Zampini #endif /* on missing GESVD */
6168674ae819SStefano Zampini           }
6169a773dcb8SStefano Zampini         }
617055080a34SStefano Zampini       }
61719162d606SStefano Zampini       /* update pointers information */
61729162d606SStefano Zampini       if (valid_constraints) {
61739162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
61749162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
61759162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
61769162d606SStefano Zampini         /* set change_of_basis flag */
61773ba16761SJacob Faibussowitsch         if (boolforchange) PetscCall(PetscBTSet(change_basis, total_counts_cc));
6178b3d85658SStefano Zampini         total_counts_cc++;
617945a1bb75SStefano Zampini       }
618045a1bb75SStefano Zampini     }
6181984c4197SStefano Zampini     /* free workspace */
61828f1c130eSStefano Zampini     if (!skip_lapack) {
61839566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6184984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
61859566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6186984c4197SStefano Zampini #endif
61879566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
61889566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
61899566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6190984c4197SStefano Zampini     }
619148a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
61929566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6193cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
619432fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
619508122e43SStefano Zampini   } else {
619608122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6197984c4197SStefano Zampini 
619808122e43SStefano Zampini     total_counts = 0;
619908122e43SStefano Zampini     n_vertices   = 0;
620048a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
620108122e43SStefano Zampini     max_constraints = 0;
62029162d606SStefano Zampini     total_counts_cc = 0;
620308122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
620408122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
62059162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
620608122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
620708122e43SStefano Zampini     }
62089162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
62099162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
62109162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
62119162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
621274d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
62139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
62149162d606SStefano Zampini     total_counts_cc = 0;
62159162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
6216ad540459SPierre Jolivet       if (pcbddc->adaptive_constraints_n[i]) constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
621708122e43SStefano Zampini     }
621808122e43SStefano Zampini 
62198bec7fa6SStefano Zampini     max_size_of_constraint = 0;
62209162d606SStefano 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]);
62219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
622208122e43SStefano Zampini     /* Change of basis */
62239566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
622408122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
622508122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
622648a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
622708122e43SStefano Zampini       }
622808122e43SStefano Zampini     }
622908122e43SStefano Zampini   }
6230984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
62319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
623208122e43SStefano Zampini 
62339162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
623432fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
62359566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
623663a3b9bcSJacob 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);
623732fe681dSStefano Zampini   }
6238674ae819SStefano Zampini 
6239674ae819SStefano Zampini   /* Create constraint matrix */
62409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
62419566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
62429566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6243984c4197SStefano Zampini 
6244984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6245a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
62465a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
62479566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
6248984c4197SStefano Zampini   total_primal_vertices        = 0;
6249b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
62509162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
62519162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
625272b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
62539162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6254b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
625564efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
6256ad540459SPierre Jolivet       for (k = 0; k < constraints_n[i]; k++) pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k];
6257b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
625891af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
62593ba16761SJacob Faibussowitsch         PetscCall(PetscBTSet(qr_needed_idx, i));
6260a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
6261a717540cSStefano Zampini       }
6262fa434743SStefano Zampini     } else {
6263b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
6264fa434743SStefano Zampini     }
6265a717540cSStefano Zampini   }
6266b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6267b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
6268674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
62699566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
62709566063dSJacob 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));
62719566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
62720e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
6273984c4197SStefano Zampini 
6274984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
627574d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
62769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
6277984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
627874d5cdf7SStefano Zampini 
6279984c4197SStefano Zampini   j            = total_primal_vertices;
628074d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
6281b3d85658SStefano Zampini   cum          = total_primal_vertices;
62829162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
62834641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
6284b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6285b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6286b3d85658SStefano Zampini       cum++;
62879162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
628874d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
628974d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
629074d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
629174d5cdf7SStefano Zampini       }
62929162d606SStefano Zampini       j += constraints_n[i];
6293674ae819SStefano Zampini     }
6294674ae819SStefano Zampini   }
62959566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
62969566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
62979566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
6298088faed8SStefano Zampini 
6299674ae819SStefano Zampini   /* set values in constraint matrix */
630048a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
6301984c4197SStefano Zampini   total_counts = total_primal_vertices;
63029162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
63034641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
63049162d606SStefano Zampini       PetscInt *cols;
63059162d606SStefano Zampini 
63069162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
63079162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
63089162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
63099162d606SStefano Zampini         PetscInt     row = total_counts + k;
63109162d606SStefano Zampini         PetscScalar *vals;
63119162d606SStefano Zampini 
63129162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
63139566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
63149162d606SStefano Zampini       }
63159162d606SStefano Zampini       total_counts += constraints_n[i];
6316674ae819SStefano Zampini     }
6317674ae819SStefano Zampini   }
6318674ae819SStefano Zampini   /* assembling */
63199566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
63209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
63219566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
6322088faed8SStefano Zampini 
6323674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6324674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
6325026de310SStefano Zampini     /* dual and primal dofs on a single cc */
6326984c4197SStefano Zampini     PetscInt dual_dofs, primal_dofs;
6327984c4197SStefano Zampini     /* working stuff for GEQRF */
63285a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
6329984c4197SStefano Zampini     PetscBLASInt lqr_work;
6330984c4197SStefano Zampini     /* working stuff for UNGQR */
63313c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
6332984c4197SStefano Zampini     PetscBLASInt lgqr_work;
6333984c4197SStefano Zampini     /* working stuff for TRTRS */
63345a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
63353f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
6336984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
6337984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
6338984c4197SStefano Zampini     PetscScalar *start_vals;
6339984c4197SStefano Zampini     /* working stuff for values insertion */
63404641a718SStefano Zampini     PetscBT   is_primal;
634164efe560SStefano Zampini     PetscInt *aux_primal_numbering_B;
6342906d46d4SStefano Zampini     /* matrix sizes */
6343906d46d4SStefano Zampini     PetscInt global_size, local_size;
6344906d46d4SStefano Zampini     /* temporary change of basis */
6345906d46d4SStefano Zampini     Mat localChangeOfBasisMatrix;
6346cf5a6209SStefano Zampini     /* extra space for debugging */
63475a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
6348984c4197SStefano Zampini 
63499566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
63509566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
63519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
6352906d46d4SStefano Zampini     /* nonzeros for local mat */
63539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
63541dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6355bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
63561dd7afcfSStefano Zampini     } else {
63571dd7afcfSStefano Zampini       const PetscInt *ii;
63581dd7afcfSStefano Zampini       PetscInt        n;
63591dd7afcfSStefano Zampini       PetscBool       flg_row;
63609566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
63611dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
63629566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
63631dd7afcfSStefano Zampini     }
63649162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
6365a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
63669162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
6367a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
63689162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
6369a717540cSStefano Zampini         } else {
63709162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
63719162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
6372a717540cSStefano Zampini         }
6373a717540cSStefano Zampini       }
6374a717540cSStefano Zampini     }
63759566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
63769566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
63779566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
63781dd7afcfSStefano Zampini     /* Set interior change in the matrix */
63791dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
638048a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
63811dd7afcfSStefano Zampini     } else {
63821dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
63831dd7afcfSStefano Zampini       PetscScalar    *aa;
63841dd7afcfSStefano Zampini       PetscInt        n;
63851dd7afcfSStefano Zampini       PetscBool       flg_row;
63869566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
63879566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
638848a46eb9SPierre 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));
63899566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
63909566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
63911dd7afcfSStefano Zampini     }
6392a717540cSStefano Zampini 
6393a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
63949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
63959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
6396a717540cSStefano Zampini     }
6397a717540cSStefano Zampini 
6398a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
6399a717540cSStefano Zampini     /*
6400a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
6401a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
6402a717540cSStefano Zampini 
64037c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
6404a717540cSStefano Zampini 
64057c625d9fSStefano 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)
6406a6b551f4SStefano Zampini 
6407a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
6408a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
6409a717540cSStefano Zampini             |              ...                        |
6410a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
6411a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
6412a717540cSStefano Zampini 
6413a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
6414a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
6415a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
6416a6b551f4SStefano Zampini 
6417a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
6418a717540cSStefano Zampini     */
64195a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
6420984c4197SStefano Zampini       /* space to store Q */
64219566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
64224e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
64239566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
6424984c4197SStefano Zampini       /* first we issue queries for optimal work */
64259566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
64269566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
64279566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
6428984c4197SStefano Zampini       lqr_work = -1;
6429792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
643028b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %d", (int)lierr);
64319566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
64329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((PetscInt)PetscRealPart(lqr_work_t), &qr_work));
6433984c4197SStefano Zampini       lgqr_work = -1;
64349566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
64359566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
64369566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
64379566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
64383f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
6439792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
644028b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %d", (int)lierr);
64419566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
64429566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((PetscInt)PetscRealPart(lgqr_work_t), &gqr_work));
6443984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
64449566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
6445a717540cSStefano Zampini       /* allocating workspace for check */
644648a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
6447a717540cSStefano Zampini     }
6448984c4197SStefano Zampini     /* array to store whether a node is primal or not */
64499566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
64509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
64519566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
645263a3b9bcSJacob 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);
645348a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
64549566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
6455984c4197SStefano Zampini 
6456a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
64579162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
64589162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
64594641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
6460984c4197SStefano Zampini         /* get constraint info */
64619162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
6462984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
6463984c4197SStefano Zampini 
646448a46eb9SPierre 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));
6465984c4197SStefano Zampini 
6466fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
6467a717540cSStefano Zampini 
6468a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
646948a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6470984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
64719566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6472984c4197SStefano Zampini 
6473984c4197SStefano Zampini           /* compute QR decomposition of constraints */
64749566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
64759566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
64769566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64779566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6478792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
647928b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %d", (int)lierr);
64809566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6481984c4197SStefano Zampini 
6482a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
64839566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
6484984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
64859566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
64869566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
64879566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64889566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
64899566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6490792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
649128b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %d", (int)lierr);
64929566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6493984c4197SStefano Zampini 
6494a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
64959566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
64969566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
64979566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
64989566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
64999566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6500792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
650128b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %d", (int)lierr);
65029566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
6503984c4197SStefano Zampini 
6504984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
6505984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
6506984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
65079566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
65089566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
65099566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
65109566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65119566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
65129566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
65139566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6514792fecdfSBarry 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));
65159566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
65169566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
6517984c4197SStefano Zampini 
6518984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
65199162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
6520984c4197SStefano Zampini           /* insert cols for primal dofs */
6521984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
6522984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
65239162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
65249566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6525984c4197SStefano Zampini           }
6526984c4197SStefano Zampini           /* insert cols for dual dofs */
6527984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
65289162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
6529984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
65309162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
65319566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
6532984c4197SStefano Zampini               j++;
6533674ae819SStefano Zampini             }
6534674ae819SStefano Zampini           }
6535984c4197SStefano Zampini 
6536984c4197SStefano Zampini           /* check change of basis */
6537984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
6538984c4197SStefano Zampini             PetscInt  ii, jj;
6539984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
65409566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
65419566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
65429566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
65439566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
65449566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
65459566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
65469566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6547792fecdfSBarry 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));
65489566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6549984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
6550984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
6551cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
6552c068d9bbSLisandro 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;
6553674ae819SStefano Zampini               }
6554674ae819SStefano Zampini             }
6555984c4197SStefano Zampini             if (!valid_qr) {
65569566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
6557984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
6558984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
6559cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
656063a3b9bcSJacob 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])));
6561674ae819SStefano Zampini                   }
6562c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
656363a3b9bcSJacob 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])));
6564984c4197SStefano Zampini                   }
6565984c4197SStefano Zampini                 }
6566984c4197SStefano Zampini               }
6567674ae819SStefano Zampini             } else {
65689566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
6569674ae819SStefano Zampini             }
6570674ae819SStefano Zampini           }
6571a717540cSStefano Zampini         } else { /* simple transformation block */
6572a717540cSStefano Zampini           PetscInt    row, col;
6573a6b551f4SStefano Zampini           PetscScalar val, norm;
6574a6b551f4SStefano Zampini 
65759566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6576792fecdfSBarry 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));
6577a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
65789162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
65799162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
6580bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
65819162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
65829566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
65839566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
6584a717540cSStefano Zampini             } else {
6585a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
65869162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
6587a717540cSStefano Zampini                 if (row != col) {
65889162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
6589a717540cSStefano Zampini                 } else {
65909162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
6591a717540cSStefano Zampini                 }
65929566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
6593a717540cSStefano Zampini               }
6594a717540cSStefano Zampini             }
6595a717540cSStefano Zampini           }
659648a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
6597a717540cSStefano Zampini         }
6598984c4197SStefano Zampini       } else {
659948a46eb9SPierre 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));
6600674ae819SStefano Zampini       }
6601674ae819SStefano Zampini     }
6602a717540cSStefano Zampini 
6603a717540cSStefano Zampini     /* free workspace */
6604a717540cSStefano Zampini     if (qr_needed) {
66051baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
66069566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
66079566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
66089566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
66099566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
66109566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
6611674ae819SStefano Zampini     }
66129566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
66139566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
66149566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
6615906d46d4SStefano Zampini 
6616906d46d4SStefano Zampini     /* assembling of global change of variable */
661788c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
6618bbb9e6c6SStefano Zampini       Mat      tmat;
661916f15bc4SStefano Zampini       PetscInt bs;
662016f15bc4SStefano Zampini 
66219566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
66229566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
66239566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
66249566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
66259566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
66269566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
66279566063dSJacob Faibussowitsch       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->ChangeOfBasisMatrix));
66289566063dSJacob Faibussowitsch       PetscCall(MatSetType(pcbddc->ChangeOfBasisMatrix, MATAIJ));
66299566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(pc->pmat, &bs));
66309566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(pcbddc->ChangeOfBasisMatrix, bs));
66319566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(pcbddc->ChangeOfBasisMatrix, local_size, local_size, global_size, global_size));
66329566063dSJacob Faibussowitsch       PetscCall(MatISSetMPIXAIJPreallocation_Private(tmat, pcbddc->ChangeOfBasisMatrix, PETSC_TRUE));
66339566063dSJacob Faibussowitsch       PetscCall(MatConvert(tmat, MATAIJ, MAT_REUSE_MATRIX, &pcbddc->ChangeOfBasisMatrix));
66349566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
66359566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
66369566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
66379566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
66389566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
66399566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
66409566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
664188c03ad3SStefano Zampini 
6642906d46d4SStefano Zampini       /* check */
6643906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
6644906d46d4SStefano Zampini         PetscReal error;
6645906d46d4SStefano Zampini         Vec       x, x_change;
6646906d46d4SStefano Zampini 
66479566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
66489566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
66499566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
66509566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
66519566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
66529566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
66539566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
66549566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
66559566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
66569566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
66579566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
66589566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
6659049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
66609566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
66619566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
6662906d46d4SStefano Zampini       }
6663b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
6664b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
6665b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6666bf3a8328SStefano Zampini 
666708401ef6SPierre 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");
6668b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
6669ac632422SStefano Zampini           Mat S_new, tmat;
6670bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
6671bbb9e6c6SStefano Zampini 
66729566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
66739566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
6674bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6675bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
6676bf3a8328SStefano Zampini             IS                     is_V;
66779566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
66789566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
66799566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
66809566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
66819566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
6682bf3a8328SStefano Zampini           }
66839566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
66849566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
66859566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
66869566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
6687bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
6688bf3a8328SStefano Zampini             const PetscScalar *array;
6689bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
6690bf3a8328SStefano Zampini             PetscInt           i, n_V;
6691bf3a8328SStefano Zampini 
66929566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
66939566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
66949566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
66959566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
66969566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
6697b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
6698b087196eSStefano Zampini               PetscScalar val;
6699b087196eSStefano Zampini               PetscInt    idx;
6700b087196eSStefano Zampini 
6701b087196eSStefano Zampini               idx = idxs_V[i];
6702b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
67039566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
6704b087196eSStefano Zampini             }
67059566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
67069566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
67079566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
67089566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
67099566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
6710bf3a8328SStefano Zampini           }
6711ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
67129566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
6713ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
67149566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
67159566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
67169566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
67171baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
6718ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
67199566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
6720ac632422SStefano Zampini           }
67219566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
67229566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
6723b96c3477SStefano Zampini         }
6724c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
6725b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
6726c9db6a07SStefano Zampini           PetscInt i;
6727c9db6a07SStefano Zampini 
672848a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
67299566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
6730c9db6a07SStefano Zampini         }
6731b96c3477SStefano Zampini       }
673216909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
673316909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
673416909a7fSStefano Zampini       } else {
67359566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
673616909a7fSStefano Zampini       }
67371dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
673827b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
673972b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
67409566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
674172b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
674272b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
674372b8c272SStefano Zampini     }
67441dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
674527b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
67469566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
6747b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
6748906d46d4SStefano Zampini     } else {
67491dd7afcfSStefano Zampini       Mat benign_global = NULL;
675027b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
67511dd7afcfSStefano Zampini         Mat M;
67521dd7afcfSStefano Zampini 
67539e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
67549566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
67559566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
67569566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
67579e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
67589566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
67599566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
6760906d46d4SStefano Zampini         } else {
67619566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
67629566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
6763906d46d4SStefano Zampini         }
67649566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
67659566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
67669566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
67679566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
67681dd7afcfSStefano Zampini       }
67691dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
67709566063dSJacob Faibussowitsch         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->ChangeOfBasisMatrix));
67719566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
677227b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
67731dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
67741dd7afcfSStefano Zampini       }
67751dd7afcfSStefano Zampini     }
677616909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
677716909a7fSStefano Zampini       IS              is_global;
677816909a7fSStefano Zampini       const PetscInt *gidxs;
677916909a7fSStefano Zampini 
67809566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
67819566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
67829566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
67839566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
67849566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
678516909a7fSStefano Zampini     }
67861dd7afcfSStefano Zampini   }
678748a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
6788a717540cSStefano Zampini 
678972b8c272SStefano Zampini   if (!pcbddc->fake_change) {
67904f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
67914f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
67924f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
67934f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
6794019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
6795019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
6796019a44ceSStefano Zampini       pcbddc->local_primal_size++;
6797019a44ceSStefano Zampini     }
6798019a44ceSStefano Zampini 
6799019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
6800727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
6801727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
68029566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6803c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
68040e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
68059566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
6806727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
6807727cdba6SStefano Zampini       }
68080e6343abSStefano Zampini     }
6809727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
68101c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
681172b8c272SStefano Zampini   }
68129566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
6813727cdba6SStefano Zampini 
6814a717540cSStefano Zampini   /* flush dbg viewer */
68151baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6816a717540cSStefano Zampini 
6817e310c8b4SStefano Zampini   /* free workspace */
68189566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
68199566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
682008122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
68219566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
68229566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
682308122e43SStefano Zampini   } else {
6824d0609cedSBarry 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));
68259566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
68269566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
682708122e43SStefano Zampini   }
68283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6829674ae819SStefano Zampini }
6830674ae819SStefano Zampini 
6831d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
6832d71ae5a4SJacob Faibussowitsch {
683371582508SStefano Zampini   ISLocalToGlobalMapping map;
6834674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
6835674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
683666da6bd7Sstefano_zampini   PetscInt               i, N;
683766da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
6838674ae819SStefano Zampini 
6839674ae819SStefano Zampini   PetscFunctionBegin;
68408af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
6841b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
68428e61c736SStefano Zampini     /* Reset previously computed graph */
68439566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
6844674ae819SStefano Zampini     /* Init local Graph struct */
68459566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
68469566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
68479566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
6848674ae819SStefano Zampini 
684948a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
6850575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
68519371c9d4SSatish 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,
68529371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
68539577ea80SStefano Zampini 
6854674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
685566da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
68564d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
68574d379d7bSStefano Zampini       PetscInt  nvtxs;
6858e496cd5dSStefano Zampini       PetscBool flg_row = PETSC_FALSE;
6859674ae819SStefano Zampini 
68609566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
68612fffb893SStefano Zampini       if (flg_row) {
68629566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
6863b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
68642fffb893SStefano Zampini       }
68659566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
686666da6bd7Sstefano_zampini       rcsr = PETSC_TRUE;
6867674ae819SStefano Zampini     }
68681baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6869674ae819SStefano Zampini 
6870ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
6871ab8c8b98SStefano Zampini       PetscReal   *lcoords;
6872ab8c8b98SStefano Zampini       PetscInt     n;
6873ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
6874ab8c8b98SStefano Zampini 
68754f819b78SStefano Zampini       /* TODO: support for blocked */
687663a3b9bcSJacob 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);
68779566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
68789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
68799566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_contiguous(pcbddc->mat_graph->cdim, MPIU_REAL, &dimrealtype));
68809566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
68819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
68829566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
68839566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
68849566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
6885ab8c8b98SStefano Zampini 
6886ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
6887ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
6888ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
6889ab8c8b98SStefano Zampini     }
68909371c9d4SSatish 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,
68919371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
6892625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
6893ab8c8b98SStefano Zampini 
6894674ae819SStefano Zampini     /* Setup of Graph */
68954b2aedd3SStefano Zampini     pcbddc->mat_graph->commsizelimit = 0; /* don't use the COMM_SELF variant of the graph */
68969566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
6897674ae819SStefano Zampini 
68984f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
68994f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
690020c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
69014f1b2e48SStefano Zampini 
69029566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
69039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
690420c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
69054f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
69064f1b2e48SStefano Zampini         const PetscInt *idxs;
69074f1b2e48SStefano Zampini         PetscInt        nl, j;
69084f1b2e48SStefano Zampini 
69099566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
69109566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
691171582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
69129566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
69134f1b2e48SStefano Zampini       }
691420c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
691520c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
69164f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
69174f1b2e48SStefano Zampini     }
69188af8fcf9SStefano Zampini   }
69194f1b2e48SStefano Zampini 
6920cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
6921674ae819SStefano Zampini     /* Graph's connected components analysis */
69229566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
692371582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
69244f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
69258af8fcf9SStefano Zampini   }
692666da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
69273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6928674ae819SStefano Zampini }
6929674ae819SStefano Zampini 
6930d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[])
6931d71ae5a4SJacob Faibussowitsch {
6932295df10fSStefano Zampini   PetscInt     i, j, n;
69339a7d3425SStefano Zampini   PetscScalar *alphas;
6934295df10fSStefano Zampini   PetscReal    norm, *onorms;
69359a7d3425SStefano Zampini 
69369a7d3425SStefano Zampini   PetscFunctionBegin;
6937295df10fSStefano Zampini   n = *nio;
69383ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
69399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
69409566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
694192cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
6942295df10fSStefano Zampini     onorms[0] = 0.0;
69439566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
6944295df10fSStefano Zampini   } else {
6945295df10fSStefano Zampini     onorms[0] = norm;
694692cccca0SStefano Zampini   }
6947295df10fSStefano Zampini 
69488c0031efSStefano Zampini   for (i = 1; i < n; i++) {
69499566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
69508c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
69519566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
69529566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
695392cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
6954295df10fSStefano Zampini       onorms[i] = 0.0;
69559566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
6956295df10fSStefano Zampini     } else {
6957295df10fSStefano Zampini       onorms[i] = norm;
695892cccca0SStefano Zampini     }
69599a7d3425SStefano Zampini   }
6960295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
6961295df10fSStefano Zampini   for (i = 0; i < n; i++) {
6962295df10fSStefano Zampini     if (onorms[i] == 0.0) {
6963295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
6964295df10fSStefano Zampini         if (onorms[j] != 0.0) {
69659566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
6966295df10fSStefano Zampini           onorms[j] = 0.0;
6967295df10fSStefano Zampini         }
6968295df10fSStefano Zampini       }
6969295df10fSStefano Zampini     }
6970295df10fSStefano Zampini   }
6971295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
69729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
69733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
69749a7d3425SStefano Zampini }
69759a7d3425SStefano Zampini 
6976d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void)
6977d71ae5a4SJacob Faibussowitsch {
6978e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
697957de7509SStefano Zampini   Mat                    A;
6980e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
6981e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
698252e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
698352e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
6984bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
698557de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
698627b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
698727b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
698827b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
698927b6a85dSStefano Zampini   MPI_Comm               subcomm;
6990a57a6d2fSStefano Zampini 
6991e7931f94SStefano Zampini   PetscFunctionBegin;
699257de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
69939566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
699428b400f6SJacob 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);
699557de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
699657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
699763a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
699857de7509SStefano Zampini 
699957de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
70009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
70019566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
70029566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
70039566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
7004bb360cb4SStefano Zampini   im_active = !!n;
70051c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
700657de7509SStefano Zampini   void_procs = size - active_procs;
700757de7509SStefano Zampini   /* get ranks of of non-active processes in mat communicator */
700857de7509SStefano Zampini   if (void_procs) {
700957de7509SStefano Zampini     PetscInt ncand;
701057de7509SStefano Zampini 
701157de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
70129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
70139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
701457de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
7015ad540459SPierre Jolivet       if (!procs_candidates[i]) procs_candidates[ncand++] = i;
701657de7509SStefano Zampini     }
701757de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
701857de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
701957de7509SStefano Zampini   }
702057de7509SStefano Zampini 
7021bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
70229dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
70239566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
7024bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
702514f0bfb9SStefano Zampini     PetscInt issize, isidx, dest;
702614f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
702714f0bfb9SStefano Zampini     else dest = rank;
702857de7509SStefano Zampini     if (im_active) {
702957de7509SStefano Zampini       issize = 1;
703057de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
703114f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
703257de7509SStefano Zampini       } else {
703314f0bfb9SStefano Zampini         isidx = dest;
703457de7509SStefano Zampini       }
703557de7509SStefano Zampini     } else {
703657de7509SStefano Zampini       issize = 0;
703757de7509SStefano Zampini       isidx  = -1;
703857de7509SStefano Zampini     }
7039bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
70409566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
70419566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
70423ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
704357de7509SStefano Zampini   }
70449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-matis_partitioning_use_vwgt", &use_vwgt, NULL));
70459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-matis_partitioning_threshold", &threshold, NULL));
704627b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7047e7931f94SStefano Zampini 
7048e7931f94SStefano Zampini   /* Get info on mapping */
70499566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
70509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7051e7931f94SStefano Zampini 
7052e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
70539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7054e7931f94SStefano Zampini   xadj[0] = 0;
7055e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
70569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
70579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
70589566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
705927b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
70609371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7061e7931f94SStefano Zampini 
706227b6a85dSStefano Zampini   xadj_count = 0;
70632b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
706427b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
706527b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7066d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7067d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7068d023bfaeSStefano Zampini         xadj_count++;
706927b6a85dSStefano Zampini         break;
707027b6a85dSStefano Zampini       }
7071e7931f94SStefano Zampini     }
7072e7931f94SStefano Zampini   }
7073d023bfaeSStefano Zampini   xadj[1] = xadj_count;
70749566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
70759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
70769566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7077e7931f94SStefano Zampini 
70789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7079e7931f94SStefano Zampini 
708027b6a85dSStefano Zampini   /* Restrict work on active processes only */
70819566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
708227b6a85dSStefano Zampini   if (void_procs) {
70839566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
70849566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
70859566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
708627b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
708727b6a85dSStefano Zampini   } else {
708827b6a85dSStefano Zampini     psubcomm = NULL;
708927b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
709027b6a85dSStefano Zampini   }
709127b6a85dSStefano Zampini 
709227b6a85dSStefano Zampini   v_wgt = NULL;
709327b6a85dSStefano Zampini   if (!color) {
70949566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
70959566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
70969566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7097c8587f34SStefano Zampini   } else {
709852e5ac9dSStefano Zampini     Mat             subdomain_adj;
709952e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
710052e5ac9dSStefano Zampini     MatPartitioning partitioner;
710127b6a85dSStefano Zampini     PetscInt        rstart = 0, rend = 0;
710252e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
710357de7509SStefano Zampini     PetscMPIInt     size;
7104b0c7d250SStefano Zampini     PetscBool       aggregate;
7105b0c7d250SStefano Zampini 
71069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
710727b6a85dSStefano Zampini     if (void_procs) {
710827b6a85dSStefano Zampini       PetscInt prank = rank;
71099566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
71109566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
711148a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
71129566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
711327b6a85dSStefano Zampini     } else {
711427b6a85dSStefano Zampini       oldranks = NULL;
711527b6a85dSStefano Zampini     }
7116b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
711727b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7118b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7119b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7120b0c7d250SStefano Zampini       PetscScalar *vals;
7121b0c7d250SStefano Zampini 
71229566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7123b0c7d250SStefano Zampini       lrows = 0;
7124b0c7d250SStefano Zampini       if (nrank < redprocs) {
7125b0c7d250SStefano Zampini         lrows = size / redprocs;
7126b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7127b0c7d250SStefano Zampini       }
71289566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
71299566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
71309566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
71319566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7132b0c7d250SStefano Zampini       row   = nrank;
7133b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7134b0c7d250SStefano Zampini       cols  = adjncy;
71359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7136b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
71379566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
71389566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
71399566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
71409566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
71419566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
71429566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
71439566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
714427b6a85dSStefano Zampini       if (use_vwgt) {
714527b6a85dSStefano Zampini         Vec                v;
714627b6a85dSStefano Zampini         const PetscScalar *array;
714727b6a85dSStefano Zampini         PetscInt           nl;
714827b6a85dSStefano Zampini 
71499566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
71509566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
71519566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
71529566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
71539566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
71549566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
71559566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
715622db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
71579566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
71589566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
715927b6a85dSStefano Zampini       }
7160b0c7d250SStefano Zampini     } else {
71619566063dSJacob Faibussowitsch       PetscCall(MatCreateMPIAdj(subcomm, 1, (PetscInt)size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
716227b6a85dSStefano Zampini       if (use_vwgt) {
71639566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7164bb360cb4SStefano Zampini         v_wgt[0] = n;
716527b6a85dSStefano Zampini       }
7166b0c7d250SStefano Zampini     }
71679566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7168e7931f94SStefano Zampini 
7169e7931f94SStefano Zampini     /* Partition */
71709566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7171ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
71729566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7173ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
71749566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7175ce64c636SStefano Zampini #else
71769566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7177ce64c636SStefano Zampini #endif
71789566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
71791baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
718057de7509SStefano Zampini     *n_subdomains = PetscMin((PetscInt)size, *n_subdomains);
71819566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
71829566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
71839566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
71849566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7185e7931f94SStefano Zampini 
718652e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
71879566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
71889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
71899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
719057de7509SStefano Zampini     if (!aggregate) {
719157de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
71926bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
719357de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
719427b6a85dSStefano Zampini       } else if (oldranks) {
7195b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
719627b6a85dSStefano Zampini       } else {
719727b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
719857de7509SStefano Zampini       }
719928143c3dSStefano Zampini     } else {
72007fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7201b0c7d250SStefano Zampini       PetscMPIInt  tag;
7202b0c7d250SStefano Zampini       MPI_Request *reqs;
7203b0c7d250SStefano Zampini 
72049566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
72059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
720648a46eb9SPierre Jolivet       for (i = rstart; i < rend; i++) PetscCallMPI(MPI_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
72079566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
72089566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Waitall(rend - rstart, reqs, MPI_STATUSES_IGNORE));
72099566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
721057de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
72116bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
72127fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
721327b6a85dSStefano Zampini       } else if (oldranks) {
72147fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
721527b6a85dSStefano Zampini       } else {
72167fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
721728143c3dSStefano Zampini       }
721857de7509SStefano Zampini     }
72199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7220e7931f94SStefano Zampini     /* clean up */
72219566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
72229566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
72239566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
72249566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
7225e7931f94SStefano Zampini   }
72269566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
72279566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
7228e7931f94SStefano Zampini 
7229e7931f94SStefano Zampini   /* assemble parallel IS for sends */
7230e7931f94SStefano Zampini   i = 1;
723127b6a85dSStefano Zampini   if (!color) i = 0;
72329566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
72333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7234e7931f94SStefano Zampini }
7235e7931f94SStefano Zampini 
72369371c9d4SSatish Balay typedef enum {
72379371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
72389371c9d4SSatish Balay   MATAIJ_PRIVATE,
72399371c9d4SSatish Balay   MATBAIJ_PRIVATE,
72409371c9d4SSatish Balay   MATSBAIJ_PRIVATE
72419371c9d4SSatish Balay } MatTypePrivate;
7242e7931f94SStefano Zampini 
7243d71ae5a4SJacob Faibussowitsch 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[])
7244d71ae5a4SJacob Faibussowitsch {
724570cf5478SStefano Zampini   Mat                    local_mat;
7246e7931f94SStefano Zampini   IS                     is_sends_internal;
72479d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
72481ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
72499d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
7250e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
7251e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
7252e7931f94SStefano Zampini   const PetscInt        *is_indices;
7253e7931f94SStefano Zampini   MatType                new_local_type;
7254e7931f94SStefano Zampini   /* buffers */
7255e7931f94SStefano Zampini   PetscInt          *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
725628143c3dSStefano Zampini   PetscInt          *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
72579d30be91SStefano Zampini   PetscInt          *recv_buffer_idxs_local;
72581683a169SBarry Smith   PetscScalar       *ptr_vals, *recv_buffer_vals;
72591683a169SBarry Smith   const PetscScalar *send_buffer_vals;
72601ae86dd6SStefano Zampini   PetscScalar       *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
7261e7931f94SStefano Zampini   /* MPI */
726228143c3dSStefano Zampini   MPI_Comm     comm, comm_n;
726328143c3dSStefano Zampini   PetscSubcomm subcomm;
7264e569e4e1SStefano Zampini   PetscMPIInt  n_sends, n_recvs, size;
726528143c3dSStefano Zampini   PetscMPIInt *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
726628143c3dSStefano Zampini   PetscMPIInt *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
72671ae86dd6SStefano Zampini   PetscMPIInt  len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
72681ae86dd6SStefano Zampini   MPI_Request *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
72691ae86dd6SStefano Zampini   MPI_Request *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
7270e7931f94SStefano Zampini 
7271e7931f94SStefano Zampini   PetscFunctionBegin;
727257de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
72739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
72745f80ce2aSJacob 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);
727557de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
727657de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
727757de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
727857de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
727957de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
72801ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
72811ae86dd6SStefano Zampini   if (nvecs) {
728208401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
72831ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
72841ae86dd6SStefano Zampini   }
728557de7509SStefano Zampini   /* further checks */
72869566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
72879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
72885f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
72899566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
72905f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
729157de7509SStefano Zampini   if (reuse && *mat_n) {
729270cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
729357de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
72949566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
72955f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
72969566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
72979566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
729863a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
729963a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
730070cf5478SStefano Zampini   }
73019566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
7302064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
730357de7509SStefano Zampini 
7304e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
7305e7931f94SStefano Zampini   if (!is_sends) {
73065f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
73079566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
7308c8587f34SStefano Zampini   } else {
73099566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
7310e7931f94SStefano Zampini     is_sends_internal = is_sends;
7311c8587f34SStefano Zampini   }
7312e7931f94SStefano Zampini 
7313e7931f94SStefano Zampini   /* get comm */
73149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7315e7931f94SStefano Zampini 
7316e7931f94SStefano Zampini   /* compute number of sends */
73179566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
73189566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
7319e7931f94SStefano Zampini 
7320e7931f94SStefano Zampini   /* compute number of receives */
73219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
73229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
73239566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
73249566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
7325e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
73269566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
73279566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
7328e7931f94SStefano Zampini 
732928143c3dSStefano Zampini   /* restrict comm if requested */
73300a545947SLisandro Dalcin   subcomm     = NULL;
733128143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
733228143c3dSStefano Zampini   if (restrict_comm) {
7333779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
7334779c1cceSStefano Zampini 
733528143c3dSStefano Zampini     color = 0;
733653a05cb3SStefano Zampini     if (restrict_full) {
73376aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
733853a05cb3SStefano Zampini     } else {
73396aad120cSJose 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 */
734053a05cb3SStefano Zampini     }
73411c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
7342e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
734328143c3dSStefano Zampini     /* check if reuse has been requested */
734457de7509SStefano Zampini     if (reuse) {
734528143c3dSStefano Zampini       if (*mat_n) {
734628143c3dSStefano Zampini         PetscMPIInt subcommsize2;
73479566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
73485f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
734928143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
735028143c3dSStefano Zampini       } else {
735128143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
735228143c3dSStefano Zampini       }
735328143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
7354779c1cceSStefano Zampini       PetscMPIInt rank;
7355779c1cceSStefano Zampini 
73569566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
73579566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
73589566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
73599566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
7360306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
736128143c3dSStefano Zampini     }
736228143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
736328143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
736428143c3dSStefano Zampini   } else {
736528143c3dSStefano Zampini     comm_n = comm;
736628143c3dSStefano Zampini   }
736728143c3dSStefano Zampini 
7368e7931f94SStefano Zampini   /* prepare send/receive buffers */
73699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
73709566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
73719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
73729566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
737348a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
7374e7931f94SStefano Zampini 
737528143c3dSStefano Zampini   /* Get data from local matrices */
7376e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
7377e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
7378e7931f94SStefano Zampini   /*
7379e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
7380e7931f94SStefano Zampini        send_buffer_idxs should contain:
7381e7931f94SStefano Zampini        - MatType_PRIVATE type
7382e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
7383e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
7384e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
7385e7931f94SStefano Zampini     */
7386e432b41dSStefano Zampini   {
7387e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
7388e432b41dSStefano Zampini 
73899566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
73909566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
73919566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
73929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
7393e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
7394e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
73959566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
73969566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
73979566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
73989566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
7399e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
7400e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
7401e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
7402c8587f34SStefano Zampini     }
7403c8587f34SStefano Zampini   }
74049566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
740528143c3dSStefano Zampini   /* additional is (if any) */
740628143c3dSStefano Zampini   if (nis) {
740728143c3dSStefano Zampini     PetscMPIInt psum;
740828143c3dSStefano Zampini     PetscInt    j;
740928143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
741028143c3dSStefano Zampini       PetscInt plen;
74119566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
74129566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
74136aad120cSJose E. Roman       psum += len + 1; /* indices + length */
741428143c3dSStefano Zampini     }
74159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
741628143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
741728143c3dSStefano Zampini       PetscInt        plen;
741828143c3dSStefano Zampini       const PetscInt *is_array_idxs;
74199566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
742028143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
74219566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
74229566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
74239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
74246aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
742528143c3dSStefano Zampini     }
7426ad540459SPierre Jolivet     for (i = 0; i < n_sends; i++) ilengths_idxs_is[is_indices[i]] = psum;
74279566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
742828143c3dSStefano Zampini   }
74299566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
743028143c3dSStefano Zampini 
7431e7931f94SStefano Zampini   buf_size_idxs    = 0;
7432e7931f94SStefano Zampini   buf_size_vals    = 0;
743328143c3dSStefano Zampini   buf_size_idxs_is = 0;
74341ae86dd6SStefano Zampini   buf_size_vecs    = 0;
7435e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7436e7931f94SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
7437e7931f94SStefano Zampini     buf_size_vals += (PetscInt)olengths_vals[i];
743828143c3dSStefano Zampini     if (nis) buf_size_idxs_is += (PetscInt)olengths_idxs_is[i];
74391ae86dd6SStefano Zampini     if (nvecs) buf_size_vecs += (PetscInt)olengths_idxs[i];
7440e7931f94SStefano Zampini   }
74419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
74429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
74439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
74449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
7445e7931f94SStefano Zampini 
7446e7931f94SStefano Zampini   /* get new tags for clean communications */
74479566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
74489566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
74499566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
74509566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
7451e7931f94SStefano Zampini 
7452e7931f94SStefano Zampini   /* allocate for requests */
74539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
74549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
74559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
74569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
74579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
74589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
74599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
74609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
7461e7931f94SStefano Zampini 
7462e7931f94SStefano Zampini   /* communications */
7463e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
7464e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
746528143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
74661ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
7467e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7468e7931f94SStefano Zampini     source_dest = onodes[i];
74699566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, source_dest, tag_idxs, comm, &recv_req_idxs[i]));
74709566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, source_dest, tag_vals, comm, &recv_req_vals[i]));
7471e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7472e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
747328143c3dSStefano Zampini     if (nis) {
747457de7509SStefano Zampini       source_dest = onodes_is[i];
74759566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_idxs_is, olengths_idxs_is[i], MPIU_INT, source_dest, tag_idxs_is, comm, &recv_req_idxs_is[i]));
747628143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
747728143c3dSStefano Zampini     }
74781ae86dd6SStefano Zampini     if (nvecs) {
74791ae86dd6SStefano Zampini       source_dest = onodes[i];
74809566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &recv_req_vecs[i]));
74811ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
74821ae86dd6SStefano Zampini     }
7483e7931f94SStefano Zampini   }
7484e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
74859566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
74869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
74879566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend((PetscScalar *)send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
748848a46eb9SPierre 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]));
74891ae86dd6SStefano Zampini     if (nvecs) {
74909566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
74919566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
74921ae86dd6SStefano Zampini     }
7493e7931f94SStefano Zampini   }
74949566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
74959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
7496e7931f94SStefano Zampini 
7497e7931f94SStefano Zampini   /* assemble new l2g map */
74989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
7499e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
75009d30be91SStefano Zampini   new_local_rows = 0;
7501e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75029d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7503e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7504e7931f94SStefano Zampini   }
75059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
7506e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
75079d30be91SStefano Zampini   new_local_rows = 0;
7508e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75099566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
75109d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
7511e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7512e7931f94SStefano Zampini   }
75139566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
75149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
75159566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
7516e7931f94SStefano Zampini 
7517e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
7518e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
7519e7931f94SStefano 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) */
7520e7931f94SStefano Zampini   if (n_recvs) {
752128143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
7522e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
7523e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
7524e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
7525e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
7526e7931f94SStefano Zampini         break;
7527e7931f94SStefano Zampini       }
7528e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
7529e7931f94SStefano Zampini     }
7530e7931f94SStefano Zampini     switch (new_local_type_private) {
753128143c3dSStefano Zampini     case MATDENSE_PRIVATE:
7532e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7533e7931f94SStefano Zampini       bs             = 1;
7534e7931f94SStefano Zampini       break;
7535e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
7536e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
7537e7931f94SStefano Zampini       bs             = 1;
7538e7931f94SStefano Zampini       break;
7539d71ae5a4SJacob Faibussowitsch     case MATBAIJ_PRIVATE:
7540d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQBAIJ;
7541d71ae5a4SJacob Faibussowitsch       break;
7542d71ae5a4SJacob Faibussowitsch     case MATSBAIJ_PRIVATE:
7543d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQSBAIJ;
7544d71ae5a4SJacob Faibussowitsch       break;
7545d71ae5a4SJacob Faibussowitsch     default:
7546d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
7547e7931f94SStefano Zampini     }
7548ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
7549ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
755028143c3dSStefano Zampini     bs             = 1;
7551e7931f94SStefano Zampini   }
7552e7931f94SStefano Zampini 
755370cf5478SStefano Zampini   /* create MATIS object if needed */
755457de7509SStefano Zampini   if (!reuse) {
75559566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
75569566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
755770cf5478SStefano Zampini   } else {
755870cf5478SStefano Zampini     /* it also destroys the local matrices */
755957de7509SStefano Zampini     if (*mat_n) {
75609566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
756157de7509SStefano Zampini     } else { /* this is a fake object */
75629566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
756357de7509SStefano Zampini     }
756470cf5478SStefano Zampini   }
75659566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
75669566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
75679d30be91SStefano Zampini 
75689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
75699d30be91SStefano Zampini 
75709d30be91SStefano Zampini   /* Global to local map of received indices */
75719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
75729566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
75739566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
75749d30be91SStefano Zampini 
75759d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
75769d30be91SStefano Zampini   buf_size_idxs = 0;
75779d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
75789d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
75799d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
75809d30be91SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
75819d30be91SStefano Zampini   }
75829566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
75839d30be91SStefano Zampini 
75849d30be91SStefano Zampini   /* set preallocation */
75859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
75869d30be91SStefano Zampini   if (!newisdense) {
75870a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
75889d30be91SStefano Zampini 
75899d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
759048a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
75919d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
75929d30be91SStefano Zampini       PetscInt j;
75939d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
7594ad540459SPierre Jolivet         for (j = 0; j < *(ptr_idxs + 1); j++) new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1);
75959d30be91SStefano Zampini       } else {
75969d30be91SStefano Zampini         /* TODO */
75979d30be91SStefano Zampini       }
75989d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
75999d30be91SStefano Zampini     }
76009d30be91SStefano Zampini     if (new_local_nnz) {
76019d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
76029566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
76039d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
76049566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
76059d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
76069566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
76079d30be91SStefano Zampini     } else {
76089566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
76099d30be91SStefano Zampini     }
76109566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
76119d30be91SStefano Zampini   } else {
76129566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
76139d30be91SStefano Zampini   }
7614e7931f94SStefano Zampini 
7615e7931f94SStefano Zampini   /* set values */
7616e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
76179d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
7618e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
7619e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
76209566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
76219566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
76229566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
76239566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
76249566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
762528143c3dSStefano Zampini     } else {
762628143c3dSStefano Zampini       /* TODO */
7627e7931f94SStefano Zampini     }
7628e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
7629e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
7630e7931f94SStefano Zampini   }
76319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
76329566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
76339566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
76349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
76359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
76369566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
7637e7931f94SStefano Zampini 
7638dfd14d43SStefano Zampini #if 0
763928143c3dSStefano Zampini   if (!restrict_comm) { /* check */
7640e7931f94SStefano Zampini     Vec       lvec,rvec;
7641e7931f94SStefano Zampini     PetscReal infty_error;
7642e7931f94SStefano Zampini 
76439566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
76449566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
76459566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
76469566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
76479566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
76489566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
76499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
76509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
76519566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
7652e7931f94SStefano Zampini   }
765328143c3dSStefano Zampini #endif
7654e7931f94SStefano Zampini 
765528143c3dSStefano Zampini   /* assemble new additional is (if any) */
765628143c3dSStefano Zampini   if (nis) {
765728143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
765828143c3dSStefano Zampini 
76599566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
76609566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
766128143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
766228143c3dSStefano Zampini     psum     = 0;
766328143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
766428143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
766528143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
766628143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
766728143c3dSStefano Zampini         psum += plen;
766828143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
766928143c3dSStefano Zampini       }
767028143c3dSStefano Zampini     }
76719566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
76729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
7673ad540459SPierre Jolivet     for (i = 1; i < nis; i++) temp_idxs[i] = temp_idxs[i - 1] + count_is[i - 1];
76749566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
767528143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
767628143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
767728143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
767828143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
76799566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
768028143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
768128143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
768228143c3dSStefano Zampini       }
768328143c3dSStefano Zampini     }
768428143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
76859566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
76869566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
76879566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
768828143c3dSStefano Zampini     }
76899566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
76909566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
76919566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
769228143c3dSStefano Zampini   }
7693e7931f94SStefano Zampini   /* free workspace */
76949566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
76959566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
76969566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
76979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
7698e7931f94SStefano Zampini   if (isdense) {
76999566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
77009566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
77019566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
7702e7931f94SStefano Zampini   } else {
77039566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
7704e7931f94SStefano Zampini   }
770528143c3dSStefano Zampini   if (nis) {
77069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
77079566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
770828143c3dSStefano Zampini   }
77091ae86dd6SStefano Zampini 
77101ae86dd6SStefano Zampini   if (nvecs) {
77119566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
77129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
77139566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
77149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
77159566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
77169566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
77179566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
77181ae86dd6SStefano Zampini     /* set values */
77191ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
77201ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
77219566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
77221ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
77231ae86dd6SStefano Zampini       PetscInt j;
7724ad540459SPierre Jolivet       for (j = 0; j < *(ptr_idxs + 1); j++) send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j);
77251ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
77261ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
77271ae86dd6SStefano Zampini     }
77289566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
77299566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
77309566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
77311ae86dd6SStefano Zampini   }
77321ae86dd6SStefano Zampini 
77339566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
77349566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
77359566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
77369566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
77379566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
77389566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
77399566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
77409566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
77419566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
77429566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
77439566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
77449566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
77459566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
77469566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
77479566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
774828143c3dSStefano Zampini   if (nis) {
77499566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
77509566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
77519566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
775228143c3dSStefano Zampini   }
77539566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
77546aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
77559566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
775648a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
77571ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
77589566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
77591ae86dd6SStefano Zampini     }
776053a05cb3SStefano Zampini     *mat_n = NULL;
776128143c3dSStefano Zampini   }
77623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7763e7931f94SStefano Zampini }
7764a57a6d2fSStefano Zampini 
776512edc857SStefano Zampini /* temporary hack into ksp private data structure */
7766af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
776712edc857SStefano Zampini 
7768d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, PetscScalar *coarse_submat_vals)
7769d71ae5a4SJacob Faibussowitsch {
7770c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7771c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
777220a2ab83SStefano Zampini   Mat                    coarse_mat, coarse_mat_is, coarse_submat_dense;
77731ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
77741e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
77759881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
777620a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
77774f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
77786e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
777930368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
7780e569e4e1SStefano Zampini   PetscInt               coarse_eqs_per_proc;
7781f9eb5b7dSStefano Zampini   PC                     pc_temp;
7782c8587f34SStefano Zampini   PCType                 coarse_pc_type;
7783c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
7784f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
77857274672aSStefano Zampini   PetscBool              coarse_reuse;
77861e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
778768457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
778822bc73bbSStefano Zampini   PetscScalar           *array;
778957de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
779057de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
7791e569e4e1SStefano Zampini   PetscMPIInt            size;
7792fdc09c96SStefano Zampini 
7793c8587f34SStefano Zampini   PetscFunctionBegin;
77949566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
7795c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
779668457ee5SStefano 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 */
7797fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
77985a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
77997de4f681Sstefano_zampini 
78007de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
7801fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
78029566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
78039566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
7804f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
7805fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
780651bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
780751bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
78089566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
7809fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
7810fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
7811fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
7812f4ddd8eeSStefano Zampini       }
7813fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
7814fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
7815f4ddd8eeSStefano Zampini     }
781670cf5478SStefano Zampini     /* reset any subassembling information */
781748a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
78186e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
7819fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
7820f4ddd8eeSStefano Zampini   }
782157de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
78229566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
78239566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
782457de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
782518a45a71SStefano Zampini   } else {
782657de7509SStefano Zampini     coarse_mat       = NULL;
782757de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
78286e683305SStefano Zampini   }
7829e7931f94SStefano Zampini 
7830abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
78319566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
78329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
7833abbbba34SStefano Zampini 
7834abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
78359566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, coarse_submat_vals, &coarse_submat_dense));
78369566063dSJacob 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));
78379566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat_dense));
78389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
78399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
78409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_submat_dense));
7841abbbba34SStefano Zampini 
784257de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
784357de7509SStefano Zampini   im_active = !!(pcis->n);
78441c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
784557de7509SStefano Zampini 
784614f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
784728d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
784857de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
78499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
785057de7509SStefano Zampini   coarse_mat_is        = NULL;
785157de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
785257de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
7853e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
7854ce64c636SStefano Zampini   if (coarse_eqs_per_proc < 0) coarse_eqs_per_proc = pcbddc->coarse_size;
785557de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
7856e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
785757de7509SStefano Zampini   if (multilevel_requested) {
785857de7509SStefano Zampini     ncoarse    = active_procs / pcbddc->coarsening_ratio;
785957de7509SStefano Zampini     restr      = PETSC_FALSE;
786057de7509SStefano Zampini     full_restr = PETSC_FALSE;
786157de7509SStefano Zampini   } else {
7862e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
786357de7509SStefano Zampini     restr      = PETSC_TRUE;
786457de7509SStefano Zampini     full_restr = PETSC_TRUE;
786557de7509SStefano Zampini   }
7866e569e4e1SStefano Zampini   if (!pcbddc->coarse_size || size == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
786757de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
786857de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
7869a198735bSStefano Zampini     if (pcbddc->coarsening_ratio > 1) {
7870bb360cb4SStefano Zampini       if (multilevel_requested) {
78719566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7872bb360cb4SStefano Zampini       } else {
78739566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
7874bb360cb4SStefano Zampini       }
7875a198735bSStefano Zampini     } else {
78767de4f681Sstefano_zampini       PetscMPIInt rank;
787728d58a37SPierre Jolivet 
78789566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
7879e569e4e1SStefano Zampini       have_void = (active_procs == (PetscInt)size) ? PETSC_FALSE : PETSC_TRUE;
78809566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
7881a198735bSStefano Zampini     }
788257de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
788357de7509SStefano Zampini     PetscInt psum;
788457de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
788557de7509SStefano Zampini     else psum = 0;
78861c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
7887075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
788857de7509SStefano Zampini   }
788957de7509SStefano Zampini   /* determine if we can go multilevel */
789057de7509SStefano Zampini   if (multilevel_requested) {
789157de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
789257de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
789357de7509SStefano Zampini   }
789457de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
789557de7509SStefano Zampini 
7896e4d548c7SStefano Zampini   /* dump subassembling pattern */
789748a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
78986e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
78991e0482f5SStefano Zampini   nedcfield = -1;
79004f819b78SStefano Zampini   corners   = NULL;
79018966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
79026e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
79036e683305SStefano Zampini     const PetscInt        *idxs;
79046e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
79056e683305SStefano Zampini 
79066e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
79079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
79086e683305SStefano Zampini     /* allocate space for temporary storage */
79099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
79109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
79116e683305SStefano Zampini     /* allocate for IS array */
79126e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
79131e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
79141e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
79151e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
79161e0482f5SStefano Zampini       } else {
79171e0482f5SStefano Zampini         nedcfield = 0;
791863a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
79191e0482f5SStefano Zampini         nisdofs = 1;
79201e0482f5SStefano Zampini       }
79211e0482f5SStefano Zampini     }
79226e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
792327b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
792430368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
79259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
79266e683305SStefano Zampini     /* dofs splitting */
79276e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
79289566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
79291e0482f5SStefano Zampini       if (nedcfield != i) {
79309566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
79319566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
79329566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
79339566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
79341e0482f5SStefano Zampini       } else {
79359566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
79369566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
79379566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
793863a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
79399566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
79401e0482f5SStefano Zampini       }
79419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
79429566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
79439566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
79446e683305SStefano Zampini     }
79456e683305SStefano Zampini     /* neumann boundaries */
79466e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
79479566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
79489566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
79499566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
79509566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
79519566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
79529566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
79539566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
79549566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
79556e683305SStefano Zampini     }
79564f819b78SStefano Zampini     /* coordinates */
79574f819b78SStefano Zampini     if (pcbddc->corner_selected) {
79589566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
79599566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
79609566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
79619566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
796263a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
79639566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
79649566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
79659566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
79669566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
79674f819b78SStefano Zampini     }
79689566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
79699566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
79709566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
79716e683305SStefano Zampini   } else {
79726e683305SStefano Zampini     nis     = 0;
79736e683305SStefano Zampini     nisdofs = 0;
79746e683305SStefano Zampini     nisneu  = 0;
797530368db7SStefano Zampini     nisvert = 0;
79766e683305SStefano Zampini     isarray = NULL;
79776e683305SStefano Zampini   }
79786e683305SStefano Zampini   /* destroy no longer needed map */
79799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
79806e683305SStefano Zampini 
798157de7509SStefano Zampini   /* subassemble */
798257de7509SStefano Zampini   if (multilevel_allowed) {
79831ae86dd6SStefano Zampini     Vec       vp[1];
79841ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
798557de7509SStefano Zampini     PetscBool reuse, reuser;
79861ae86dd6SStefano Zampini 
798757de7509SStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
798857de7509SStefano Zampini     else reuse = PETSC_FALSE;
79891c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&reuse, &reuser, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
79901ae86dd6SStefano Zampini     vp[0] = NULL;
79911ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
79929566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
79939566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
79949566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
79951ae86dd6SStefano Zampini       nvecs = 1;
79961ae86dd6SStefano Zampini 
79971ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
7998a198735bSStefano Zampini         Mat      B, loc_divudotp;
79991ae86dd6SStefano Zampini         Vec      v, p;
80001ae86dd6SStefano Zampini         IS       dummy;
80011ae86dd6SStefano Zampini         PetscInt np;
80021ae86dd6SStefano Zampini 
80039566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
80049566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
80059566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
80069566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
80079566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
80089566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
80099566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
80109566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
80119566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
80129566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
80139566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
80149566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
80159566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
80169566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
80179566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
80189566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
801974e2c79eSStefano Zampini       }
80201ae86dd6SStefano Zampini     }
80211ae86dd6SStefano Zampini     if (reuser) {
80229566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
802374e2c79eSStefano Zampini     } else {
80249566063dSJacob Faibussowitsch       PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
80251ae86dd6SStefano Zampini     }
80261ae86dd6SStefano Zampini     if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
80271683a169SBarry Smith       PetscScalar       *arraym;
80281683a169SBarry Smith       const PetscScalar *arrayv;
80291ae86dd6SStefano Zampini       PetscInt           nl;
80309566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vp[0], &nl));
80319566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
80329566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
80339566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(vp[0], &arrayv));
80349566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(arraym, arrayv, nl));
80359566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
80369566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
80379566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vp[0]));
8038a198735bSStefano Zampini     } else {
80399566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
80401ae86dd6SStefano Zampini     }
80411ae86dd6SStefano Zampini   } else {
80429566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
80436e683305SStefano Zampini   }
804457de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
804557de7509SStefano Zampini     if (!multilevel_allowed) {
80469566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
80476e683305SStefano Zampini     } else {
804857de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
804957de7509SStefano Zampini       if (coarse_mat_is) {
805028b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
80519566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
805257de7509SStefano Zampini         coarse_mat = coarse_mat_is;
805357de7509SStefano Zampini       }
8054779c1cceSStefano Zampini     }
8055779c1cceSStefano Zampini   }
80569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
80579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
80586e683305SStefano Zampini 
80596e683305SStefano Zampini   /* create local to global scatters for coarse problem */
806068457ee5SStefano Zampini   if (compute_vecs) {
80616e683305SStefano Zampini     PetscInt lrows;
80629566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
806357de7509SStefano Zampini     if (coarse_mat) {
80649566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
80656e683305SStefano Zampini     } else {
80666e683305SStefano Zampini       lrows = 0;
80676e683305SStefano Zampini     }
80689566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
80699566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
80709566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
80719566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
80729566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
80736e683305SStefano Zampini   }
80749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8075c8587f34SStefano Zampini 
8076f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8077f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8078f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8079f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8080f9eb5b7dSStefano Zampini   } else {
8081f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8082f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8083c8587f34SStefano Zampini   }
8084c8587f34SStefano Zampini 
80856e683305SStefano Zampini   /* print some info if requested */
80866e683305SStefano Zampini   if (pcbddc->dbg_flag) {
80876e683305SStefano Zampini     if (!multilevel_allowed) {
80889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
80896e683305SStefano Zampini       if (multilevel_requested) {
809063a3b9bcSJacob 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));
80916e683305SStefano Zampini       } else if (pcbddc->max_levels) {
809263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
80936e683305SStefano Zampini       }
80949566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
80956e683305SStefano Zampini     }
80966e683305SStefano Zampini   }
80976e683305SStefano Zampini 
80981e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
80991e0482f5SStefano Zampini   coarseG = NULL;
81001e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
81011e0482f5SStefano Zampini     MPI_Comm ccomm;
81021e0482f5SStefano Zampini     if (coarse_mat) {
81031e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
81041e0482f5SStefano Zampini     } else {
81051e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
81061e0482f5SStefano Zampini     }
81079566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
81081e0482f5SStefano Zampini   }
81091e0482f5SStefano Zampini 
8110f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
811157de7509SStefano Zampini   if (coarse_mat) {
811228d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
81136a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8114b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
81157274672aSStefano Zampini 
81166e683305SStefano Zampini     if (pcbddc->dbg_flag) {
811757de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
81189566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
81196e683305SStefano Zampini     }
8120f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8121312be037SStefano Zampini       char   prefix[256], str_level[16];
8122e604994aSStefano Zampini       size_t len;
81231e0482f5SStefano Zampini 
81249566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
81259566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
81269566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
81279566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1));
81289566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
81299566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
81309566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
81319566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
81321e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
81339566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8134e604994aSStefano Zampini       /* prefix */
8135c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(prefix, "", sizeof(prefix)));
8136c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(str_level, "", sizeof(str_level)));
8137e604994aSStefano Zampini       if (!pcbddc->current_level) {
81389566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
81399566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8140c8587f34SStefano Zampini       } else {
81419566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8142312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8143312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8144a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
81459566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
81469566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)(pcbddc->current_level)));
81479566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8148e604994aSStefano Zampini       }
81499566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
81503e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
81519566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
81529566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
81539566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8154f9eb5b7dSStefano Zampini       /* allow user customization */
81559566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8156e569e4e1SStefano Zampini       /* get some info after set from options */
81579566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
815828d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
815928d58a37SPierre Jolivet       force = PETSC_FALSE;
81609566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
81619566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
81629566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
816328d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8164e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
81659566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
81669566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
81679566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
81689566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
81694f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8170d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8171dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8172dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8173d0609cedSBarry Smith           PetscOptionsEnd();
81744f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
81754f819b78SStefano Zampini         }
8176e569e4e1SStefano Zampini       }
81773e3c6dadSStefano Zampini     }
81783e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
81799566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
81803e3c6dadSStefano Zampini     if (nisdofs) {
81819566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
818248a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
81833e3c6dadSStefano Zampini     }
81843e3c6dadSStefano Zampini     if (nisneu) {
81859566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
81869566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8187312be037SStefano Zampini     }
818830368db7SStefano Zampini     if (nisvert) {
81899566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
81909566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
819130368db7SStefano Zampini     }
81921baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8193f9eb5b7dSStefano Zampini 
8194f9eb5b7dSStefano Zampini     /* get some info after set from options */
81959566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
81964f819b78SStefano Zampini 
8197b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
819848a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
819928d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
820028d58a37SPierre Jolivet     force = PETSC_FALSE;
82019566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
82029566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
820348a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
82049566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
82054f3a063dSStefano Zampini     if (isredundant) {
82064f3a063dSStefano Zampini       KSP inner_ksp;
82074f3a063dSStefano Zampini       PC  inner_pc;
82089326c5c6Sstefano_zampini 
82099566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
82109566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
82114f3a063dSStefano Zampini     }
8212f9eb5b7dSStefano Zampini 
821357de7509SStefano Zampini     /* parameters which miss an API */
82149566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
821557de7509SStefano Zampini     if (isbddc) {
8216720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
82177274672aSStefano Zampini 
8218720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
821957de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8220e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
822127b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
822227b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
8223a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
8224a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
8225a198735bSStefano Zampini         IS                     row, col;
8226a198735bSStefano Zampini         const PetscInt        *gidxs;
8227a198735bSStefano Zampini         PetscInt               n, st, M, N;
8228a198735bSStefano Zampini 
82299566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
82309566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
8231a198735bSStefano Zampini         st = st - n;
82329566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
82339566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
82349566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
82359566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
82369566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
82379566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
82389566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
82399566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
82409566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
82419566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
82429566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
82439566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
82449566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
82459566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
82469566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
82479566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
82489566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
82499566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
82509566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
82519566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
82529566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
82539566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
8254720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8255bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8256720d30f9SStefano Zampini       }
8257d4d8cf7bSStefano Zampini     }
82589881197aSStefano Zampini 
82593301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
82609566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
8261b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
8262b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
8263b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
8264b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
8265b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
8266b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
8267b94d7dedSBarry Smith 
826848a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
82696e683305SStefano Zampini     /* set operators */
82709566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
82719566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
82729566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
82731baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
82746e683305SStefano Zampini   }
82759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
82769566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
8277b1ecc7b1SStefano Zampini #if 0
8278b9b85e73SStefano Zampini   {
8279b9b85e73SStefano Zampini     PetscViewer viewer;
8280b9b85e73SStefano Zampini     char filename[256];
8281a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "coarse_mat_level%d.m",pcbddc->current_level));
82829566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
82839566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
82849566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
82859566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
82869566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
8287b9b85e73SStefano Zampini   }
8288b9b85e73SStefano Zampini #endif
8289f9eb5b7dSStefano Zampini 
82904f819b78SStefano Zampini   if (corners) {
82914f819b78SStefano Zampini     Vec             gv;
82924f819b78SStefano Zampini     IS              is;
82934f819b78SStefano Zampini     const PetscInt *idxs;
82944f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
82954f819b78SStefano Zampini     PetscScalar    *coords;
82964f819b78SStefano Zampini 
829728b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
82989566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
82999566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
83009566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
83019566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
83029566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
83039566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
83049566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
83059566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
83064f819b78SStefano Zampini 
83079566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
83089566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
83099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
83109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
83114f819b78SStefano Zampini     for (i = 0; i < n; i++) {
8312ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d];
83134f819b78SStefano Zampini     }
83149566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
83159566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
83164f819b78SStefano Zampini 
83179566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
83189566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
83199566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
83209566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
83219566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
83229566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
83239566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
83249566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
83254f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
83264f819b78SStefano Zampini       PC        coarse_pc;
83274f819b78SStefano Zampini       PetscBool isbddc;
83284f819b78SStefano Zampini 
83299566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
83309566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
83314f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
83324f819b78SStefano Zampini         PetscReal *realcoords;
83334f819b78SStefano Zampini 
83349566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
83354f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
83369566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
83374f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
83384f819b78SStefano Zampini #else
83394f819b78SStefano Zampini         realcoords = coords;
83404f819b78SStefano Zampini #endif
83419566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
83424f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
83439566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
83444f819b78SStefano Zampini #endif
83454f819b78SStefano Zampini       }
83464f819b78SStefano Zampini     }
83479566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
83489566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
83494f819b78SStefano Zampini   }
83509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
83514f819b78SStefano Zampini 
835298a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
835398a51de6SStefano Zampini     Vec crhs, csol;
835404708bb6SStefano Zampini 
83559566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
83569566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
835748a46eb9SPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &((pcbddc->coarse_ksp)->vec_sol), NULL));
835848a46eb9SPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &((pcbddc->coarse_ksp)->vec_rhs)));
8359b0f5fe93SStefano Zampini   }
83609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
8361b0f5fe93SStefano Zampini 
8362b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
8363b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
83649566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
836548a46eb9SPierre 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));
83669566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
83679566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
83689566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
83699566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
8370b0f5fe93SStefano Zampini     if (coarse_mat) {
8371b0f5fe93SStefano Zampini       Vec          nullv;
8372b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
8373b0f5fe93SStefano Zampini       PetscInt     nl;
8374b0f5fe93SStefano Zampini 
83759566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
83769566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
83779566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
83789566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
83799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
83809566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
83819566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
83829566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
83839566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
83849566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
8385b0f5fe93SStefano Zampini     }
8386b0f5fe93SStefano Zampini   }
83879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8388b0f5fe93SStefano Zampini 
83899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
8390b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
8391b0f5fe93SStefano Zampini     PetscBool ispreonly;
8392b0f5fe93SStefano Zampini 
8393b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
8394b0f5fe93SStefano Zampini       PetscBool isnull;
83957c625d9fSStefano Zampini 
83969566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
83971baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
8398bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
8399b0f5fe93SStefano Zampini     }
8400b0f5fe93SStefano Zampini     /* setup coarse ksp */
84019566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
8402cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
84039566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
84046e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
8405c8587f34SStefano Zampini       KSP         check_ksp;
84062b510759SStefano Zampini       KSPType     check_ksp_type;
8407c8587f34SStefano Zampini       PC          check_pc;
84086e683305SStefano Zampini       Vec         check_vec, coarse_vec;
84096a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
84102b510759SStefano Zampini       PetscInt    its;
84116e683305SStefano Zampini       PetscBool   compute_eigs;
84126e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
84136e683305SStefano Zampini       PetscInt    neigs;
84148e185a42SStefano Zampini       const char *prefix;
8415c8587f34SStefano Zampini 
84162b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
84179566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
84189566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
84199566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
84209566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
84219566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_DEFAULT, pcbddc->coarse_size));
8422e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
84239566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
84249566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
84252b510759SStefano Zampini       if (ispreonly) {
84262b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
84276e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
84282b510759SStefano Zampini       } else {
8429cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
84306e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
8431c8587f34SStefano Zampini       }
84329566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
84339566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
84349566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
84359566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
84369566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
84379566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
84389566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
84399566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
84409566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
84419566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
84429566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
8443c8587f34SStefano Zampini       /* create random vec */
84449566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
84459566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
84469566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
8447c8587f34SStefano Zampini       /* solve coarse problem */
84489566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
84499566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
8450cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
84516e683305SStefano Zampini       if (compute_eigs) {
84529566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
84539566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
84549566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
84551ae86dd6SStefano Zampini         if (neigs) {
84566e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
84576e683305SStefano Zampini           lambda_min = eigs_r[0];
84586e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
84592701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
84609566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
84619566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
8462cbcc2c2aSStefano Zampini             }
8463c8587f34SStefano Zampini           }
8464c8587f34SStefano Zampini         }
84651ae86dd6SStefano Zampini       }
8466cbcc2c2aSStefano Zampini 
8467c8587f34SStefano Zampini       /* check coarse problem residual error */
84686e683305SStefano Zampini       if (pcbddc->dbg_flag) {
84696e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
84709566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
84719566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
84729566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
84739566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
84749566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
84759566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
84769566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(pcbddc->coarse_ksp), dbg_viewer));
84779566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(check_pc), dbg_viewer));
847863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
847963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
848048a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
84816e683305SStefano Zampini         if (compute_eigs) {
84826e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
8483b03ebc13SStefano Zampini           KSPConvergedReason reason;
84849566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
84859566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
84869566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
84879566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
848863a3b9bcSJacob 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));
848948a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
84906e683305SStefano Zampini         }
84919566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
84929566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
84936e683305SStefano Zampini       }
84949566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
84959566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
84969566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
84976e683305SStefano Zampini       if (compute_eigs) {
84989566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
84999566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
8500c8587f34SStefano Zampini       }
85016e683305SStefano Zampini     }
85026e683305SStefano Zampini   }
85039566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
8504cbcc2c2aSStefano Zampini   /* print additional info */
8505cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
85066e683305SStefano Zampini     /* waits until all processes reaches this point */
85079566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
850863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
85099566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8510cbcc2c2aSStefano Zampini   }
8511cbcc2c2aSStefano Zampini 
85122b510759SStefano Zampini   /* free memory */
85139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
85149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
85153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8516c8587f34SStefano Zampini }
8517674ae819SStefano Zampini 
8518d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n)
8519d71ae5a4SJacob Faibussowitsch {
8520f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
8521f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
8522f34684f1SStefano Zampini   Mat_IS         *matis  = (Mat_IS *)pc->pmat->data;
8523dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
8524dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
852573be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
8526dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
8527f34684f1SStefano Zampini 
8528f34684f1SStefano Zampini   PetscFunctionBegin;
8529f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
853008401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
85319566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
85329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
85339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
85349566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)(pc->pmat)), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
85359566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
85369566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
85379566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
85389566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
853963a3b9bcSJacob 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);
85409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
85419566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
85429566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
85439566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
85449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
8545f34684f1SStefano Zampini 
8546f34684f1SStefano Zampini   /* check numbering */
8547f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
8548019a44ceSStefano Zampini     PetscScalar coarsesum, *array, *array2;
8549dc456d91SStefano Zampini     PetscInt    i;
8550b9b85e73SStefano Zampini     PetscBool   set_error = PETSC_FALSE, set_error_reduced = PETSC_FALSE;
8551f34684f1SStefano Zampini 
85529566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
85539566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
85549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse indices\n"));
85559566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
8556019a44ceSStefano Zampini     /* counter */
85579566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85589566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 1.0));
85599566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85609566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85619566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
85629566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
85639566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.0));
856448a46eb9SPierre 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));
85659566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
85669566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
85679566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85689566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85699566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85709566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
85719566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
85729566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec1_N, &array));
85739566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec2_N, &array2));
8574f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8575019a44ceSStefano Zampini       if (array[i] != 0.0 && array[i] != array2[i]) {
85762c66d082SStefano Zampini         PetscInt owned = (PetscInt)PetscRealPart(array[i]), gi;
857775c01103SStefano Zampini         PetscInt neigh = (PetscInt)PetscRealPart(array2[i]);
8578b9b85e73SStefano Zampini         set_error      = PETSC_TRUE;
85799566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, 1, &i, &gi));
858063a3b9bcSJacob 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));
8581f34684f1SStefano Zampini       }
8582f34684f1SStefano Zampini     }
85839566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec2_N, &array2));
85841c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&set_error, &set_error_reduced, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
85859566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
8586f34684f1SStefano Zampini     for (i = 0; i < pcis->n; i++) {
8587f34684f1SStefano Zampini       if (PetscRealPart(array[i]) > 0.0) array[i] = 1.0 / PetscRealPart(array[i]);
8588f34684f1SStefano Zampini     }
85899566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec1_N, &array));
85909566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_global, 0.0));
85919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85929566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
85939566063dSJacob Faibussowitsch     PetscCall(VecSum(pcis->vec1_global, &coarsesum));
859463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT " (%lf)\n", coarse_size, (double)PetscRealPart(coarsesum)));
8595b9b85e73SStefano Zampini     if (pcbddc->dbg_flag > 1 || set_error_reduced) {
8596ca8b9ea9SStefano Zampini       PetscInt *gidxs;
8597ca8b9ea9SStefano Zampini 
85989566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->local_primal_size, &gidxs));
85999566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(pcis->mapping, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, gidxs));
86009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Distribution of local primal indices\n"));
86019566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86029566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d\n", PetscGlobalRank));
8603f34684f1SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
860463a3b9bcSJacob 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]));
8605f34684f1SStefano Zampini       }
86069566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86079566063dSJacob Faibussowitsch       PetscCall(PetscFree(gidxs));
8608f34684f1SStefano Zampini     }
86099566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
861128b400f6SJacob Faibussowitsch     PetscCheck(!set_error_reduced, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "BDDC Numbering of coarse dofs failed");
8612f34684f1SStefano Zampini   }
86136080607fSStefano Zampini 
8614f34684f1SStefano Zampini   /* get back data */
8615f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
8616f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
86173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8618674ae819SStefano Zampini }
8619674ae819SStefano Zampini 
8620d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis)
8621d71ae5a4SJacob Faibussowitsch {
8622e456f2a8SStefano Zampini   IS           localis_t;
8623a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
8624e456f2a8SStefano Zampini   PetscScalar *vals;
8625e456f2a8SStefano Zampini 
8626e456f2a8SStefano Zampini   PetscFunctionBegin;
8627a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
86289566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
86299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
8630e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
86319566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
86329566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
86339566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
86341035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
86359566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
86369566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
86371035eff8SStefano Zampini   }
86389566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
86399566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
86409566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
86419566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
8642a7dc3881SStefano Zampini   /* now compute set in local ordering */
86439566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
86449566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
86459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
86469566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
8647a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
8648ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) lsize++;
8649e456f2a8SStefano Zampini   }
86509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
8651a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
8652ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) idxs[lsize++] = i;
8653e456f2a8SStefano Zampini   }
86549566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
86559566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
8656e456f2a8SStefano Zampini   *localis = localis_t;
86573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8658e456f2a8SStefano Zampini }
8659906d46d4SStefano Zampini 
8660d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr)
8661d71ae5a4SJacob Faibussowitsch {
86627c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
86637c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
86647c625d9fSStefano Zampini   PC_IS   *pcisf;
86657c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
86667c625d9fSStefano Zampini   PC       pcf;
86677c625d9fSStefano Zampini 
86687c625d9fSStefano Zampini   PetscFunctionBegin;
86697c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
86707c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
86717c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
86727c625d9fSStefano Zampini 
86737c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
867432fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
867532fe681dSStefano Zampini 
86767c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
86777c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
86787c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
86797c625d9fSStefano Zampini   pcisf->n          = pcis->n;
86807c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
86817c625d9fSStefano Zampini 
86827c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
868332fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
86847c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
868532fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
868632fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
868732fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
868832fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
868932fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
869032fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
86917c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
869232fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
869332fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
869432fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
86957c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
869632fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
869732fe681dSStefano Zampini 
869832fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
86997c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
87007c625d9fSStefano Zampini 
87017c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
87027c625d9fSStefano 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));
87037c625d9fSStefano 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));
87047c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
87057c625d9fSStefano Zampini 
870632fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
87077c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
870832fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
870932fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
871032fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
871132fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
87127c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
87133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
87147c625d9fSStefano Zampini }
87157c625d9fSStefano Zampini 
8716d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
8717d71ae5a4SJacob Faibussowitsch {
8718a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
8719b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
8720b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
8721a64f4aa4SStefano Zampini   Mat             S_j;
8722b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
8723b96c3477SStefano Zampini   PetscBool       free_used_adj;
8724b96c3477SStefano Zampini 
8725b96c3477SStefano Zampini   PetscFunctionBegin;
87269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
8727b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
8728b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
872908122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
8730b96c3477SStefano Zampini     used_xadj   = NULL;
8731b96c3477SStefano Zampini     used_adjncy = NULL;
8732b96c3477SStefano Zampini   } else {
873308122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
873408122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
873508122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
873608122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
8737b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
8738b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
8739b96c3477SStefano Zampini     } else {
87402fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
8741b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
8742b96c3477SStefano Zampini       PetscInt        nvtxs;
8743b96c3477SStefano Zampini 
87449566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
87452fffb893SStefano Zampini       if (flg_row) {
87469566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
87479566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
87489566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
8749b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
87502fffb893SStefano Zampini       } else {
87512fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
87522fffb893SStefano Zampini         used_xadj                 = NULL;
87532fffb893SStefano Zampini         used_adjncy               = NULL;
87542fffb893SStefano Zampini       }
87559566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
8756b96c3477SStefano Zampini     }
8757b96c3477SStefano Zampini   }
8758d5574798SStefano Zampini 
8759d5574798SStefano Zampini   /* setup sub_schurs data */
87609566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
8761df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
8762df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
87639566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
87649566063dSJacob 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));
8765a64f4aa4SStefano Zampini   } else {
876672b8c272SStefano Zampini     Mat       change        = NULL;
87679d54b7f4SStefano Zampini     Vec       scaling       = NULL;
8768111315fdSstefano_zampini     IS        change_primal = NULL, iP;
8769111315fdSstefano_zampini     PetscInt  benign_n;
8770111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
87717ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
8772111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
8773a3df083aSStefano Zampini 
87745feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
87755feab87aSStefano Zampini       PetscInt n_vertices;
87765feab87aSStefano Zampini 
87779566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
87782034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
87795feab87aSStefano Zampini     }
8780a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
8781a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
8782ca92afb2SStefano Zampini     } else {
8783a3df083aSStefano Zampini       benign_n = 0;
8784ca92afb2SStefano Zampini     }
8785b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
8786b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
8787b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
878872b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
878922db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
87901c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
879122db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
8792b7ab4a40SStefano Zampini     }
87937c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
8794b7ab4a40SStefano Zampini     if (need_change) {
879528b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
879632fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
879788c03ad3SStefano Zampini     }
87989d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
8799111315fdSstefano_zampini 
88009566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
8801111315fdSstefano_zampini     if (iP) {
8802d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
88039566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
8804d0609cedSBarry Smith       PetscOptionsEnd();
8805111315fdSstefano_zampini     }
8806111315fdSstefano_zampini     if (discrete_harmonic) {
8807111315fdSstefano_zampini       Mat A;
88089566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
88099566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
88109566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
88119371c9d4SSatish 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,
88129371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
88139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
8814111315fdSstefano_zampini     } else {
88159371c9d4SSatish 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,
88169371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
8817111315fdSstefano_zampini     }
88189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
88199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
8820ca92afb2SStefano Zampini   }
88219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
8822b96c3477SStefano Zampini 
8823b96c3477SStefano Zampini   /* free adjacency */
88241baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
88259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
88263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8827b96c3477SStefano Zampini }
8828b96c3477SStefano Zampini 
8829d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCInitSubSchurs(PC pc)
8830d71ae5a4SJacob Faibussowitsch {
8831b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
8832b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
8833b96c3477SStefano Zampini   PCBDDCGraph graph;
8834b96c3477SStefano Zampini 
8835b96c3477SStefano Zampini   PetscFunctionBegin;
8836b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
883708122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
88383301b35fSStefano Zampini     IS       verticesIS, verticescomm;
88393301b35fSStefano Zampini     PetscInt vsize, *idxs;
8840b96c3477SStefano Zampini 
88419566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
88429566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
88439566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
88449566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
88459566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
88469566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
88479566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
88489566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
88499566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
88509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
88519566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
8852b96c3477SStefano Zampini   } else {
8853b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
8854b96c3477SStefano Zampini   }
8855e4d548c7SStefano Zampini   /* print some info */
88565c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
8857e4d548c7SStefano Zampini     IS       vertices;
8858e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
88599566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
88609566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
88619566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
88629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
88639566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
886463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
886563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
886663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
88679566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
88689566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
88699566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
8870e4d548c7SStefano Zampini   }
8871b96c3477SStefano Zampini 
8872b96c3477SStefano Zampini   /* sub_schurs init */
887348a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
887432fe681dSStefano 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));
8875a64f4aa4SStefano Zampini 
8876b96c3477SStefano Zampini   /* free graph struct */
887748a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
88783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8879b96c3477SStefano Zampini }
8880fa34dd3eSStefano Zampini 
8881d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCCheckOperator(PC pc)
8882d71ae5a4SJacob Faibussowitsch {
8883fa34dd3eSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
8884fa34dd3eSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
8885fa34dd3eSStefano Zampini 
8886fa34dd3eSStefano Zampini   PetscFunctionBegin;
8887fa34dd3eSStefano Zampini   if (pcbddc->n_vertices == pcbddc->local_primal_size) {
8888fa34dd3eSStefano Zampini     IS           zerodiag = NULL;
88894f1b2e48SStefano Zampini     Mat          S_j, B0_B = NULL;
8890fa34dd3eSStefano Zampini     Vec          dummy_vec = NULL, vec_check_B, vec_scale_P;
88914f1b2e48SStefano Zampini     PetscScalar *p0_check, *array, *array2;
889275c01103SStefano Zampini     PetscReal    norm;
8893fa34dd3eSStefano Zampini     PetscInt     i;
8894fa34dd3eSStefano Zampini 
8895fa34dd3eSStefano Zampini     /* B0 and B0_B */
8896fa34dd3eSStefano Zampini     if (zerodiag) {
8897fa34dd3eSStefano Zampini       IS dummy;
8898fa34dd3eSStefano Zampini 
88999566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &dummy));
89009566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
89019566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(B0_B, NULL, &dummy_vec));
89029566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&dummy));
8903fa34dd3eSStefano Zampini     }
8904fa34dd3eSStefano Zampini     /* I need a primal vector to scale primal nodes since BDDC sums contibutions */
89059566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_P, &vec_scale_P));
89069566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 1.0));
89079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89089566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89099566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, vec_scale_P, INSERT_VALUES, SCATTER_REVERSE));
89109566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, vec_scale_P, INSERT_VALUES, SCATTER_REVERSE));
89119566063dSJacob Faibussowitsch     PetscCall(VecReciprocal(vec_scale_P));
8912fa34dd3eSStefano Zampini     /* S_j */
89139566063dSJacob Faibussowitsch     PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
89149566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
8915fa34dd3eSStefano Zampini 
8916fa34dd3eSStefano Zampini     /* mimic vector in \widetilde{W}_\Gamma */
89179566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec1_N, NULL));
8918fa34dd3eSStefano Zampini     /* continuous in primal space */
89199566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcbddc->coarse_vec, NULL));
89209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
89239566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcbddc->benign_n, &p0_check));
89244f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) p0_check[i] = array[pcbddc->local_primal_size - pcbddc->benign_n + i];
89259566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, pcbddc->local_primal_size, pcbddc->local_primal_ref_node, array, INSERT_VALUES));
89269566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
89279566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
89289566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
89299566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_N, pcis->vec2_B, INSERT_VALUES, SCATTER_FORWARD));
89309566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_N, pcis->vec2_B, INSERT_VALUES, SCATTER_FORWARD));
89319566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec2_B, &vec_check_B));
89329566063dSJacob Faibussowitsch     PetscCall(VecCopy(pcis->vec2_B, vec_check_B));
8933fa34dd3eSStefano Zampini 
8934fa34dd3eSStefano Zampini     /* assemble rhs for coarse problem */
8935fa34dd3eSStefano Zampini     /* widetilde{S}_\Gamma w_\Gamma + \widetilde{B0}^T_B p0 */
8936fa34dd3eSStefano Zampini     /* local with Schur */
89379566063dSJacob Faibussowitsch     PetscCall(MatMult(S_j, pcis->vec2_B, pcis->vec1_B));
8938fa34dd3eSStefano Zampini     if (zerodiag) {
89399566063dSJacob Faibussowitsch       PetscCall(VecGetArray(dummy_vec, &array));
89404f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) array[i] = p0_check[i];
89419566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(dummy_vec, &array));
89429566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(B0_B, dummy_vec, pcis->vec1_B, pcis->vec1_B));
8943fa34dd3eSStefano Zampini     }
8944fa34dd3eSStefano Zampini     /* sum on primal nodes the local contributions */
89459566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
89469566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
89479566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcis->vec1_N, &array));
89489566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array2));
8949fa34dd3eSStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) array2[i] = array[pcbddc->local_primal_ref_node[i]];
89509566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array2));
89519566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcis->vec1_N, &array));
89529566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->coarse_vec, 0.));
89539566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89549566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, ADD_VALUES, SCATTER_FORWARD));
89559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->coarse_vec, pcbddc->vec1_P, INSERT_VALUES, SCATTER_REVERSE));
89579566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
8958fa34dd3eSStefano Zampini     /* scale primal nodes (BDDC sums contibutions) */
89599566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(pcbddc->vec1_P, vec_scale_P, pcbddc->vec1_P));
89609566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, pcbddc->local_primal_size, pcbddc->local_primal_ref_node, array, INSERT_VALUES));
89619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
89629566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
89639566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
89649566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
89659566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
8966fa34dd3eSStefano Zampini     /* global: \widetilde{B0}_B w_\Gamma */
8967fa34dd3eSStefano Zampini     if (zerodiag) {
89689566063dSJacob Faibussowitsch       PetscCall(MatMult(B0_B, pcis->vec2_B, dummy_vec));
89699566063dSJacob Faibussowitsch       PetscCall(VecGetArray(dummy_vec, &array));
89704f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = array[i];
89719566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(dummy_vec, &array));
8972fa34dd3eSStefano Zampini     }
8973fa34dd3eSStefano Zampini     /* BDDC */
89749566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_D, 0.));
89759566063dSJacob Faibussowitsch     PetscCall(PCBDDCApplyInterfacePreconditioner(pc, PETSC_FALSE));
8976fa34dd3eSStefano Zampini 
89779566063dSJacob Faibussowitsch     PetscCall(VecCopy(pcis->vec1_B, pcis->vec2_B));
89789566063dSJacob Faibussowitsch     PetscCall(VecAXPY(pcis->vec1_B, -1.0, vec_check_B));
89799566063dSJacob Faibussowitsch     PetscCall(VecNorm(pcis->vec1_B, NORM_INFINITY, &norm));
898063a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] BDDC local error is %1.4e\n", PetscGlobalRank, (double)norm));
898148a46eb9SPierre 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])));
89829566063dSJacob Faibussowitsch     PetscCall(PetscFree(p0_check));
89839566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec_scale_P));
89849566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec_check_B));
89859566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&dummy_vec));
89869566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&S_j));
89879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
8988fa34dd3eSStefano Zampini   }
89893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8990fa34dd3eSStefano Zampini }
89911e0482f5SStefano Zampini 
89921e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
8993d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
8994d71ae5a4SJacob Faibussowitsch {
89951e0482f5SStefano Zampini   Mat         At;
89961e0482f5SStefano Zampini   IS          rows;
89971e0482f5SStefano Zampini   PetscInt    rst, ren;
89981e0482f5SStefano Zampini   PetscLayout rmap;
89991e0482f5SStefano Zampini 
90001e0482f5SStefano Zampini   PetscFunctionBegin;
90011e0482f5SStefano Zampini   rst = ren = 0;
90021e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
90039566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
90049566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
90059566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
90069566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
90079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
90081e0482f5SStefano Zampini   }
90099566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
90109566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
90119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
90121e0482f5SStefano Zampini 
90131e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
90141e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
90151e0482f5SStefano Zampini     IS          from, to;
90161e0482f5SStefano Zampini     Vec         gvec;
90171e0482f5SStefano Zampini     PetscInt    lsize;
90181e0482f5SStefano Zampini 
90199566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
90209566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
90219566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
90229566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&((*B)->rmap)));
90239566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
90241e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
90251e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
90269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
90279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
90289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
90299566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
90301e0482f5SStefano Zampini     b->A = a->A;
90311e0482f5SStefano Zampini     b->B = a->B;
90321e0482f5SStefano Zampini 
90331e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
90341e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
90350a545947SLisandro Dalcin     b->rowindices   = NULL;
90360a545947SLisandro Dalcin     b->rowvalues    = NULL;
90371e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
90381e0482f5SStefano Zampini 
90391e0482f5SStefano Zampini     (*B)->rmap         = rmap;
90401e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
90411e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
90421e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
90431e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
90441e0482f5SStefano Zampini 
90451e0482f5SStefano Zampini     if (a->colmap) {
90461e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
9047eec179cfSJacob Faibussowitsch       PetscCall(PetscHMapIDuplicate(a->colmap, &b->colmap));
90481e0482f5SStefano Zampini #else
90499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
90509566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
90511e0482f5SStefano Zampini #endif
90520a545947SLisandro Dalcin     } else b->colmap = NULL;
90531e0482f5SStefano Zampini     if (a->garray) {
90541e0482f5SStefano Zampini       PetscInt len;
90551e0482f5SStefano Zampini       len = a->B->cmap->n;
90569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
90579566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
90580a545947SLisandro Dalcin     } else b->garray = NULL;
90591e0482f5SStefano Zampini 
90609566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
90611e0482f5SStefano Zampini     b->lvec = a->lvec;
90621e0482f5SStefano Zampini 
90631e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
90649566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
90659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
90669566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
90679566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
90689566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
90699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
90709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
90719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
90721e0482f5SStefano Zampini   }
90739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
90743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
90751e0482f5SStefano Zampini }
9076