xref: /petsc/src/ksp/pc/impls/bddc/bddcprivate.c (revision a4cdd7ef251453db2f52ffbd7cb093bd68a5ec82)
11cf9b237SStefano Zampini #include <../src/mat/impls/aij/seq/aij.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
49de2952eSStefano Zampini #include <petsc/private/kernels/blockinvert.h>
5837cedc9SStefano Zampini #include <../src/mat/impls/dense/seq/dense.h>
6c80a6c00SStefano Zampini #include <petscdmplex.h>
7674ae819SStefano Zampini #include <petscblaslapack.h>
8daf8a457SStefano Zampini #include <petsc/private/sfimpl.h>
9c80a6c00SStefano Zampini #include <petsc/private/dmpleximpl.h>
107620a527SStefano Zampini #include <petscdmda.h>
11674ae819SStefano Zampini 
121e0482f5SStefano Zampini static PetscErrorCode MatMPIAIJRestrict(Mat, MPI_Comm, Mat *);
131e0482f5SStefano Zampini 
14f498cd09SStefano Zampini /* if range is true,  it returns B s.t. span{B} = range(A)
15f498cd09SStefano Zampini    if range is false, it returns B s.t. range(B) _|_ range(A) */
16ba38deedSJacob Faibussowitsch static PetscErrorCode MatDenseOrthogonalRangeOrComplement(Mat A, PetscBool range, PetscInt lw, PetscScalar *work, PetscReal *rwork, Mat *B)
17d71ae5a4SJacob Faibussowitsch {
18a13144ffSStefano Zampini   PetscScalar *uwork, *data, *U, ds = 0.;
19a13144ffSStefano Zampini   PetscReal   *sing;
20a13144ffSStefano Zampini   PetscBLASInt bM, bN, lwork, lierr, di = 1;
21a13144ffSStefano Zampini   PetscInt     ulw, i, nr, nc, n;
22abee2b68SSebastian Grimberg #if defined(PETSC_USE_COMPLEX)
23abee2b68SSebastian Grimberg   PetscReal *rwork2;
24abee2b68SSebastian Grimberg #endif
25a13144ffSStefano Zampini 
26a13144ffSStefano Zampini   PetscFunctionBegin;
279566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
283ba16761SJacob Faibussowitsch   if (!nr || !nc) PetscFunctionReturn(PETSC_SUCCESS);
29a13144ffSStefano Zampini 
30a13144ffSStefano Zampini   /* workspace */
31a13144ffSStefano Zampini   if (!work) {
32a13144ffSStefano Zampini     ulw = PetscMax(PetscMax(1, 5 * PetscMin(nr, nc)), 3 * PetscMin(nr, nc) + PetscMax(nr, nc));
339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ulw, &uwork));
34a13144ffSStefano Zampini   } else {
35a13144ffSStefano Zampini     ulw   = lw;
36a13144ffSStefano Zampini     uwork = work;
37a13144ffSStefano Zampini   }
38a13144ffSStefano Zampini   n = PetscMin(nr, nc);
39a13144ffSStefano Zampini   if (!rwork) {
409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &sing));
41a13144ffSStefano Zampini   } else {
42a13144ffSStefano Zampini     sing = rwork;
43a13144ffSStefano Zampini   }
44a13144ffSStefano Zampini 
45a13144ffSStefano Zampini   /* SVD */
469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nr, &U));
479566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nr, &bM));
489566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(nc, &bN));
499566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast(ulw, &lwork));
509566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(A, &data));
519566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
52abee2b68SSebastian Grimberg #if !defined(PETSC_USE_COMPLEX)
53792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, &lierr));
54abee2b68SSebastian Grimberg #else
559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(5 * n, &rwork2));
56792fecdfSBarry Smith   PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("A", "N", &bM, &bN, data, &bM, sing, U, &bM, &ds, &di, uwork, &lwork, rwork2, &lierr));
579566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork2));
58abee2b68SSebastian Grimberg #endif
599566063dSJacob Faibussowitsch   PetscCall(PetscFPTrapPop());
6028b400f6SJacob Faibussowitsch   PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
619566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(A, &data));
629371c9d4SSatish Balay   for (i = 0; i < n; i++)
639371c9d4SSatish Balay     if (sing[i] < PETSC_SMALL) break;
6448a46eb9SPierre Jolivet   if (!rwork) PetscCall(PetscFree(sing));
6548a46eb9SPierre Jolivet   if (!work) PetscCall(PetscFree(uwork));
66a13144ffSStefano Zampini   /* create B */
67f498cd09SStefano Zampini   if (!range) {
689566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, nr - i, NULL, B));
699566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
709566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U + nr * i, (nr - i) * nr));
71f498cd09SStefano Zampini   } else {
729566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, nr, i, NULL, B));
739566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(*B, &data));
749566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data, U, i * nr));
75f498cd09SStefano Zampini   }
769566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(*B, &data));
779566063dSJacob Faibussowitsch   PetscCall(PetscFree(U));
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
79a13144ffSStefano Zampini }
80a13144ffSStefano Zampini 
811e0482f5SStefano Zampini /* TODO REMOVE */
821e0482f5SStefano Zampini #if defined(PRINT_GDET)
831e0482f5SStefano Zampini static int inc = 0;
841e0482f5SStefano Zampini static int lev = 0;
851e0482f5SStefano Zampini #endif
861e0482f5SStefano Zampini 
87ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCComputeNedelecChangeEdge(Mat lG, IS edge, IS extrow, IS extcol, IS corners, Mat *Gins, Mat *GKins, PetscScalar cvals[2], PetscScalar *work, PetscReal *rwork)
88d71ae5a4SJacob Faibussowitsch {
89a13144ffSStefano Zampini   Mat          GE, GEd;
90a13144ffSStefano Zampini   PetscInt     rsize, csize, esize;
91a13144ffSStefano Zampini   PetscScalar *ptr;
92a13144ffSStefano Zampini 
93a13144ffSStefano Zampini   PetscFunctionBegin;
949566063dSJacob Faibussowitsch   PetscCall(ISGetSize(edge, &esize));
953ba16761SJacob Faibussowitsch   if (!esize) PetscFunctionReturn(PETSC_SUCCESS);
969566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extrow, &rsize));
979566063dSJacob Faibussowitsch   PetscCall(ISGetSize(extcol, &csize));
98a13144ffSStefano Zampini 
99a13144ffSStefano Zampini   /* gradients */
100a13144ffSStefano Zampini   ptr = work + 5 * esize;
1019566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, extrow, extcol, MAT_INITIAL_MATRIX, &GE));
1029566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, rsize, csize, ptr, Gins));
1039566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, Gins));
1049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
105a13144ffSStefano Zampini 
106a13144ffSStefano Zampini   /* constants */
107a13144ffSStefano Zampini   ptr += rsize * csize;
1089566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, esize, csize, ptr, &GEd));
1099566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(lG, edge, extcol, MAT_INITIAL_MATRIX, &GE));
1109566063dSJacob Faibussowitsch   PetscCall(MatConvert(GE, MATSEQDENSE, MAT_REUSE_MATRIX, &GEd));
1119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GE));
1129566063dSJacob Faibussowitsch   PetscCall(MatDenseOrthogonalRangeOrComplement(GEd, PETSC_FALSE, 5 * esize, work, rwork, GKins));
1139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&GEd));
1141e0482f5SStefano Zampini 
1151e0482f5SStefano Zampini   if (corners) {
1161e0482f5SStefano Zampini     Mat                GEc;
1171683a169SBarry Smith     const PetscScalar *vals;
1181683a169SBarry Smith     PetscScalar        v;
1191e0482f5SStefano Zampini 
1209566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(lG, edge, corners, MAT_INITIAL_MATRIX, &GEc));
1219566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(GEc, *GKins, MAT_INITIAL_MATRIX, 1.0, &GEd));
1229566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(GEd, &vals));
123a8f51744SPierre Jolivet     /* v       = PetscAbsScalar(vals[0]); */
124637e8532SStefano Zampini     v        = 1.;
1251e0482f5SStefano Zampini     cvals[0] = vals[0] / v;
1261e0482f5SStefano Zampini     cvals[1] = vals[1] / v;
1279566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(GEd, &vals));
1289566063dSJacob Faibussowitsch     PetscCall(MatScale(*GKins, 1. / v));
1291e0482f5SStefano Zampini #if defined(PRINT_GDET)
1301e0482f5SStefano Zampini     {
1311e0482f5SStefano Zampini       PetscViewer viewer;
1321e0482f5SStefano Zampini       char        filename[256];
133a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "Gdet_l%d_r%d_cc%d.m", lev, PetscGlobalRank, inc++));
1349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &viewer));
1359566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
1369566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEc, "GEc"));
1379566063dSJacob Faibussowitsch       PetscCall(MatView(GEc, viewer));
138f4f49eeaSPierre Jolivet       PetscCall(PetscObjectSetName((PetscObject)*GKins, "GK"));
1399566063dSJacob Faibussowitsch       PetscCall(MatView(*GKins, viewer));
1409566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)GEd, "Gproj"));
1419566063dSJacob Faibussowitsch       PetscCall(MatView(GEd, viewer));
1429566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
1431e0482f5SStefano Zampini     }
1441e0482f5SStefano Zampini #endif
1459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEd));
1469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GEc));
1471e0482f5SStefano Zampini   }
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149a13144ffSStefano Zampini }
150a13144ffSStefano Zampini 
1519de2952eSStefano Zampini static PetscErrorCode MatAIJExtractRows(Mat, IS, Mat *);
1529de2952eSStefano Zampini 
153d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNedelecSupport(PC pc)
154d71ae5a4SJacob Faibussowitsch {
155a13144ffSStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
156a13144ffSStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
1570569b399SStefano Zampini   Mat                    G, T, conn, lG, lGt, lGis, lGall, lGe, lGinit;
158a13144ffSStefano Zampini   PetscSF                sfv;
1591e0482f5SStefano Zampini   ISLocalToGlobalMapping el2g, vl2g, fl2g, al2g;
160a13144ffSStefano Zampini   MPI_Comm               comm;
161c2151214SStefano Zampini   IS                     lned, primals, allprimals, nedfieldlocal;
162c2151214SStefano Zampini   IS                    *eedges, *extrows, *extcols, *alleedges;
1637d871cd7SStefano Zampini   PetscBT                btv, bte, btvc, btb, btbd, btvcand, btvi, btee, bter;
164a13144ffSStefano Zampini   PetscScalar           *vals, *work;
165a13144ffSStefano Zampini   PetscReal             *rwork;
166a13144ffSStefano Zampini   const PetscInt        *idxs, *ii, *jj, *iit, *jjt;
1671e0482f5SStefano Zampini   PetscInt               ne, nv, Lv, order, n, field;
168eee23b56SStefano Zampini   PetscInt               i, j, extmem, cum, maxsize, nee;
169b03ebc13SStefano Zampini   PetscInt              *extrow, *extrowcum, *marks, *vmarks, *gidxs;
170a13144ffSStefano Zampini   PetscInt              *sfvleaves, *sfvroots;
171b03ebc13SStefano Zampini   PetscInt              *corners, *cedges;
172637e8532SStefano Zampini   PetscInt              *ecount, **eneighs, *vcount, **vneighs;
173b03ebc13SStefano Zampini   PetscInt              *emarks;
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     /* one ref for the destruction of al2g, one for el2g */
3039566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3049566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)al2g));
3051e0482f5SStefano Zampini     el2g = al2g;
306c2151214SStefano Zampini     fl2g = NULL;
307c2151214SStefano Zampini   }
308a13144ffSStefano Zampini 
309213b8bfaSStefano Zampini   /* Start communication to drop connections for interior edges (for cc analysis only) */
3109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
3119566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
312c2151214SStefano Zampini   if (nedfieldlocal) {
3139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
314c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[idxs[i]] = 1;
3159566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
316c2151214SStefano Zampini   } else {
317c2151214SStefano Zampini     for (i = 0; i < ne; i++) matis->sf_leafdata[i] = 1;
318c2151214SStefano Zampini   }
3199566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
3209566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
321213b8bfaSStefano Zampini 
322213b8bfaSStefano Zampini   if (!singular) { /* drop connections with interior edges to avoid unneeded communications and memory movements */
3239566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(pcbddc->discretegradient, MAT_COPY_VALUES, &G));
3249566063dSJacob Faibussowitsch     PetscCall(MatSetOption(G, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
3251e0482f5SStefano Zampini     if (global) {
3261e0482f5SStefano Zampini       PetscInt rst;
3271e0482f5SStefano Zampini 
3289566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(G, &rst, NULL));
329c2151214SStefano Zampini       for (i = 0, cum = 0; i < pc->pmat->rmap->n; i++) {
330ad540459SPierre Jolivet         if (matis->sf_rootdata[i] < 2) matis->sf_rootdata[cum++] = i + rst;
331c2151214SStefano Zampini       }
3329566063dSJacob Faibussowitsch       PetscCall(MatSetOption(G, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE));
3339566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, matis->sf_rootdata, 0., NULL, NULL));
3341e0482f5SStefano Zampini     } else {
3351e0482f5SStefano Zampini       PetscInt *tbz;
3361e0482f5SStefano Zampini 
3379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ne, &tbz));
3389566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3399566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
3409566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nedfieldlocal, &idxs));
3411e0482f5SStefano Zampini       for (i = 0, cum = 0; i < ne; i++)
3429371c9d4SSatish Balay         if (matis->sf_leafdata[idxs[i]] == 1) tbz[cum++] = i;
3439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
3449566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(el2g, cum, tbz, tbz));
3459566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(G, cum, tbz, 0., NULL, NULL));
3469566063dSJacob Faibussowitsch       PetscCall(PetscFree(tbz));
3471e0482f5SStefano Zampini     }
348213b8bfaSStefano Zampini   } else { /* we need the entire G to infer the nullspace */
3499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->discretegradient));
350213b8bfaSStefano Zampini     G = pcbddc->discretegradient;
351213b8bfaSStefano Zampini   }
352a13144ffSStefano Zampini 
353a13144ffSStefano Zampini   /* Extract subdomain relevant rows of G  */
3549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(el2g, &idxs));
3559566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, ne, idxs, PETSC_USE_POINTER, &lned));
3569de2952eSStefano Zampini   PetscCall(MatAIJExtractRows(G, lned, &lGall));
3579de2952eSStefano Zampini   /* PetscCall(MatCreateSubMatrix(G, lned, NULL, MAT_INITIAL_MATRIX, &lGall)); */
3589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(el2g, &idxs));
3599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&lned));
3609566063dSJacob Faibussowitsch   PetscCall(MatConvert(lGall, MATIS, MAT_INITIAL_MATRIX, &lGis));
3619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGall));
3629566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(lGis, &lG));
363a13144ffSStefano Zampini 
3649de2952eSStefano Zampini   if (matis->allow_repeated) { /* multi-element support */
3659de2952eSStefano Zampini     Mat                   *lGn, B;
3669de2952eSStefano Zampini     IS                    *is_rows, *tcols, tmap, nmap;
3679de2952eSStefano Zampini     PetscInt               subnv;
3689de2952eSStefano Zampini     const PetscInt        *subvidxs;
3699de2952eSStefano Zampini     ISLocalToGlobalMapping mapn;
3709de2952eSStefano Zampini 
3719de2952eSStefano Zampini     PetscCall(PetscCalloc1(pcbddc->n_local_subs * pcbddc->n_local_subs, &lGn));
3729de2952eSStefano Zampini     PetscCall(PetscMalloc1(pcbddc->n_local_subs, &is_rows));
3739de2952eSStefano Zampini     PetscCall(PetscMalloc1(pcbddc->n_local_subs, &tcols));
3749de2952eSStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) {
3759de2952eSStefano Zampini       if (fl2g) {
3769de2952eSStefano Zampini         PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->local_subs[i], &is_rows[i]));
3779de2952eSStefano Zampini       } else {
3789de2952eSStefano Zampini         PetscCall(PetscObjectReference((PetscObject)pcbddc->local_subs[i]));
3799de2952eSStefano Zampini         is_rows[i] = pcbddc->local_subs[i];
3809de2952eSStefano Zampini       }
3819de2952eSStefano Zampini       PetscCall(MatCreateSubMatrix(lG, is_rows[i], NULL, MAT_INITIAL_MATRIX, &lGn[i * (1 + pcbddc->n_local_subs)]));
3829de2952eSStefano Zampini       PetscCall(MatSeqAIJCompactOutExtraColumns_SeqAIJ(lGn[i * (1 + pcbddc->n_local_subs)], &mapn));
3839de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingGetSize(mapn, &subnv));
3849de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingGetIndices(mapn, &subvidxs));
3859de2952eSStefano Zampini       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, subnv, subvidxs, PETSC_COPY_VALUES, &tcols[i]));
3869de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingRestoreIndices(mapn, &subvidxs));
3879de2952eSStefano Zampini       PetscCall(ISLocalToGlobalMappingDestroy(&mapn));
3889de2952eSStefano Zampini     }
3899de2952eSStefano Zampini 
3909de2952eSStefano Zampini     /* Create new MATIS with repeated vertices */
3919de2952eSStefano Zampini     PetscCall(MatCreate(comm, &B));
3929de2952eSStefano Zampini     PetscCall(MatSetSizes(B, lGis->rmap->n, lGis->cmap->n, lGis->rmap->N, lGis->cmap->N));
3939de2952eSStefano Zampini     PetscCall(MatSetType(B, MATIS));
3949de2952eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PETSC_TRUE));
3959de2952eSStefano Zampini     PetscCall(ISConcatenate(PETSC_COMM_SELF, pcbddc->n_local_subs, tcols, &tmap));
3969de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingApplyIS(lGis->cmap->mapping, tmap, &nmap));
3979de2952eSStefano Zampini     PetscCall(ISDestroy(&tmap));
3989de2952eSStefano Zampini     PetscCall(ISGetLocalSize(nmap, &subnv));
3999de2952eSStefano Zampini     PetscCall(ISGetIndices(nmap, &subvidxs));
4009de2952eSStefano Zampini     PetscCall(ISCreateGeneral(comm, subnv, subvidxs, PETSC_USE_POINTER, &tmap));
4019de2952eSStefano Zampini     PetscCall(ISRestoreIndices(nmap, &subvidxs));
4029de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingCreateIS(tmap, &mapn));
4039de2952eSStefano Zampini     PetscCall(ISDestroy(&tmap));
4049de2952eSStefano Zampini     PetscCall(ISDestroy(&nmap));
4059de2952eSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(B, lGis->rmap->mapping, mapn));
4069de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingDestroy(&mapn));
4079de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, pcbddc->n_local_subs, is_rows, pcbddc->n_local_subs, NULL, lGn, &lG));
4089de2952eSStefano Zampini     for (PetscInt i = 0; i < pcbddc->n_local_subs; i++) {
4099de2952eSStefano Zampini       PetscCall(MatDestroy(&lGn[i * (1 + pcbddc->n_local_subs)]));
4109de2952eSStefano Zampini       PetscCall(ISDestroy(&is_rows[i]));
4119de2952eSStefano Zampini       PetscCall(ISDestroy(&tcols[i]));
4129de2952eSStefano Zampini     }
4139de2952eSStefano Zampini     PetscCall(MatConvert(lG, MATSEQAIJ, MAT_INPLACE_MATRIX, &lG));
4149de2952eSStefano Zampini     PetscCall(PetscFree(lGn));
4159de2952eSStefano Zampini     PetscCall(PetscFree(is_rows));
4169de2952eSStefano Zampini     PetscCall(PetscFree(tcols));
4179de2952eSStefano Zampini     PetscCall(MatISSetLocalMat(B, lG));
4189de2952eSStefano Zampini     PetscCall(MatDestroy(&lG));
4199de2952eSStefano Zampini 
4209de2952eSStefano Zampini     PetscCall(MatDestroy(&lGis));
4219de2952eSStefano Zampini     lGis = B;
4229de2952eSStefano Zampini   }
4239de2952eSStefano Zampini 
424213b8bfaSStefano Zampini   /* SF for nodal dofs communications */
4259566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(G, NULL, &Lv));
4269566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(lGis, NULL, &vl2g));
4279566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)vl2g));
4289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(vl2g, &nv));
4299566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sfv));
4309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(vl2g, &idxs));
4319566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sfv, lGis->cmap, nv, NULL, PETSC_OWN_POINTER, idxs));
4329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(vl2g, &idxs));
433213b8bfaSStefano Zampini   i = singular ? 2 : 1;
4349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i * nv, &sfvleaves, i * Lv, &sfvroots));
435a13144ffSStefano Zampini 
4361e0482f5SStefano Zampini   /* Destroy temporary G created in MATIS format and modified G */
4379de2952eSStefano Zampini   PetscCall(MatISGetLocalMat(lGis, &lG));
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)lG));
4399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGis));
4409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&G));
441a13144ffSStefano Zampini 
442213b8bfaSStefano Zampini   if (print) {
4439566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "initial_lG"));
4449566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
445213b8bfaSStefano Zampini   }
446213b8bfaSStefano Zampini 
447213b8bfaSStefano Zampini   /* Save lG for values insertion in change of basis */
4489566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGinit));
4490569b399SStefano Zampini 
450a13144ffSStefano Zampini   /* Analyze the edge-nodes connections (duplicate lG) */
4519566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(lG, MAT_COPY_VALUES, &lGe));
4529566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGe, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
4539566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btv));
4549566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &bte));
4559566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btb));
4569566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btbd));
4579566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvcand));
458a13144ffSStefano Zampini   /* need to import the boundary specification to ensure the
459a13144ffSStefano Zampini      proper detection of coarse edges' endpoints */
460a13144ffSStefano Zampini   if (pcbddc->DirichletBoundariesLocal) {
461c2151214SStefano Zampini     IS is;
462c2151214SStefano Zampini 
463c2151214SStefano Zampini     if (fl2g) {
4649566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->DirichletBoundariesLocal, &is));
465c2151214SStefano Zampini     } else {
466c2151214SStefano Zampini       is = pcbddc->DirichletBoundariesLocal;
467c2151214SStefano Zampini     }
4689566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4699566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
470a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
4719de2952eSStefano Zampini       if (idxs[i] >= 0 && idxs[i] < ne) {
4729566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btb, idxs[i]));
4739566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btbd, idxs[i]));
474a13144ffSStefano Zampini       }
475a13144ffSStefano Zampini     }
4769566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
47748a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
478a13144ffSStefano Zampini   }
479a13144ffSStefano Zampini   if (pcbddc->NeumannBoundariesLocal) {
480c2151214SStefano Zampini     IS is;
481c2151214SStefano Zampini 
482c2151214SStefano Zampini     if (fl2g) {
4839566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_MASK, pcbddc->NeumannBoundariesLocal, &is));
484c2151214SStefano Zampini     } else {
485c2151214SStefano Zampini       is = pcbddc->NeumannBoundariesLocal;
486c2151214SStefano Zampini     }
4879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &cum));
4889566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
489a13144ffSStefano Zampini     for (i = 0; i < cum; i++) {
4909de2952eSStefano Zampini       if (idxs[i] >= 0 && idxs[i] < ne) PetscCall(PetscBTSet(btb, idxs[i]));
491a13144ffSStefano Zampini     }
4929566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
49348a46eb9SPierre Jolivet     if (fl2g) PetscCall(ISDestroy(&is));
494c2151214SStefano Zampini   }
495c2151214SStefano Zampini 
496213b8bfaSStefano Zampini   /* Count neighs per dof */
4979de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, &ecount, NULL));
4989de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, &vcount, NULL));
499637e8532SStefano Zampini 
5007d871cd7SStefano Zampini   /* need to remove coarse faces' dofs and coarse edges' dirichlet dofs
5017d871cd7SStefano Zampini      for proper detection of coarse edges' endpoints */
5029566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(ne, &btee));
50362b0c6f7SStefano Zampini   for (i = 0; i < ne; i++) {
50448a46eb9SPierre Jolivet     if ((ecount[i] > 2 && !PetscBTLookup(btbd, i)) || (ecount[i] == 2 && PetscBTLookup(btb, i))) PetscCall(PetscBTSet(btee, i));
50562b0c6f7SStefano Zampini   }
5069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ne, &marks));
50762b0c6f7SStefano Zampini   if (!conforming) {
5089566063dSJacob Faibussowitsch     PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
5099566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
51062b0c6f7SStefano Zampini   }
5119566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5129566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGe, &vals));
51362b0c6f7SStefano Zampini   cum = 0;
514a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
515dec27d64SStefano Zampini     /* eliminate rows corresponding to edge dofs belonging to coarse faces */
51662b0c6f7SStefano Zampini     if (!PetscBTLookup(btee, i)) {
517a13144ffSStefano Zampini       marks[cum++] = i;
518dec27d64SStefano Zampini       continue;
519dec27d64SStefano Zampini     }
520dec27d64SStefano Zampini     /* set badly connected edge dofs as primal */
52162b0c6f7SStefano Zampini     if (!conforming) {
52262b0c6f7SStefano Zampini       if (ii[i + 1] - ii[i] != order + 1) { /* every row of G on the coarse edge should list order+1 nodal dofs */
523a13144ffSStefano Zampini         marks[cum++] = i;
5249566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(bte, i));
52548a46eb9SPierre Jolivet         for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
52662b0c6f7SStefano Zampini       } else {
527aaa8cc7dSPierre Jolivet         /* every edge dofs should be connected through a certain number of nodal dofs
52862b0c6f7SStefano Zampini            to other edge dofs belonging to coarse edges
52962b0c6f7SStefano Zampini            - at most 2 endpoints
53062b0c6f7SStefano Zampini            - order-1 interior nodal dofs
53162b0c6f7SStefano Zampini            - no undefined nodal dofs (nconn < order)
53262b0c6f7SStefano Zampini         */
53362b0c6f7SStefano Zampini         PetscInt ends = 0, ints = 0, undef = 0;
53462b0c6f7SStefano Zampini         for (j = ii[i]; j < ii[i + 1]; j++) {
53562b0c6f7SStefano Zampini           PetscInt v     = jj[j], k;
53662b0c6f7SStefano Zampini           PetscInt nconn = iit[v + 1] - iit[v];
5379371c9d4SSatish Balay           for (k = iit[v]; k < iit[v + 1]; k++)
5389371c9d4SSatish Balay             if (!PetscBTLookup(btee, jjt[k])) nconn--;
53962b0c6f7SStefano Zampini           if (nconn > order) ends++;
54062b0c6f7SStefano Zampini           else if (nconn == order) ints++;
54162b0c6f7SStefano Zampini           else undef++;
54262b0c6f7SStefano Zampini         }
54362b0c6f7SStefano Zampini         if (undef || ends > 2 || ints != order - 1) {
54462b0c6f7SStefano Zampini           marks[cum++] = i;
5459566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(bte, i));
54648a46eb9SPierre Jolivet           for (j = ii[i]; j < ii[i + 1]; j++) PetscCall(PetscBTSet(btv, jj[j]));
54762b0c6f7SStefano Zampini         }
54862b0c6f7SStefano Zampini       }
549a13144ffSStefano Zampini     }
550dec27d64SStefano Zampini     /* We assume the order on the element edge is ii[i+1]-ii[i]-1 */
551dec27d64SStefano Zampini     if (!order && ii[i + 1] != ii[i]) {
552dec27d64SStefano Zampini       PetscScalar val = 1. / (ii[i + 1] - ii[i] - 1);
553dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vals[j] = val;
554a13144ffSStefano Zampini     }
555dec27d64SStefano Zampini   }
5569566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btee));
5579566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGe, &vals));
5589566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
55962b0c6f7SStefano Zampini   if (!conforming) {
5609566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
5619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lGt));
56262b0c6f7SStefano Zampini   }
5639566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGe, cum, marks, 0., NULL, NULL));
564637e8532SStefano Zampini 
5659de2952eSStefano Zampini   if (matis->allow_repeated) { /* assign a uniq global id to edge local subsets and communicate it with nodal space */
5669de2952eSStefano Zampini     PetscSF   emlsf, vmlsf;
5679de2952eSStefano Zampini     PetscInt *eleaves, *vleaves, *meleaves, *mvleaves;
5689de2952eSStefano Zampini     PetscInt  cum_subs = 0, n_subs = pcbddc->n_local_subs, bs, emnr, emnl, vmnr, vmnl;
5699de2952eSStefano Zampini 
5709de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(el2g, &bs));
5719de2952eSStefano Zampini     PetscCheck(bs == 1, comm, PETSC_ERR_SUP, "Not coded");
5729de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(vl2g, &bs));
5739de2952eSStefano Zampini     PetscCheck(bs == 1, comm, PETSC_ERR_SUP, "Not coded");
5749de2952eSStefano Zampini 
5759de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockMultiLeavesSF(el2g, &emlsf));
5769de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockMultiLeavesSF(vl2g, &vmlsf));
5779de2952eSStefano Zampini 
5789de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(emlsf, &emnr, &emnl, NULL, NULL));
5799de2952eSStefano Zampini     for (i = 0, j = 0; i < ne; i++) j += ecount[i];
5809de2952eSStefano Zampini     PetscCheck(emnr == ne, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of roots in edge multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, emnr, ne);
5819de2952eSStefano Zampini     PetscCheck(emnl == j, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of leaves in edge multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, emnl, j);
5829de2952eSStefano Zampini 
5839de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(vmlsf, &vmnr, &vmnl, NULL, NULL));
5849de2952eSStefano Zampini     for (i = 0, j = 0; i < nv; i++) j += vcount[i];
5859de2952eSStefano Zampini     PetscCheck(vmnr == nv, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of roots in nodal multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, vmnr, nv);
5869de2952eSStefano Zampini     PetscCheck(vmnl == j, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of leaves in nodal multi-leaves SF %" PetscInt_FMT " != %" PetscInt_FMT, vmnl, j);
5879de2952eSStefano Zampini 
5889de2952eSStefano Zampini     PetscCall(PetscMalloc1(ne, &eleaves));
5899de2952eSStefano Zampini     PetscCall(PetscMalloc1(nv, &vleaves));
5909de2952eSStefano Zampini     for (i = 0; i < ne; i++) eleaves[i] = -1;
5919de2952eSStefano Zampini     for (i = 0; i < nv; i++) vleaves[i] = -1;
5929de2952eSStefano Zampini     PetscCall(PetscMalloc1(emnl, &meleaves));
5939de2952eSStefano Zampini     PetscCall(PetscMalloc1(vmnl, &mvleaves));
5949de2952eSStefano Zampini 
5959de2952eSStefano Zampini     PetscCallMPI(MPI_Exscan(&n_subs, &cum_subs, 1, MPIU_INT, MPI_SUM, comm));
5969de2952eSStefano Zampini     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
5979de2952eSStefano Zampini     for (i = 0; i < n_subs; i++) {
5989de2952eSStefano Zampini       const PetscInt *idxs;
5999de2952eSStefano Zampini       const PetscInt  subid = cum_subs + i;
6009de2952eSStefano Zampini       PetscInt        ns;
6019de2952eSStefano Zampini 
6029de2952eSStefano Zampini       PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &ns));
6039de2952eSStefano Zampini       PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
6049de2952eSStefano Zampini       for (j = 0; j < ns; j++) {
6059de2952eSStefano Zampini         const PetscInt e = idxs[j];
6069de2952eSStefano Zampini 
6079de2952eSStefano Zampini         eleaves[e] = subid;
6089de2952eSStefano Zampini         for (PetscInt k = ii[e]; k < ii[e + 1]; k++) vleaves[jj[k]] = subid;
6099de2952eSStefano Zampini       }
6109de2952eSStefano Zampini       PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
6119de2952eSStefano Zampini     }
6129de2952eSStefano Zampini     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
6139de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(emlsf, MPIU_INT, eleaves, meleaves, MPI_REPLACE));
6149de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(emlsf, MPIU_INT, eleaves, meleaves, MPI_REPLACE));
6159de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(vmlsf, MPIU_INT, vleaves, mvleaves, MPI_REPLACE));
6169de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(vmlsf, MPIU_INT, vleaves, mvleaves, MPI_REPLACE));
6179de2952eSStefano Zampini     PetscCall(PetscFree(eleaves));
6189de2952eSStefano Zampini     PetscCall(PetscFree(vleaves));
6199de2952eSStefano Zampini 
6209de2952eSStefano Zampini     PetscCall(PetscMalloc1(ne + 1, &eneighs));
6219de2952eSStefano Zampini     eneighs[0] = meleaves;
6229de2952eSStefano Zampini     for (i = 1; i < ne; i++) {
6239de2952eSStefano Zampini       PetscCall(PetscSortInt(ecount[i - 1], eneighs[i - 1]));
6249de2952eSStefano Zampini       eneighs[i] = eneighs[i - 1] + ecount[i - 1];
6259de2952eSStefano Zampini     }
6269de2952eSStefano Zampini     PetscCall(PetscMalloc1(nv + 1, &vneighs));
6279de2952eSStefano Zampini     vneighs[0] = mvleaves;
6289de2952eSStefano Zampini     for (i = 1; i < nv; i++) {
6299de2952eSStefano Zampini       PetscCall(PetscSortInt(vcount[i - 1], vneighs[i - 1]));
6309de2952eSStefano Zampini       vneighs[i] = vneighs[i - 1] + vcount[i - 1];
6319de2952eSStefano Zampini     }
6329de2952eSStefano Zampini   } else {
6339de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(el2g, NULL, NULL, &eneighs));
6349de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(vl2g, NULL, NULL, &vneighs));
6359de2952eSStefano Zampini   }
6369de2952eSStefano Zampini 
637b03ebc13SStefano Zampini   /* identify splitpoints and corner candidates */
6389566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGe, MAT_INITIAL_MATRIX, &lGt));
639a13144ffSStefano Zampini   if (print) {
6409566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGe, "edgerestr_lG"));
6419566063dSJacob Faibussowitsch     PetscCall(MatView(lGe, NULL));
6429566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "edgerestr_lGt"));
6439566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
644a13144ffSStefano Zampini   }
6459566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
6469566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(lGt, &vals));
647a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
648637e8532SStefano Zampini     PetscInt  ord = order, test = ii[i + 1] - ii[i], vc = vcount[i];
6497d871cd7SStefano Zampini     PetscBool sneighs = PETSC_TRUE, bdir = PETSC_FALSE;
650b03ebc13SStefano Zampini     if (!order) { /* variable order */
651dec27d64SStefano Zampini       PetscReal vorder = 0.;
652dec27d64SStefano Zampini 
653dec27d64SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) vorder += PetscRealPart(vals[j]);
654dec27d64SStefano Zampini       test = PetscFloorReal(vorder + 10. * PETSC_SQRT_MACHINE_EPSILON);
65563a3b9bcSJacob Faibussowitsch       PetscCheck(vorder - test <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected value for vorder: %g (%" PetscInt_FMT ")", (double)vorder, test);
656dec27d64SStefano Zampini       ord = 1;
657dec27d64SStefano Zampini     }
6586bdcaf15SBarry 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);
659637e8532SStefano Zampini     for (j = ii[i]; j < ii[i + 1] && sneighs; j++) {
6609de2952eSStefano Zampini       const PetscInt e = jj[j];
6619de2952eSStefano Zampini 
6629de2952eSStefano Zampini       if (PetscBTLookup(btbd, e)) {
6637d871cd7SStefano Zampini         bdir = PETSC_TRUE;
6647d871cd7SStefano Zampini         break;
6657d871cd7SStefano Zampini       }
6669de2952eSStefano Zampini       if (vc != ecount[e]) {
667637e8532SStefano Zampini         sneighs = PETSC_FALSE;
668637e8532SStefano Zampini       } else {
6699de2952eSStefano Zampini         const PetscInt *vn = vneighs[i], *en = eneighs[e];
6709de2952eSStefano Zampini 
6719de2952eSStefano Zampini         for (PetscInt k = 0; k < vc; k++) {
672637e8532SStefano Zampini           if (vn[k] != en[k]) {
673637e8532SStefano Zampini             sneighs = PETSC_FALSE;
674637e8532SStefano Zampini             break;
675637e8532SStefano Zampini           }
676637e8532SStefano Zampini         }
677637e8532SStefano Zampini       }
678637e8532SStefano Zampini     }
6797d871cd7SStefano Zampini     if (!sneighs || test >= 3 * ord || bdir) { /* splitpoints */
6803ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "SPLITPOINT %" PetscInt_FMT " (%s %s %s)\n", i, PetscBools[!sneighs], PetscBools[test >= 3 * ord], PetscBools[bdir]));
6819566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
682dec27d64SStefano Zampini     } else if (test == ord) {
683b03ebc13SStefano Zampini       if (order == 1 || (!order && ii[i + 1] - ii[i] == 1)) {
6843ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINT %" PetscInt_FMT "\n", i));
6859566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btv, i));
686a13144ffSStefano Zampini       } else {
6873ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "CORNER CANDIDATE %" PetscInt_FMT "\n", i));
6889566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(btvcand, i));
689a13144ffSStefano Zampini       }
690a13144ffSStefano Zampini     }
691a13144ffSStefano Zampini   }
6929566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btbd));
693b03ebc13SStefano Zampini 
694b03ebc13SStefano Zampini   /* a candidate is valid if it is connected to another candidate via a non-primal edge dof */
695b03ebc13SStefano Zampini   if (order != 1) {
6963ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "INSPECTING CANDIDATES\n"));
6979566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
698b03ebc13SStefano Zampini     for (i = 0; i < nv; i++) {
699b03ebc13SStefano Zampini       if (PetscBTLookup(btvcand, i)) {
700b03ebc13SStefano Zampini         PetscBool found = PETSC_FALSE;
701b03ebc13SStefano Zampini         for (j = ii[i]; j < ii[i + 1] && !found; j++) {
702b03ebc13SStefano Zampini           PetscInt k, e = jj[j];
703b03ebc13SStefano Zampini           if (PetscBTLookup(bte, e)) continue;
704b03ebc13SStefano Zampini           for (k = iit[e]; k < iit[e + 1]; k++) {
705b03ebc13SStefano Zampini             PetscInt v = jjt[k];
706b03ebc13SStefano Zampini             if (v != i && PetscBTLookup(btvcand, v)) {
707b03ebc13SStefano Zampini               found = PETSC_TRUE;
708b03ebc13SStefano Zampini               break;
709b03ebc13SStefano Zampini             }
710b03ebc13SStefano Zampini           }
711b03ebc13SStefano Zampini         }
712b03ebc13SStefano Zampini         if (!found) {
7133ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " CLEARED\n", i));
7149566063dSJacob Faibussowitsch           PetscCall(PetscBTClear(btvcand, i));
715b03ebc13SStefano Zampini         } else {
7163ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  CANDIDATE %" PetscInt_FMT " ACCEPTED\n", i));
717b03ebc13SStefano Zampini         }
718b03ebc13SStefano Zampini       }
719b03ebc13SStefano Zampini     }
7209566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGe, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
721b03ebc13SStefano Zampini   }
7229566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(lGt, &vals));
7239566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
7249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGe));
725a13144ffSStefano Zampini 
726a13144ffSStefano Zampini   /* Get the local G^T explicitly */
7279566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
7289566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
7299566063dSJacob Faibussowitsch   PetscCall(MatSetOption(lGt, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE));
730a13144ffSStefano Zampini 
7319de2952eSStefano Zampini   /* Mark shared nodal dofs */
7329566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvi));
7339de2952eSStefano Zampini   for (i = 0; i < nv; i++) {
7349de2952eSStefano Zampini     if (vcount[i] > 1) PetscCall(PetscBTSet(btvi, i));
735a13144ffSStefano Zampini   }
7369de2952eSStefano Zampini 
7379de2952eSStefano Zampini   if (matis->allow_repeated) {
7389de2952eSStefano Zampini     PetscCall(PetscFree(eneighs[0]));
7399de2952eSStefano Zampini     PetscCall(PetscFree(vneighs[0]));
7409de2952eSStefano Zampini     PetscCall(PetscFree(eneighs));
7419de2952eSStefano Zampini     PetscCall(PetscFree(vneighs));
7429de2952eSStefano Zampini   }
7439de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(el2g, NULL, &ecount, &eneighs));
7449de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(vl2g, NULL, &vcount, &vneighs));
745a13144ffSStefano Zampini 
746a13144ffSStefano Zampini   /* communicate corners and splitpoints */
7479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nv, &vmarks));
7489566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvleaves, nv));
7499566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(sfvroots, Lv));
7509371c9d4SSatish Balay   for (i = 0; i < nv; i++)
7519371c9d4SSatish Balay     if (PetscUnlikely(PetscBTLookup(btv, i))) sfvleaves[i] = 1;
752a13144ffSStefano Zampini 
753a13144ffSStefano Zampini   if (print) {
754a13144ffSStefano Zampini     IS tbz;
755a13144ffSStefano Zampini 
756a13144ffSStefano Zampini     cum = 0;
757a13144ffSStefano Zampini     for (i = 0; i < nv; i++)
7589371c9d4SSatish Balay       if (sfvleaves[i]) vmarks[cum++] = i;
759a13144ffSStefano Zampini 
7609566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
7619566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_local"));
7629566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
7639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
764a13144ffSStefano Zampini   }
765a13144ffSStefano Zampini 
7669566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
7679566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfv, MPIU_INT, sfvleaves, sfvroots, MPI_SUM));
7689566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
7699566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfv, MPIU_INT, sfvroots, sfvleaves, MPI_REPLACE));
770a13144ffSStefano Zampini 
7714e64d54eSstefano_zampini   /* Zero rows of lGt corresponding to identified corners
7724e64d54eSstefano_zampini      and interior nodal dofs */
773a13144ffSStefano Zampini   cum = 0;
774a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
775a13144ffSStefano Zampini     if (sfvleaves[i]) {
776a13144ffSStefano Zampini       vmarks[cum++] = i;
7779566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btv, i));
7789de2952eSStefano Zampini     } else if (!PetscBTLookup(btvi, i)) vmarks[cum++] = i;
779a13144ffSStefano Zampini   }
7809566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvi));
781a13144ffSStefano Zampini   if (print) {
782a13144ffSStefano Zampini     IS tbz;
783a13144ffSStefano Zampini 
7849566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, vmarks, PETSC_COPY_VALUES, &tbz));
7859566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)tbz, "corners_to_be_zeroed_with_interior"));
7869566063dSJacob Faibussowitsch     PetscCall(ISView(tbz, NULL));
7879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tbz));
788a13144ffSStefano Zampini   }
7899566063dSJacob Faibussowitsch   PetscCall(MatZeroRows(lGt, cum, vmarks, 0., NULL, NULL));
7909566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmarks));
7919566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfv));
7929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sfvleaves, sfvroots));
793a13144ffSStefano Zampini 
794a13144ffSStefano Zampini   /* Recompute G */
7959566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
7969566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lGt, MAT_INITIAL_MATRIX, &lG));
797a13144ffSStefano Zampini   if (print) {
7989566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lG, "used_lG"));
7999566063dSJacob Faibussowitsch     PetscCall(MatView(lG, NULL));
8009566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)lGt, "used_lGt"));
8019566063dSJacob Faibussowitsch     PetscCall(MatView(lGt, NULL));
802a13144ffSStefano Zampini   }
803a13144ffSStefano Zampini 
804a13144ffSStefano Zampini   /* Get primal dofs (if any) */
805a13144ffSStefano Zampini   cum = 0;
806a13144ffSStefano Zampini   for (i = 0; i < ne; i++) {
807a13144ffSStefano Zampini     if (PetscUnlikely(PetscBTLookup(bte, i))) marks[cum++] = i;
808a13144ffSStefano Zampini   }
8091baa6e33SBarry Smith   if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, marks, marks));
8109566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, cum, marks, PETSC_COPY_VALUES, &primals));
811a13144ffSStefano Zampini   if (print) {
8129566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "prescribed_primal_dofs"));
8139566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
814a13144ffSStefano Zampini   }
8159566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bte));
816c2151214SStefano Zampini   /* TODO: what if the user passed in some of them ?  */
8179566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
8189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&primals));
819a13144ffSStefano Zampini 
820a13144ffSStefano Zampini   /* Compute edge connectivity */
8219566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lG, "econn_"));
8224222ddf1SHong Zhang 
8234222ddf1SHong Zhang   /* Symbolic conn = lG*lGt */
8249566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(lG, lGt, NULL, &conn));
8259566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(conn, MATPRODUCT_AB));
8269566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(conn, "default"));
8279566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(conn, PETSC_DEFAULT));
8289566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)conn, "econn_"));
8299566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(conn));
8309566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(conn));
8319566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
832c2151214SStefano Zampini   if (fl2g) {
833c2151214SStefano Zampini     PetscBT   btf;
834c2151214SStefano Zampini     PetscInt *iia, *jja, *iiu, *jju;
835c2151214SStefano Zampini     PetscBool rest = PETSC_FALSE, free = PETSC_FALSE;
836c2151214SStefano Zampini 
837c2151214SStefano Zampini     /* create CSR for all local dofs */
8389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &iia));
839c2151214SStefano Zampini     if (pcbddc->mat_graph->nvtxs_csr) { /* the user has passed in a CSR graph */
84063a3b9bcSJacob 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);
841c2151214SStefano Zampini       iiu = pcbddc->mat_graph->xadj;
842c2151214SStefano Zampini       jju = pcbddc->mat_graph->adjncy;
843c2151214SStefano Zampini     } else if (pcbddc->use_local_adj) {
844c2151214SStefano Zampini       rest = PETSC_TRUE;
8459566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
846c2151214SStefano Zampini     } else {
847c2151214SStefano Zampini       free = PETSC_TRUE;
8489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n + 1, &iiu, n, &jju));
849c2151214SStefano Zampini       iiu[0] = 0;
850c2151214SStefano Zampini       for (i = 0; i < n; i++) {
851c2151214SStefano Zampini         iiu[i + 1] = i + 1;
852c2151214SStefano Zampini         jju[i]     = -1;
853d904f53bSStefano Zampini       }
854c2151214SStefano Zampini     }
855c2151214SStefano Zampini 
856c2151214SStefano Zampini     /* import sizes of CSR */
857c2151214SStefano Zampini     iia[0] = 0;
858c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] = iiu[i + 1] - iiu[i];
859c2151214SStefano Zampini 
860c2151214SStefano Zampini     /* overwrite entries corresponding to the Nedelec field */
8619566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(n, &btf));
8629566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(nedfieldlocal, &idxs));
863c2151214SStefano Zampini     for (i = 0; i < ne; i++) {
8649566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(btf, idxs[i]));
865c2151214SStefano Zampini       iia[idxs[i] + 1] = ii[i + 1] - ii[i];
866c2151214SStefano Zampini     }
867c2151214SStefano Zampini 
868c2151214SStefano Zampini     /* iia in CSR */
869c2151214SStefano Zampini     for (i = 0; i < n; i++) iia[i + 1] += iia[i];
870c2151214SStefano Zampini 
871c2151214SStefano Zampini     /* jja in CSR */
8729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(iia[n], &jja));
873c2151214SStefano Zampini     for (i = 0; i < n; i++)
874c2151214SStefano Zampini       if (!PetscBTLookup(btf, i))
8759371c9d4SSatish Balay         for (j = 0; j < iiu[i + 1] - iiu[i]; j++) jja[iia[i] + j] = jju[iiu[i] + j];
876c2151214SStefano Zampini 
877c2151214SStefano Zampini     /* map edge dofs connectivity */
8781e0482f5SStefano Zampini     if (jj) {
8799566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, ii[ne], jj, (PetscInt *)jj));
880c2151214SStefano Zampini       for (i = 0; i < ne; i++) {
881c2151214SStefano Zampini         PetscInt e = idxs[i];
882c2151214SStefano Zampini         for (j = 0; j < ii[i + 1] - ii[i]; j++) jja[iia[e] + j] = jj[ii[i] + j];
883c2151214SStefano Zampini       }
8841e0482f5SStefano Zampini     }
8859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(nedfieldlocal, &idxs));
8869566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, iia, jja, PETSC_OWN_POINTER));
88748a46eb9SPierre Jolivet     if (rest) PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_TRUE, PETSC_FALSE, &i, (const PetscInt **)&iiu, (const PetscInt **)&jju, &done));
8881baa6e33SBarry Smith     if (free) PetscCall(PetscFree2(iiu, jju));
8899566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&btf));
890c2151214SStefano Zampini   } else {
8919566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, n, ii, jj, PETSC_USE_POINTER));
892c2151214SStefano Zampini   }
893c2151214SStefano Zampini 
894a13144ffSStefano Zampini   /* Analyze interface for edge dofs */
8959566063dSJacob Faibussowitsch   PetscCall(PCBDDCAnalyzeInterface(pc));
896213b8bfaSStefano Zampini   pcbddc->mat_graph->twodim = PETSC_FALSE;
897a13144ffSStefano Zampini 
898a13144ffSStefano Zampini   /* Get coarse edges in the edge space */
8999566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
9009566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
901a13144ffSStefano Zampini 
902c2151214SStefano Zampini   if (fl2g) {
9039566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
9049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee, &eedges));
90548a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
906c2151214SStefano Zampini   } else {
907c2151214SStefano Zampini     eedges  = alleedges;
908c2151214SStefano Zampini     primals = allprimals;
909c2151214SStefano Zampini   }
910c2151214SStefano Zampini 
911a13144ffSStefano Zampini   /* Mark fine edge dofs with their coarse edge id */
9129566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(marks, ne));
9139566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
9149566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
915c2151214SStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = nee + 1;
9169566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
917c2151214SStefano Zampini   if (print) {
9189566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs"));
9199566063dSJacob Faibussowitsch     PetscCall(ISView(primals, NULL));
920c2151214SStefano Zampini   }
921c2151214SStefano Zampini 
922c2151214SStefano Zampini   maxsize = 0;
923a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
924a13144ffSStefano Zampini     PetscInt size, mark = i + 1;
925a13144ffSStefano Zampini 
9269566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
9279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
928a13144ffSStefano Zampini     for (j = 0; j < size; j++) marks[idxs[j]] = mark;
9299566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
930a13144ffSStefano Zampini     maxsize = PetscMax(maxsize, size);
931a13144ffSStefano Zampini   }
932a13144ffSStefano Zampini 
933a13144ffSStefano Zampini   /* Find coarse edge endpoints */
9349566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
9359566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
936a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
937a13144ffSStefano Zampini     PetscInt mark = i + 1, size;
938a13144ffSStefano Zampini 
9399566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
9401e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
94163a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
9429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
943a13144ffSStefano Zampini     if (print) {
94463a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "ENDPOINTS ANALYSIS EDGE %" PetscInt_FMT "\n", i));
9459566063dSJacob Faibussowitsch       PetscCall(ISView(eedges[i], NULL));
946a13144ffSStefano Zampini     }
947a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
948a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
9493ba16761SJacob Faibussowitsch       if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  idx %" PetscInt_FMT "\n", ee));
950a13144ffSStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
9513ba16761SJacob Faibussowitsch         if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    inspect %" PetscInt_FMT "\n", jj[k]));
952a13144ffSStefano Zampini         if (PetscBTLookup(btv, jj[k])) {
9533ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      corner found (already set) %" PetscInt_FMT "\n", jj[k]));
954a13144ffSStefano Zampini         } else if (PetscBTLookup(btvcand, jj[k])) { /* is it ok? */
955a13144ffSStefano Zampini           PetscInt  k2;
956a13144ffSStefano Zampini           PetscBool corner = PETSC_FALSE;
957a13144ffSStefano Zampini           for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) {
9583ba16761SJacob 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])));
959c2151214SStefano Zampini             /* it's a corner if either is connected with an edge dof belonging to a different cc or
960c2151214SStefano Zampini                if the edge dof lie on the natural part of the boundary */
961c2151214SStefano Zampini             if ((marks[jjt[k2]] && marks[jjt[k2]] != mark) || (!marks[jjt[k2]] && PetscBTLookup(btb, jjt[k2]))) {
962a13144ffSStefano Zampini               corner = PETSC_TRUE;
963a13144ffSStefano Zampini               break;
964a13144ffSStefano Zampini             }
965a13144ffSStefano Zampini           }
966a13144ffSStefano Zampini           if (corner) { /* found the nodal dof corresponding to the endpoint of the edge */
9673ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        corner found %" PetscInt_FMT "\n", jj[k]));
9689566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
969a13144ffSStefano Zampini           } else {
9703ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "        no corners found\n"));
971a13144ffSStefano Zampini           }
972a13144ffSStefano Zampini         }
973a13144ffSStefano Zampini       }
974a13144ffSStefano Zampini     }
9759566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
976a13144ffSStefano Zampini   }
9779566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
9789566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
9799566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btb));
980a13144ffSStefano Zampini 
981a13144ffSStefano Zampini   /* Reset marked primal dofs */
9829566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(primals, &cum));
9839566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(primals, &idxs));
984a13144ffSStefano Zampini   for (i = 0; i < cum; i++) marks[idxs[i]] = 0;
9859566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(primals, &idxs));
986a13144ffSStefano Zampini 
9870569b399SStefano Zampini   /* Now use the initial lG */
9889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
9899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
9900569b399SStefano Zampini   lG = lGinit;
9919566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lG, MAT_INITIAL_MATRIX, &lGt));
9920569b399SStefano Zampini 
993a13144ffSStefano Zampini   /* Compute extended cols indices */
9949566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nv, &btvc));
9959566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(nee, &bter));
9969566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
9979566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lG, &i));
998a13144ffSStefano Zampini   i *= maxsize;
9999566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extcols));
10009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(i, &extrow, i, &gidxs));
1001a13144ffSStefano Zampini   eerr = PETSC_FALSE;
1002a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1003b03ebc13SStefano Zampini     PetscInt size, found = 0;
1004a13144ffSStefano Zampini 
1005a13144ffSStefano Zampini     cum = 0;
10069566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
10071e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
100863a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
10099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
10109566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
1011a13144ffSStefano Zampini     for (j = 0; j < size; j++) {
1012a13144ffSStefano Zampini       PetscInt k, ee = idxs[j];
1013b03ebc13SStefano Zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
1014b03ebc13SStefano Zampini         PetscInt vv = jj[k];
1015b03ebc13SStefano Zampini         if (!PetscBTLookup(btv, vv)) extrow[cum++] = vv;
1016b03ebc13SStefano Zampini         else if (!PetscBTLookupSet(btvc, vv)) found++;
1017b03ebc13SStefano Zampini       }
1018a13144ffSStefano Zampini     }
10199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
10209566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
10219566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
10229566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
10239566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1024a13144ffSStefano Zampini     /* it may happen that endpoints are not defined at this point
1025a13144ffSStefano Zampini        if it is the case, mark this edge for a second pass */
1026b03ebc13SStefano Zampini     if (cum != size - 1 || found != 2) {
10279566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(bter, i));
1028a13144ffSStefano Zampini       if (print) {
10299566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge"));
10309566063dSJacob Faibussowitsch         PetscCall(ISView(eedges[i], NULL));
10319566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol"));
10329566063dSJacob Faibussowitsch         PetscCall(ISView(extcols[i], NULL));
1033a13144ffSStefano Zampini       }
1034a13144ffSStefano Zampini       eerr = PETSC_TRUE;
1035a13144ffSStefano Zampini     }
1036a13144ffSStefano Zampini   }
103728b400f6SJacob Faibussowitsch   /* PetscCheck(!eerr,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected SIZE OF EDGE > EXTCOL FIRST PASS"); */
10381c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&eerr, &done, 1, MPIU_BOOL, MPI_LOR, comm));
1039a13144ffSStefano Zampini   if (done) {
1040a13144ffSStefano Zampini     PetscInt *newprimals;
1041a13144ffSStefano Zampini 
10429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ne, &newprimals));
10439566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(primals, &cum));
10449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(primals, &idxs));
10459566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(newprimals, idxs, cum));
10469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(primals, &idxs));
10479566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
10483ba16761SJacob Faibussowitsch     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOING SECOND PASS (eerr %s)\n", PetscBools[eerr]));
1049a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1050b03ebc13SStefano Zampini       PetscBool has_candidates = PETSC_FALSE;
1051b03ebc13SStefano Zampini       if (PetscBTLookup(bter, i)) {
1052a13144ffSStefano Zampini         PetscInt size, mark = i + 1;
1053a13144ffSStefano Zampini 
10549566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(eedges[i], &size));
10559566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(eedges[i], &idxs));
1056c2151214SStefano Zampini         /* for (j=0;j<size;j++) newprimals[cum++] = idxs[j]; */
1057a13144ffSStefano Zampini         for (j = 0; j < size; j++) {
1058a13144ffSStefano Zampini           PetscInt k, ee = idxs[j];
10593ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Inspecting edge dof %" PetscInt_FMT " [%" PetscInt_FMT " %" PetscInt_FMT ")\n", ee, ii[ee], ii[ee + 1]));
1060a13144ffSStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
1061a13144ffSStefano Zampini             /* set all candidates located on the edge as corners */
1062a13144ffSStefano Zampini             if (PetscBTLookup(btvcand, jj[k])) {
1063a13144ffSStefano Zampini               PetscInt k2, vv = jj[k];
1064b03ebc13SStefano Zampini               has_candidates = PETSC_TRUE;
10653ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Candidate set to vertex %" PetscInt_FMT "\n", vv));
10669566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(btv, vv));
1067a13144ffSStefano Zampini               /* set all edge dofs connected to candidate as primals */
1068a13144ffSStefano Zampini               for (k2 = iit[vv]; k2 < iit[vv + 1]; k2++) {
1069a13144ffSStefano Zampini                 if (marks[jjt[k2]] == mark) {
1070a13144ffSStefano Zampini                   PetscInt k3, ee2 = jjt[k2];
10713ba16761SJacob Faibussowitsch                   if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Connected edge dof set to primal %" PetscInt_FMT "\n", ee2));
1072a13144ffSStefano Zampini                   newprimals[cum++] = ee2;
1073a13144ffSStefano Zampini                   /* finally set the new corners */
1074a13144ffSStefano Zampini                   for (k3 = ii[ee2]; k3 < ii[ee2 + 1]; k3++) {
10753ba16761SJacob Faibussowitsch                     if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Connected nodal dof set to vertex %" PetscInt_FMT "\n", jj[k3]));
10769566063dSJacob Faibussowitsch                     PetscCall(PetscBTSet(btv, jj[k3]));
1077a13144ffSStefano Zampini                   }
1078a13144ffSStefano Zampini                 }
1079a13144ffSStefano Zampini               }
1080b03ebc13SStefano Zampini             } else {
10813ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Not a candidate vertex %" PetscInt_FMT "\n", jj[k]));
1082a13144ffSStefano Zampini             }
1083a13144ffSStefano Zampini           }
1084a13144ffSStefano Zampini         }
1085b03ebc13SStefano Zampini         if (!has_candidates) { /* circular edge */
1086b03ebc13SStefano Zampini           PetscInt k, ee = idxs[0], *tmarks;
1087b03ebc13SStefano Zampini 
10889566063dSJacob Faibussowitsch           PetscCall(PetscCalloc1(ne, &tmarks));
10893ba16761SJacob Faibussowitsch           if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Circular edge %" PetscInt_FMT "\n", i));
1090b03ebc13SStefano Zampini           for (k = ii[ee]; k < ii[ee + 1]; k++) {
1091b03ebc13SStefano Zampini             PetscInt k2;
10923ba16761SJacob Faibussowitsch             if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Set to corner %" PetscInt_FMT "\n", jj[k]));
10939566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(btv, jj[k]));
1094b03ebc13SStefano Zampini             for (k2 = iit[jj[k]]; k2 < iit[jj[k] + 1]; k2++) tmarks[jjt[k2]]++;
1095b03ebc13SStefano Zampini           }
1096b03ebc13SStefano Zampini           for (j = 0; j < size; j++) {
1097b03ebc13SStefano Zampini             if (tmarks[idxs[j]] > 1) {
10983ba16761SJacob Faibussowitsch               if (print) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge dof set to primal %" PetscInt_FMT "\n", idxs[j]));
1099b03ebc13SStefano Zampini               newprimals[cum++] = idxs[j];
1100b03ebc13SStefano Zampini             }
1101b03ebc13SStefano Zampini           }
11029566063dSJacob Faibussowitsch           PetscCall(PetscFree(tmarks));
1103b03ebc13SStefano Zampini         }
11049566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(eedges[i], &idxs));
1105a13144ffSStefano Zampini       }
11069566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&extcols[i]));
1107a13144ffSStefano Zampini     }
11089566063dSJacob Faibussowitsch     PetscCall(PetscFree(extcols));
11099566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &iit, &jjt, &done));
11109566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&cum, newprimals));
1111c2151214SStefano Zampini     if (fl2g) {
11129566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(fl2g, cum, newprimals, newprimals));
11139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&primals));
111448a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
11159566063dSJacob Faibussowitsch       PetscCall(PetscFree(eedges));
1116c2151214SStefano Zampini     }
11179566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
11189566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, cum, newprimals, PETSC_COPY_VALUES, &primals));
11199566063dSJacob Faibussowitsch     PetscCall(PetscFree(newprimals));
11209566063dSJacob Faibussowitsch     PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primals));
11219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
11229566063dSJacob Faibussowitsch     PetscCall(PCBDDCAnalyzeInterface(pc));
1123213b8bfaSStefano Zampini     pcbddc->mat_graph->twodim = PETSC_FALSE;
11249566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
1125c2151214SStefano Zampini     if (fl2g) {
11269566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, allprimals, &primals));
11279566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nee, &eedges));
112848a46eb9SPierre Jolivet       for (i = 0; i < nee; i++) PetscCall(ISGlobalToLocalMappingApplyIS(fl2g, IS_GTOLM_DROP, alleedges[i], &eedges[i]));
1129c2151214SStefano Zampini     } else {
1130c2151214SStefano Zampini       eedges  = alleedges;
1131c2151214SStefano Zampini       primals = allprimals;
1132c2151214SStefano Zampini     }
11339566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nee, &extcols));
1134a13144ffSStefano Zampini 
1135a13144ffSStefano Zampini     /* Mark again */
11369566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(marks, ne));
1137a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1138a13144ffSStefano Zampini       PetscInt size, mark = i + 1;
1139a13144ffSStefano Zampini 
11409566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
11419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1142a13144ffSStefano Zampini       for (j = 0; j < size; j++) marks[idxs[j]] = mark;
11439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
1144a13144ffSStefano Zampini     }
1145a13144ffSStefano Zampini     if (print) {
11469566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)primals, "obtained_primal_dofs_secondpass"));
11479566063dSJacob Faibussowitsch       PetscCall(ISView(primals, NULL));
1148a13144ffSStefano Zampini     }
1149a13144ffSStefano Zampini 
1150a13144ffSStefano Zampini     /* Recompute extended cols */
1151a13144ffSStefano Zampini     eerr = PETSC_FALSE;
1152a13144ffSStefano Zampini     for (i = 0; i < nee; i++) {
1153a13144ffSStefano Zampini       PetscInt size;
1154a13144ffSStefano Zampini 
1155a13144ffSStefano Zampini       cum = 0;
11569566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(eedges[i], &size));
11571e0482f5SStefano Zampini       if (!size && nedfieldlocal) continue;
115863a3b9bcSJacob Faibussowitsch       PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
11599566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &idxs));
1160a13144ffSStefano Zampini       for (j = 0; j < size; j++) {
1161a13144ffSStefano Zampini         PetscInt k, ee = idxs[j];
11629371c9d4SSatish Balay         for (k = ii[ee]; k < ii[ee + 1]; k++)
11639371c9d4SSatish Balay           if (!PetscBTLookup(btv, jj[k])) extrow[cum++] = jj[k];
1164a13144ffSStefano Zampini       }
11659566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &idxs));
11669566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&cum, extrow));
11679566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(vl2g, cum, extrow, gidxs));
11689566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(cum, gidxs, extrow));
11699566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cum, extrow, PETSC_COPY_VALUES, &extcols[i]));
1170a13144ffSStefano Zampini       if (cum != size - 1) {
1171a13144ffSStefano Zampini         if (print) {
11729566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)eedges[i], "error_edge_secondpass"));
11739566063dSJacob Faibussowitsch           PetscCall(ISView(eedges[i], NULL));
11749566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)extcols[i], "error_extcol_secondpass"));
11759566063dSJacob Faibussowitsch           PetscCall(ISView(extcols[i], NULL));
1176a13144ffSStefano Zampini         }
1177a13144ffSStefano Zampini         eerr = PETSC_TRUE;
1178a13144ffSStefano Zampini       }
1179a13144ffSStefano Zampini     }
1180a13144ffSStefano Zampini   }
11819566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11829566063dSJacob Faibussowitsch   PetscCall(PetscFree2(extrow, gidxs));
11839566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&bter));
11849566063dSJacob Faibussowitsch   if (print) PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, 5, PETSC_VIEWER_STDOUT_SELF));
1185a13144ffSStefano Zampini   /* an error should not occur at this point */
118628b400f6SJacob Faibussowitsch   PetscCheck(!eerr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SIZE OF EDGE > EXTCOL SECOND PASS");
1187a13144ffSStefano Zampini 
11884e64d54eSstefano_zampini   /* Check the number of endpoints */
11899566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
11909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * nee, &corners));
11919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &cedges));
11924e64d54eSstefano_zampini   for (i = 0; i < nee; i++) {
1193b03ebc13SStefano Zampini     PetscInt size, found = 0, gc[2];
11944e64d54eSstefano_zampini 
1195b03ebc13SStefano Zampini     /* init with defaults */
1196b03ebc13SStefano Zampini     cedges[i] = corners[i * 2] = corners[i * 2 + 1] = -1;
11979566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(eedges[i], &size));
11981e0482f5SStefano Zampini     if (!size && nedfieldlocal) continue;
119963a3b9bcSJacob Faibussowitsch     PetscCheck(size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected zero sized edge %" PetscInt_FMT, i);
12009566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(eedges[i], &idxs));
12019566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(nv, btvc));
12024e64d54eSstefano_zampini     for (j = 0; j < size; j++) {
12034e64d54eSstefano_zampini       PetscInt k, ee = idxs[j];
12044e64d54eSstefano_zampini       for (k = ii[ee]; k < ii[ee + 1]; k++) {
12054e64d54eSstefano_zampini         PetscInt vv = jj[k];
12064e64d54eSstefano_zampini         if (PetscBTLookup(btv, vv) && !PetscBTLookupSet(btvc, vv)) {
1207467446fbSPierre Jolivet           PetscCheck(found != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more than two corners for edge %" PetscInt_FMT, i);
1208b03ebc13SStefano Zampini           corners[i * 2 + found++] = vv;
12094e64d54eSstefano_zampini         }
12104e64d54eSstefano_zampini       }
12114e64d54eSstefano_zampini     }
1212b03ebc13SStefano Zampini     if (found != 2) {
1213b03ebc13SStefano Zampini       PetscInt e;
1214b03ebc13SStefano Zampini       if (fl2g) {
12159566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingApply(fl2g, 1, idxs, &e));
1216b03ebc13SStefano Zampini       } else {
1217b03ebc13SStefano Zampini         e = idxs[0];
1218b03ebc13SStefano Zampini       }
121963a3b9bcSJacob 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]);
1220b03ebc13SStefano Zampini     }
1221eee23b56SStefano Zampini 
1222eee23b56SStefano Zampini     /* get primal dof index on this coarse edge */
12239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(vl2g, 2, corners + 2 * i, gc));
1224b03ebc13SStefano Zampini     if (gc[0] > gc[1]) {
1225b03ebc13SStefano Zampini       PetscInt swap      = corners[2 * i];
1226b03ebc13SStefano Zampini       corners[2 * i]     = corners[2 * i + 1];
1227b03ebc13SStefano Zampini       corners[2 * i + 1] = swap;
1228b03ebc13SStefano Zampini     }
1229eee23b56SStefano Zampini     cedges[i] = idxs[size - 1];
12309566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(eedges[i], &idxs));
12313ba16761SJacob 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]));
12324e64d54eSstefano_zampini   }
12339566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lG, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12349566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvc));
12354e64d54eSstefano_zampini 
123676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
1237a13144ffSStefano Zampini     /* Inspects columns of lG (rows of lGt) and make sure the change of basis will
1238a13144ffSStefano Zampini      not interfere with neighbouring coarse edges */
12399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nee + 1, &emarks));
12409566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
1241a13144ffSStefano Zampini     for (i = 0; i < nv; i++) {
1242a13144ffSStefano Zampini       PetscInt emax = 0, eemax = 0;
1243a13144ffSStefano Zampini 
1244a13144ffSStefano Zampini       if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
12459566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(emarks, nee + 1));
1246a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) emarks[marks[jj[j]]]++;
1247a13144ffSStefano Zampini       for (j = 1; j < nee + 1; j++) {
1248a13144ffSStefano Zampini         if (emax < emarks[j]) {
1249a13144ffSStefano Zampini           emax  = emarks[j];
1250a13144ffSStefano Zampini           eemax = j;
1251a13144ffSStefano Zampini         }
1252a13144ffSStefano Zampini       }
1253a13144ffSStefano Zampini       /* not relevant for edges */
1254a13144ffSStefano Zampini       if (!eemax) continue;
1255a13144ffSStefano Zampini 
1256a13144ffSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
12577a46b595SBarry 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]);
1258a13144ffSStefano Zampini       }
1259a13144ffSStefano Zampini     }
12609566063dSJacob Faibussowitsch     PetscCall(PetscFree(emarks));
12619566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
126276bd3646SJed Brown   }
1263a13144ffSStefano Zampini 
1264a13144ffSStefano Zampini   /* Compute extended rows indices for edge blocks of the change of basis */
12659566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12669566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetMaxRowNonzeros(lGt, &extmem));
1267a13144ffSStefano Zampini   extmem *= maxsize;
12689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(extmem * nee, &extrow));
12699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nee, &extrows));
12709566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nee, &extrowcum));
1271a13144ffSStefano Zampini   for (i = 0; i < nv; i++) {
1272a13144ffSStefano Zampini     PetscInt mark = 0, size, start;
1273213b8bfaSStefano Zampini 
1274a13144ffSStefano Zampini     if (ii[i + 1] == ii[i] || PetscBTLookup(btv, i)) continue;
1275a13144ffSStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++)
12769371c9d4SSatish Balay       if (marks[jj[j]] && !mark) mark = marks[jj[j]];
1277a13144ffSStefano Zampini 
1278a13144ffSStefano Zampini     /* not relevant */
1279a13144ffSStefano Zampini     if (!mark) continue;
1280a13144ffSStefano Zampini 
1281a13144ffSStefano Zampini     /* import extended row */
1282a13144ffSStefano Zampini     mark--;
1283a13144ffSStefano Zampini     start = mark * extmem + extrowcum[mark];
1284a13144ffSStefano Zampini     size  = ii[i + 1] - ii[i];
128563a3b9bcSJacob Faibussowitsch     PetscCheck(extrowcum[mark] + size <= extmem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not enough memory allocated %" PetscInt_FMT " > %" PetscInt_FMT, extrowcum[mark] + size, extmem);
12869566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(extrow + start, jj + ii[i], size));
1287a13144ffSStefano Zampini     extrowcum[mark] += size;
1288a13144ffSStefano Zampini   }
12899566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(lGt, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &done));
12909566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lGt));
12919566063dSJacob Faibussowitsch   PetscCall(PetscFree(marks));
1292213b8bfaSStefano Zampini 
1293213b8bfaSStefano Zampini   /* Compress extrows */
1294a13144ffSStefano Zampini   cum = 0;
1295a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1296a13144ffSStefano Zampini     PetscInt size = extrowcum[i], *start = extrow + i * extmem;
12979566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&size, start));
12989566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, start, PETSC_USE_POINTER, &extrows[i]));
1299a13144ffSStefano Zampini     cum = PetscMax(cum, size);
1300a13144ffSStefano Zampini   }
13019566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrowcum));
13029566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btv));
13039566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&btvcand));
1304a13144ffSStefano Zampini 
1305a13144ffSStefano Zampini   /* Workspace for lapack inner calls and VecSetValues */
13069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2((5 + cum + maxsize) * maxsize, &work, maxsize, &rwork));
1307a13144ffSStefano Zampini 
1308a13144ffSStefano Zampini   /* Create change of basis matrix (preallocation can be improved) */
13099566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &T));
13109de2952eSStefano Zampini   PetscCall(MatSetLayouts(T, pc->mat->rmap, pc->mat->cmap));
13119566063dSJacob Faibussowitsch   PetscCall(MatSetType(T, MATAIJ));
13129de2952eSStefano Zampini   PetscCall(MatSeqAIJSetPreallocation(T, maxsize, NULL));
13139de2952eSStefano Zampini   PetscCall(MatMPIAIJSetPreallocation(T, maxsize, NULL, maxsize, NULL));
13149566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(T, al2g, al2g));
13159566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
13169566063dSJacob Faibussowitsch   PetscCall(MatSetOption(T, MAT_ROW_ORIENTED, PETSC_FALSE));
13179566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&al2g));
1318a13144ffSStefano Zampini 
1319a13144ffSStefano Zampini   /* Defaults to identity */
13209de2952eSStefano Zampini   for (i = pc->mat->rmap->rstart; i < pc->mat->rmap->rend; i++) PetscCall(MatSetValue(T, i, i, 1.0, INSERT_VALUES));
1321a13144ffSStefano Zampini 
13221e0482f5SStefano Zampini   /* Create discrete gradient for the coarser level if needed */
13239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
13249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
13251e0482f5SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) {
13261e0482f5SStefano Zampini     ISLocalToGlobalMapping cel2g, cvl2g;
13271e0482f5SStefano Zampini     IS                     wis, gwis;
13281e0482f5SStefano Zampini     PetscInt               cnv, cne;
13291e0482f5SStefano Zampini 
13309566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, nee, cedges, PETSC_COPY_VALUES, &wis));
13311e0482f5SStefano Zampini     if (fl2g) {
13329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(fl2g, wis, &pcbddc->nedclocal));
13331e0482f5SStefano Zampini     } else {
13349566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)wis));
13351e0482f5SStefano Zampini       pcbddc->nedclocal = wis;
13361e0482f5SStefano Zampini     }
13379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(el2g, wis, &gwis));
13389566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13399566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cne, &wis));
13409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cel2g));
13419566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13429566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13431e0482f5SStefano Zampini 
13449566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, 2 * nee, corners, PETSC_USE_POINTER, &wis));
13459566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(vl2g, wis, &gwis));
13469566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13479566063dSJacob Faibussowitsch     PetscCall(ISRenumber(gwis, NULL, &cnv, &wis));
13489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(wis, &cvl2g));
13499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&wis));
13509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gwis));
13511e0482f5SStefano Zampini 
13529566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &pcbddc->nedcG));
13539566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->nedcG, PETSC_DECIDE, PETSC_DECIDE, cne, cnv));
13549566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->nedcG, MATAIJ));
13559566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->nedcG, 2, NULL));
13569566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(pcbddc->nedcG, 2, NULL, 2, NULL));
13579566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->nedcG, cel2g, cvl2g));
13589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cel2g));
13599566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cvl2g));
13601e0482f5SStefano Zampini   }
13619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&vl2g));
13621e0482f5SStefano Zampini 
13631e0482f5SStefano Zampini #if defined(PRINT_GDET)
13641e0482f5SStefano Zampini   inc = 0;
13651e0482f5SStefano Zampini   lev = pcbddc->current_level;
13661e0482f5SStefano Zampini #endif
1367213b8bfaSStefano Zampini 
1368213b8bfaSStefano Zampini   /* Insert values in the change of basis matrix */
1369a13144ffSStefano Zampini   for (i = 0; i < nee; i++) {
1370a13144ffSStefano Zampini     Mat         Gins = NULL, GKins = NULL;
13711e0482f5SStefano Zampini     IS          cornersis = NULL;
13721e0482f5SStefano Zampini     PetscScalar cvals[2];
1373a13144ffSStefano Zampini 
137448a46eb9SPierre Jolivet     if (pcbddc->nedcG) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners + 2 * i, PETSC_USE_POINTER, &cornersis));
13759566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputeNedelecChangeEdge(lG, eedges[i], extrows[i], extcols[i], cornersis, &Gins, &GKins, cvals, work, rwork));
1376a13144ffSStefano Zampini     if (Gins && GKins) {
13771683a169SBarry Smith       const PetscScalar *data;
1378a13144ffSStefano Zampini       const PetscInt    *rows, *cols;
1379a13144ffSStefano Zampini       PetscInt           nrh, nch, nrc, ncc;
1380a13144ffSStefano Zampini 
13819566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(eedges[i], &cols));
1382a13144ffSStefano Zampini       /* H1 */
13839566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(extrows[i], &rows));
13849566063dSJacob Faibussowitsch       PetscCall(MatGetSize(Gins, &nrh, &nch));
13859566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Gins, &data));
13869566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrh, rows, nch, cols, data, INSERT_VALUES));
13879566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Gins, &data));
13889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(extrows[i], &rows));
1389a13144ffSStefano Zampini       /* complement */
13909566063dSJacob Faibussowitsch       PetscCall(MatGetSize(GKins, &nrc, &ncc));
139163a3b9bcSJacob Faibussowitsch       PetscCheck(ncc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Constant function has not been generated for coarse edge %" PetscInt_FMT, i);
139263a3b9bcSJacob 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);
139363a3b9bcSJacob 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);
13949566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(GKins, &data));
13959566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(T, nrc, cols, ncc, cols + nch, data, INSERT_VALUES));
13969566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(GKins, &data));
13971e0482f5SStefano Zampini 
13981e0482f5SStefano Zampini       /* coarse discrete gradient */
13991e0482f5SStefano Zampini       if (pcbddc->nedcG) {
14001e0482f5SStefano Zampini         PetscInt cols[2];
14011e0482f5SStefano Zampini 
14021e0482f5SStefano Zampini         cols[0] = 2 * i;
14031e0482f5SStefano Zampini         cols[1] = 2 * i + 1;
14049566063dSJacob Faibussowitsch         PetscCall(MatSetValuesLocal(pcbddc->nedcG, 1, &i, 2, cols, cvals, INSERT_VALUES));
14051e0482f5SStefano Zampini       }
14069566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(eedges[i], &cols));
1407a13144ffSStefano Zampini     }
14089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extrows[i]));
14099566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&extcols[i]));
14109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cornersis));
14119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Gins));
14129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&GKins));
1413a13144ffSStefano Zampini   }
14149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&el2g));
1415a13144ffSStefano Zampini 
1416a13144ffSStefano Zampini   /* Start assembling */
14179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
14181baa6e33SBarry Smith   if (pcbddc->nedcG) PetscCall(MatAssemblyBegin(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1419a13144ffSStefano Zampini 
1420a13144ffSStefano Zampini   /* Free */
1421c2151214SStefano Zampini   if (fl2g) {
14229566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primals));
142348a46eb9SPierre Jolivet     for (i = 0; i < nee; i++) PetscCall(ISDestroy(&eedges[i]));
14249566063dSJacob Faibussowitsch     PetscCall(PetscFree(eedges));
1425c2151214SStefano Zampini   }
1426eee23b56SStefano Zampini 
1427eee23b56SStefano Zampini   /* hack mat_graph with primal dofs on the coarse edges */
1428eee23b56SStefano Zampini   {
1429eee23b56SStefano Zampini     PCBDDCGraph graph  = pcbddc->mat_graph;
1430eee23b56SStefano Zampini     PetscInt   *oqueue = graph->queue;
1431eee23b56SStefano Zampini     PetscInt   *ocptr  = graph->cptr;
1432eee23b56SStefano Zampini     PetscInt    ncc, *idxs;
1433eee23b56SStefano Zampini 
1434eee23b56SStefano Zampini     /* find first primal edge */
1435eee23b56SStefano Zampini     if (pcbddc->nedclocal) {
14369566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
1437eee23b56SStefano Zampini     } else {
14381baa6e33SBarry Smith       if (fl2g) PetscCall(ISLocalToGlobalMappingApply(fl2g, nee, cedges, cedges));
1439eee23b56SStefano Zampini       idxs = cedges;
1440eee23b56SStefano Zampini     }
1441eee23b56SStefano Zampini     cum = 0;
1442eee23b56SStefano Zampini     while (cum < nee && cedges[cum] < 0) cum++;
1443eee23b56SStefano Zampini 
1444eee23b56SStefano Zampini     /* adapt connected components */
14459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(graph->nvtxs + 1, &graph->cptr, ocptr[graph->ncc], &graph->queue));
1446eee23b56SStefano Zampini     graph->cptr[0] = 0;
1447eee23b56SStefano Zampini     for (i = 0, ncc = 0; i < graph->ncc; i++) {
1448eee23b56SStefano Zampini       PetscInt lc = ocptr[i + 1] - ocptr[i];
1449eee23b56SStefano Zampini       if (cum != nee && oqueue[ocptr[i + 1] - 1] == cedges[cum]) { /* this cc has a primal dof */
1450eee23b56SStefano Zampini         graph->cptr[ncc + 1]           = graph->cptr[ncc] + 1;
1451eee23b56SStefano Zampini         graph->queue[graph->cptr[ncc]] = cedges[cum];
1452eee23b56SStefano Zampini         ncc++;
1453eee23b56SStefano Zampini         lc--;
1454eee23b56SStefano Zampini         cum++;
1455eee23b56SStefano Zampini         while (cum < nee && cedges[cum] < 0) cum++;
1456eee23b56SStefano Zampini       }
1457eee23b56SStefano Zampini       graph->cptr[ncc + 1] = graph->cptr[ncc] + lc;
1458eee23b56SStefano Zampini       for (j = 0; j < lc; j++) graph->queue[graph->cptr[ncc] + j] = oqueue[ocptr[i] + j];
1459eee23b56SStefano Zampini       ncc++;
1460eee23b56SStefano Zampini     }
1461eee23b56SStefano Zampini     graph->ncc = ncc;
146248a46eb9SPierre Jolivet     if (pcbddc->nedclocal) PetscCall(ISRestoreIndices(pcbddc->nedclocal, (const PetscInt **)&idxs));
14639566063dSJacob Faibussowitsch     PetscCall(PetscFree2(ocptr, oqueue));
1464eee23b56SStefano Zampini   }
14659566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&fl2g));
14669566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, &nee, &alleedges, &allprimals));
14679566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(pcbddc->mat_graph));
14689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
1469eee23b56SStefano Zampini 
14709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&nedfieldlocal));
14719566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrow));
14729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(work, rwork));
14739566063dSJacob Faibussowitsch   PetscCall(PetscFree(corners));
14749566063dSJacob Faibussowitsch   PetscCall(PetscFree(cedges));
14759566063dSJacob Faibussowitsch   PetscCall(PetscFree(extrows));
14769566063dSJacob Faibussowitsch   PetscCall(PetscFree(extcols));
14779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lG));
1478a13144ffSStefano Zampini 
1479a13144ffSStefano Zampini   /* Complete assembling */
14809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
14819de2952eSStefano Zampini   PetscCall(MatViewFromOptions(T, (PetscObject)pc, "-pc_bddc_nedelec_change_view"));
14821e0482f5SStefano Zampini   if (pcbddc->nedcG) {
14839566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->nedcG, MAT_FINAL_ASSEMBLY));
1484*a4cdd7efSStefano Zampini     PetscCall(MatViewFromOptions(pcbddc->nedcG, (PetscObject)pc, "-pc_bddc_nedelec_coarse_change_view"));
14851e0482f5SStefano Zampini   }
1486a13144ffSStefano Zampini 
1487a13144ffSStefano Zampini   /* set change of basis */
14889566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetChangeOfBasisMat(pc, T, singular));
14899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
14903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1491a13144ffSStefano Zampini }
1492a13144ffSStefano Zampini 
1493d8203eabSStefano Zampini /* the near-null space of BDDC carries information on quadrature weights,
1494d8203eabSStefano Zampini    and these can be collinear -> so cheat with MatNullSpaceCreate
1495d8203eabSStefano Zampini    and create a suitable set of basis vectors first */
1496d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCNullSpaceCreate(MPI_Comm comm, PetscBool has_const, PetscInt nvecs, Vec quad_vecs[], MatNullSpace *nnsp)
1497d71ae5a4SJacob Faibussowitsch {
1498d8203eabSStefano Zampini   PetscInt i;
1499d8203eabSStefano Zampini 
1500d8203eabSStefano Zampini   PetscFunctionBegin;
1501d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) {
1502d8203eabSStefano Zampini     PetscInt first, last;
1503d8203eabSStefano Zampini 
15049566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
15057827d75bSBarry Smith     PetscCheck(last - first >= 2 * nvecs || !has_const, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented");
1506d8203eabSStefano Zampini     if (i >= first && i < last) {
1507d8203eabSStefano Zampini       PetscScalar *data;
15089566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1509d8203eabSStefano Zampini       if (!has_const) {
1510d8203eabSStefano Zampini         data[i - first] = 1.;
1511d8203eabSStefano Zampini       } else {
151286fa73c5SStefano Zampini         data[2 * i - first]     = 1. / PetscSqrtReal(2.);
151386fa73c5SStefano Zampini         data[2 * i - first + 1] = -1. / PetscSqrtReal(2.);
1514d8203eabSStefano Zampini       }
15159566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1516d8203eabSStefano Zampini     }
15179566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
1518d8203eabSStefano Zampini   }
15199566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, has_const, nvecs, quad_vecs, nnsp));
1520d8203eabSStefano Zampini   for (i = 0; i < nvecs; i++) { /* reset vectors */
1521d8203eabSStefano Zampini     PetscInt first, last;
15229566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(quad_vecs[i]));
15239566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(quad_vecs[i], &first, &last));
1524d8203eabSStefano Zampini     if (i >= first && i < last) {
1525d8203eabSStefano Zampini       PetscScalar *data;
15269566063dSJacob Faibussowitsch       PetscCall(VecGetArray(quad_vecs[i], &data));
1527d8203eabSStefano Zampini       if (!has_const) {
1528d8203eabSStefano Zampini         data[i - first] = 0.;
1529d8203eabSStefano Zampini       } else {
153086fa73c5SStefano Zampini         data[2 * i - first]     = 0.;
153186fa73c5SStefano Zampini         data[2 * i - first + 1] = 0.;
1532d8203eabSStefano Zampini       }
15339566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(quad_vecs[i], &data));
1534d8203eabSStefano Zampini     }
15359566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)quad_vecs[i]));
15369566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(quad_vecs[i]));
1537d8203eabSStefano Zampini   }
15383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1539d8203eabSStefano Zampini }
1540d8203eabSStefano Zampini 
1541d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeNoNetFlux(Mat A, Mat divudotp, PetscBool transpose, IS vl2l, PCBDDCGraph graph, MatNullSpace *nnsp)
1542d71ae5a4SJacob Faibussowitsch {
1543a198735bSStefano Zampini   Mat                    loc_divudotp;
15449de2952eSStefano Zampini   Vec                    p, v, quad_vec;
15458ae0ca82SStefano Zampini   ISLocalToGlobalMapping map;
15469de2952eSStefano Zampini   PetscScalar           *array;
1547669cc0f4SStefano Zampini 
1548669cc0f4SStefano Zampini   PetscFunctionBegin;
15499566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &quad_vec, NULL));
15508ae0ca82SStefano Zampini   if (!transpose) {
15519566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, &map, NULL));
15528ae0ca82SStefano Zampini   } else {
15539566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(A, NULL, &map));
15548ae0ca82SStefano Zampini   }
15559de2952eSStefano Zampini   PetscCall(PCBDDCNullSpaceCreate(PetscObjectComm((PetscObject)A), PETSC_FALSE, 1, &quad_vec, nnsp));
15569de2952eSStefano Zampini   PetscCall(VecLockReadPop(quad_vec));
15579de2952eSStefano Zampini   PetscCall(VecSetLocalToGlobalMapping(quad_vec, map));
1558d8203eabSStefano Zampini 
1559669cc0f4SStefano Zampini   /* compute local quad vec */
15609566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(divudotp, &loc_divudotp));
15618ae0ca82SStefano Zampini   if (!transpose) {
15629566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &v, &p));
15638ae0ca82SStefano Zampini   } else {
15649566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(loc_divudotp, &p, &v));
15658ae0ca82SStefano Zampini   }
15669de2952eSStefano Zampini   /* the assumption here is that the constant vector interpolates the constant on the L2 conforming space */
15679566063dSJacob Faibussowitsch   PetscCall(VecSet(p, 1.));
15688ae0ca82SStefano Zampini   if (!transpose) {
15699566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(loc_divudotp, p, v));
15708ae0ca82SStefano Zampini   } else {
15719566063dSJacob Faibussowitsch     PetscCall(MatMult(loc_divudotp, p, v));
15728ae0ca82SStefano Zampini   }
15739de2952eSStefano Zampini   PetscCall(VecDestroy(&p));
1574fa23a32eSStefano Zampini   if (vl2l) {
1575187c917aSStefano Zampini     Mat        lA;
1576187c917aSStefano Zampini     VecScatter sc;
15779de2952eSStefano Zampini     Vec        vins;
1578187c917aSStefano Zampini 
15799566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(A, &lA));
15809566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(lA, &vins, NULL));
15819566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(v, NULL, vins, vl2l, &sc));
15829566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
15839566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sc, v, vins, INSERT_VALUES, SCATTER_FORWARD));
15849566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sc));
15859566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&v));
15869de2952eSStefano Zampini     v = vins;
1587669cc0f4SStefano Zampini   }
15889de2952eSStefano Zampini 
15899de2952eSStefano Zampini   /* mask summation of interface values */
15909de2952eSStefano Zampini   PetscInt        n, *mmask, *mask, *idxs, nmr, nr;
15919de2952eSStefano Zampini   const PetscInt *degree;
15929de2952eSStefano Zampini   PetscSF         msf;
15939de2952eSStefano Zampini 
15949de2952eSStefano Zampini   PetscCall(VecGetLocalSize(v, &n));
15959de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nr, NULL, NULL, NULL));
15969de2952eSStefano Zampini   PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf));
15979de2952eSStefano Zampini   PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
15989de2952eSStefano Zampini   PetscCall(PetscCalloc3(nmr, &mmask, n, &mask, n, &idxs));
15999de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &degree));
16009de2952eSStefano Zampini   PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &degree));
16019de2952eSStefano Zampini   for (PetscInt i = 0, c = 0; i < nr; i++) {
16029de2952eSStefano Zampini     mmask[c] = 1;
16039de2952eSStefano Zampini     c += degree[i];
16049de2952eSStefano Zampini   }
16059de2952eSStefano Zampini   PetscCall(PetscSFScatterBegin(graph->interface_subset_sf, MPIU_INT, mmask, mask));
16069de2952eSStefano Zampini   PetscCall(PetscSFScatterEnd(graph->interface_subset_sf, MPIU_INT, mmask, mask));
16079de2952eSStefano Zampini   PetscCall(VecGetArray(v, &array));
16089de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
16099de2952eSStefano Zampini     array[i] *= mask[i];
16109de2952eSStefano Zampini     idxs[i] = i;
16119de2952eSStefano Zampini   }
16129de2952eSStefano Zampini   PetscCall(VecSetValuesLocal(quad_vec, n, idxs, array, ADD_VALUES));
16139de2952eSStefano Zampini   PetscCall(VecRestoreArray(v, &array));
16149de2952eSStefano Zampini   PetscCall(PetscFree3(mmask, mask, idxs));
16159de2952eSStefano Zampini   PetscCall(VecDestroy(&v));
16169de2952eSStefano Zampini   PetscCall(VecAssemblyBegin(quad_vec));
16179de2952eSStefano Zampini   PetscCall(VecAssemblyEnd(quad_vec));
16189de2952eSStefano Zampini   PetscCall(VecViewFromOptions(quad_vec, NULL, "-pc_bddc_quad_vec_view"));
16199de2952eSStefano Zampini   PetscCall(VecLockReadPush(quad_vec));
16209de2952eSStefano Zampini   PetscCall(VecDestroy(&quad_vec));
16213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1622669cc0f4SStefano Zampini }
1623669cc0f4SStefano Zampini 
1624d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAddPrimalVerticesLocalIS(PC pc, IS primalv)
1625d71ae5a4SJacob Faibussowitsch {
16267620a527SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
16277620a527SStefano Zampini 
16287620a527SStefano Zampini   PetscFunctionBegin;
16297620a527SStefano Zampini   if (primalv) {
16307620a527SStefano Zampini     if (pcbddc->user_primal_vertices_local) {
16317620a527SStefano Zampini       IS list[2], newp;
16327620a527SStefano Zampini 
16337620a527SStefano Zampini       list[0] = primalv;
16347620a527SStefano Zampini       list[1] = pcbddc->user_primal_vertices_local;
16359566063dSJacob Faibussowitsch       PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), 2, list, &newp));
16369566063dSJacob Faibussowitsch       PetscCall(ISSortRemoveDups(newp));
16379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&list[1]));
16387620a527SStefano Zampini       pcbddc->user_primal_vertices_local = newp;
16397620a527SStefano Zampini     } else {
16409566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesLocalIS(pc, primalv));
16417620a527SStefano Zampini     }
16427620a527SStefano Zampini   }
16433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16447620a527SStefano Zampini }
1645669cc0f4SStefano Zampini 
1646d71ae5a4SJacob Faibussowitsch static PetscErrorCode func_coords_private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *out, void *ctx)
1647d71ae5a4SJacob Faibussowitsch {
16481c7a958bSStefano Zampini   PetscInt f, *comp = (PetscInt *)ctx;
16491c7a958bSStefano Zampini 
16501c7a958bSStefano Zampini   PetscFunctionBegin;
16511c7a958bSStefano Zampini   for (f = 0; f < Nf; f++) out[f] = X[*comp];
16523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16531c7a958bSStefano Zampini }
1654674ae819SStefano Zampini 
1655d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalTopologyInfo(PC pc)
1656d71ae5a4SJacob Faibussowitsch {
16571f4df5f7SStefano Zampini   Vec       local, global;
16581f4df5f7SStefano Zampini   PC_BDDC  *pcbddc     = (PC_BDDC *)pc->data;
16591f4df5f7SStefano Zampini   Mat_IS   *matis      = (Mat_IS *)pc->pmat->data;
16605c5e10d6SStefano Zampini   PetscBool monolithic = PETSC_FALSE;
16611f4df5f7SStefano Zampini 
16621f4df5f7SStefano Zampini   PetscFunctionBegin;
1663d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC topology options", "PC");
16649566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_bddc_monolithic", "Discard any information on dofs splitting", NULL, monolithic, &monolithic, NULL));
1665d0609cedSBarry Smith   PetscOptionsEnd();
16661f4df5f7SStefano Zampini   /* need to convert from global to local topology information and remove references to information in global ordering */
16679566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pc->pmat, &global, NULL));
16689566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(matis->A, &local, NULL));
16699566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(global, PETSC_TRUE));
16709566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(local, PETSC_TRUE));
16716a8fc67bSStefano Zampini   if (monolithic) { /* just get block size to properly compute vertices */
167248a46eb9SPierre Jolivet     if (pcbddc->vertex_size == 1) PetscCall(MatGetBlockSize(pc->pmat, &pcbddc->vertex_size));
16736a8fc67bSStefano Zampini     goto boundary;
16746a8fc67bSStefano Zampini   }
16755c5e10d6SStefano Zampini 
16761f4df5f7SStefano Zampini   if (pcbddc->user_provided_isfordofs) {
16771f4df5f7SStefano Zampini     if (pcbddc->n_ISForDofs) {
16781f4df5f7SStefano Zampini       PetscInt i;
16790c85b387SStefano Zampini 
16809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->n_ISForDofs, &pcbddc->ISForDofsLocal));
16811f4df5f7SStefano Zampini       for (i = 0; i < pcbddc->n_ISForDofs; i++) {
16820c85b387SStefano Zampini         PetscInt bs;
16830c85b387SStefano Zampini 
16849566063dSJacob Faibussowitsch         PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->ISForDofs[i], &pcbddc->ISForDofsLocal[i]));
16859566063dSJacob Faibussowitsch         PetscCall(ISGetBlockSize(pcbddc->ISForDofs[i], &bs));
16869566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
16879566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
16881f4df5f7SStefano Zampini       }
16891f4df5f7SStefano Zampini       pcbddc->n_ISForDofsLocal = pcbddc->n_ISForDofs;
16901f4df5f7SStefano Zampini       pcbddc->n_ISForDofs      = 0;
16919566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->ISForDofs));
16921f4df5f7SStefano Zampini     }
16931f4df5f7SStefano Zampini   } else {
169421ef3d20SStefano Zampini     if (!pcbddc->n_ISForDofsLocal) { /* field split not present */
169521ef3d20SStefano Zampini       DM dm;
169621ef3d20SStefano Zampini 
16979566063dSJacob Faibussowitsch       PetscCall(MatGetDM(pc->pmat, &dm));
169848a46eb9SPierre Jolivet       if (!dm) PetscCall(PCGetDM(pc, &dm));
169921ef3d20SStefano Zampini       if (dm) {
170021ef3d20SStefano Zampini         IS      *fields;
170121ef3d20SStefano Zampini         PetscInt nf, i;
17020c85b387SStefano Zampini 
17039566063dSJacob Faibussowitsch         PetscCall(DMCreateFieldDecomposition(dm, &nf, NULL, &fields, NULL));
17049566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nf, &pcbddc->ISForDofsLocal));
170521ef3d20SStefano Zampini         for (i = 0; i < nf; i++) {
17060c85b387SStefano Zampini           PetscInt bs;
17070c85b387SStefano Zampini 
17089566063dSJacob Faibussowitsch           PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, fields[i], &pcbddc->ISForDofsLocal[i]));
17099566063dSJacob Faibussowitsch           PetscCall(ISGetBlockSize(fields[i], &bs));
17109566063dSJacob Faibussowitsch           PetscCall(ISSetBlockSize(pcbddc->ISForDofsLocal[i], bs));
17119566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
171221ef3d20SStefano Zampini         }
17139566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
171421ef3d20SStefano Zampini         pcbddc->n_ISForDofsLocal = nf;
171521ef3d20SStefano Zampini       } else { /* See if MATIS has fields attached by the conversion from MatNest */
171621ef3d20SStefano Zampini         PetscContainer c;
171721ef3d20SStefano Zampini 
17189566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)pc->pmat, "_convert_nest_lfields", (PetscObject *)&c));
171921ef3d20SStefano Zampini         if (c) {
172021ef3d20SStefano Zampini           MatISLocalFields lf;
17219566063dSJacob Faibussowitsch           PetscCall(PetscContainerGetPointer(c, (void **)&lf));
17229566063dSJacob Faibussowitsch           PetscCall(PCBDDCSetDofsSplittingLocal(pc, lf->nr, lf->rf));
172321ef3d20SStefano Zampini         } else { /* fallback, create the default fields if bs > 1 */
17241f4df5f7SStefano Zampini           PetscInt i, n = matis->A->rmap->n;
17259566063dSJacob Faibussowitsch           PetscCall(MatGetBlockSize(pc->pmat, &i));
172621ef3d20SStefano Zampini           if (i > 1) {
1727986cdee1SStefano Zampini             pcbddc->n_ISForDofsLocal = i;
17289566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pcbddc->ISForDofsLocal));
172948a46eb9SPierre 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]));
17301f4df5f7SStefano Zampini           }
173121ef3d20SStefano Zampini         }
173221ef3d20SStefano Zampini       }
17337a0e7b2cSstefano_zampini     } else {
17347a0e7b2cSstefano_zampini       PetscInt i;
173548a46eb9SPierre Jolivet       for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->ISForDofsLocal[i]));
17361f4df5f7SStefano Zampini     }
1737986cdee1SStefano Zampini   }
17381f4df5f7SStefano Zampini 
17395c5e10d6SStefano Zampini boundary:
17401f4df5f7SStefano Zampini   if (!pcbddc->DirichletBoundariesLocal && pcbddc->DirichletBoundaries) {
17419566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->DirichletBoundaries, &pcbddc->DirichletBoundariesLocal));
17427a0e7b2cSstefano_zampini   } else if (pcbddc->DirichletBoundariesLocal) {
17439566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LAND, &pcbddc->DirichletBoundariesLocal));
17441f4df5f7SStefano Zampini   }
17451f4df5f7SStefano Zampini   if (!pcbddc->NeumannBoundariesLocal && pcbddc->NeumannBoundaries) {
17469566063dSJacob Faibussowitsch     PetscCall(PCBDDCGlobalToLocal(matis->rctx, global, local, pcbddc->NeumannBoundaries, &pcbddc->NeumannBoundariesLocal));
17477a0e7b2cSstefano_zampini   } else if (pcbddc->NeumannBoundariesLocal) {
17489566063dSJacob Faibussowitsch     PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->NeumannBoundariesLocal));
17491f4df5f7SStefano Zampini   }
175048a46eb9SPierre 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));
17519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&global));
17529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&local));
17539de2952eSStefano Zampini   /* detect local disconnected subdomains if requested or needed */
17549de2952eSStefano Zampini   if (pcbddc->detect_disconnected || matis->allow_repeated) {
17557620a527SStefano Zampini     IS        primalv = NULL;
17567620a527SStefano Zampini     PetscInt  i;
17578361f951SStefano Zampini     PetscBool filter = pcbddc->detect_disconnected_filter;
17587a0e7b2cSstefano_zampini 
175948a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
17609566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->local_subs));
17619566063dSJacob Faibussowitsch     PetscCall(PCBDDCDetectDisconnectedComponents(pc, filter, &pcbddc->n_local_subs, &pcbddc->local_subs, &primalv));
17629566063dSJacob Faibussowitsch     PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, primalv));
17639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&primalv));
17647620a527SStefano Zampini   }
17657620a527SStefano Zampini   /* early stage corner detection */
17667620a527SStefano Zampini   {
17677620a527SStefano Zampini     DM dm;
17687620a527SStefano Zampini 
17699566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
177048a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
17717620a527SStefano Zampini     if (dm) {
17727620a527SStefano Zampini       PetscBool isda;
17737620a527SStefano Zampini 
17749566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
17757620a527SStefano Zampini       if (isda) {
17767620a527SStefano Zampini         ISLocalToGlobalMapping l2l;
17777620a527SStefano Zampini         IS                     corners;
17787620a527SStefano Zampini         Mat                    lA;
17794f819b78SStefano Zampini         PetscBool              gl, lo;
17807620a527SStefano Zampini 
17814f819b78SStefano Zampini         {
17824f819b78SStefano Zampini           Vec                cvec;
17834f819b78SStefano Zampini           const PetscScalar *coords;
17844f819b78SStefano Zampini           PetscInt           dof, n, cdim;
17854f819b78SStefano Zampini           PetscBool          memc = PETSC_TRUE;
17864f819b78SStefano Zampini 
17879566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
17889566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinates(dm, &cvec));
17899566063dSJacob Faibussowitsch           PetscCall(VecGetLocalSize(cvec, &n));
17909566063dSJacob Faibussowitsch           PetscCall(VecGetBlockSize(cvec, &cdim));
17914f819b78SStefano Zampini           n /= cdim;
17929566063dSJacob Faibussowitsch           PetscCall(PetscFree(pcbddc->mat_graph->coords));
17939566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(dof * n * cdim, &pcbddc->mat_graph->coords));
17949566063dSJacob Faibussowitsch           PetscCall(VecGetArrayRead(cvec, &coords));
17954f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
17964f819b78SStefano Zampini           memc = PETSC_FALSE;
17974f819b78SStefano Zampini #endif
17984f819b78SStefano Zampini           if (dof != 1) memc = PETSC_FALSE;
17994f819b78SStefano Zampini           if (memc) {
18009566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(pcbddc->mat_graph->coords, coords, cdim * n * dof));
18014f819b78SStefano Zampini           } else { /* BDDC graph does not use any blocked information, we need to replicate the data */
18024f819b78SStefano Zampini             PetscReal *bcoords = pcbddc->mat_graph->coords;
18034f819b78SStefano Zampini             PetscInt   i, b, d;
18044f819b78SStefano Zampini 
18054f819b78SStefano Zampini             for (i = 0; i < n; i++) {
18064f819b78SStefano Zampini               for (b = 0; b < dof; b++) {
1807ad540459SPierre Jolivet                 for (d = 0; d < cdim; d++) bcoords[i * dof * cdim + b * cdim + d] = PetscRealPart(coords[i * cdim + d]);
18084f819b78SStefano Zampini               }
18094f819b78SStefano Zampini             }
18104f819b78SStefano Zampini           }
18119566063dSJacob Faibussowitsch           PetscCall(VecRestoreArrayRead(cvec, &coords));
18124f819b78SStefano Zampini           pcbddc->mat_graph->cdim  = cdim;
18134f819b78SStefano Zampini           pcbddc->mat_graph->cnloc = dof * n;
18144f819b78SStefano Zampini           pcbddc->mat_graph->cloc  = PETSC_FALSE;
18154f819b78SStefano Zampini         }
18169566063dSJacob Faibussowitsch         PetscCall(DMDAGetSubdomainCornersIS(dm, &corners));
18179566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pc->pmat, &lA));
18189566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(lA, &l2l, NULL));
18199566063dSJacob Faibussowitsch         PetscCall(MatISRestoreLocalMat(pc->pmat, &lA));
18204f819b78SStefano Zampini         lo = (PetscBool)(l2l && corners);
18211c2dc1cbSBarry Smith         PetscCall(MPIU_Allreduce(&lo, &gl, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
18224f819b78SStefano Zampini         if (gl) { /* From PETSc's DMDA */
18237620a527SStefano Zampini           const PetscInt *idx;
182472ed36d8SStefano Zampini           PetscInt        dof, bs, *idxout, n;
18257620a527SStefano Zampini 
18269566063dSJacob Faibussowitsch           PetscCall(DMDAGetInfo(dm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
18279566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetBlockSize(l2l, &bs));
18289566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(corners, &n));
18299566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(corners, &idx));
183072ed36d8SStefano Zampini           if (bs == dof) {
18319566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(n, &idxout));
18329566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApplyBlock(l2l, n, idx, idxout));
183372ed36d8SStefano Zampini           } else { /* the original DMDA local-to-local map have been modified */
183472ed36d8SStefano Zampini             PetscInt i, d;
183572ed36d8SStefano Zampini 
18369566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(dof * n, &idxout));
18379371c9d4SSatish Balay             for (i = 0; i < n; i++)
18389371c9d4SSatish Balay               for (d = 0; d < dof; d++) idxout[dof * i + d] = dof * idx[i] + d;
18399566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingApply(l2l, dof * n, idxout, idxout));
184072ed36d8SStefano Zampini 
184172ed36d8SStefano Zampini             bs = 1;
184272ed36d8SStefano Zampini             n *= dof;
184372ed36d8SStefano Zampini           }
18449566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(corners, &idx));
18459566063dSJacob Faibussowitsch           PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
18469566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)pc), bs, n, idxout, PETSC_OWN_POINTER, &corners));
18479566063dSJacob Faibussowitsch           PetscCall(PCBDDCAddPrimalVerticesLocalIS(pc, corners));
18489566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&corners));
18491c7a958bSStefano Zampini           pcbddc->corner_selected  = PETSC_TRUE;
18504f819b78SStefano Zampini           pcbddc->corner_selection = PETSC_TRUE;
18514f819b78SStefano Zampini         }
185248a46eb9SPierre Jolivet         if (corners) PetscCall(DMDARestoreSubdomainCornersIS(dm, &corners));
18537620a527SStefano Zampini       }
18547620a527SStefano Zampini     }
18557620a527SStefano Zampini   }
18561c7a958bSStefano Zampini   if (pcbddc->corner_selection && !pcbddc->mat_graph->cdim) {
18571c7a958bSStefano Zampini     DM dm;
18581c7a958bSStefano Zampini 
18599566063dSJacob Faibussowitsch     PetscCall(MatGetDM(pc->pmat, &dm));
186048a46eb9SPierre Jolivet     if (!dm) PetscCall(PCGetDM(pc, &dm));
18614f819b78SStefano Zampini     if (dm) { /* this can get very expensive, I need to find a faster alternative */
18621c7a958bSStefano Zampini       Vec          vcoords;
18631c7a958bSStefano Zampini       PetscSection section;
18641c7a958bSStefano Zampini       PetscReal   *coords;
18651c7a958bSStefano Zampini       PetscInt     d, cdim, nl, nf, **ctxs;
18661c7a958bSStefano Zampini       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
186751ab8ad6SStefano Zampini       /* debug coordinates */
186851ab8ad6SStefano Zampini       PetscViewer       viewer;
186951ab8ad6SStefano Zampini       PetscBool         flg;
187051ab8ad6SStefano Zampini       PetscViewerFormat format;
187151ab8ad6SStefano Zampini       const char       *prefix;
18721c7a958bSStefano Zampini 
18739566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(dm, &cdim));
18749566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
18759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(section, &nf));
18769566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(dm, &vcoords));
18779566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(vcoords, &nl));
18789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &coords));
18799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(nf, &funcs, nf, &ctxs));
18809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nf, &ctxs[0]));
18811c7a958bSStefano Zampini       for (d = 0; d < nf; d++) funcs[d] = func_coords_private;
18821c7a958bSStefano Zampini       for (d = 1; d < nf; d++) ctxs[d] = ctxs[d - 1] + 1;
188351ab8ad6SStefano Zampini 
188451ab8ad6SStefano Zampini       /* debug coordinates */
188551ab8ad6SStefano Zampini       PetscCall(PCGetOptionsPrefix(pc, &prefix));
188651ab8ad6SStefano Zampini       PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)vcoords), ((PetscObject)vcoords)->options, prefix, "-pc_bddc_coords_vec_view", &viewer, &format, &flg));
188751ab8ad6SStefano Zampini       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
18881c7a958bSStefano Zampini       for (d = 0; d < cdim; d++) {
18891c7a958bSStefano Zampini         PetscInt           i;
18901c7a958bSStefano Zampini         const PetscScalar *v;
189151ab8ad6SStefano Zampini         char               name[16];
18921c7a958bSStefano Zampini 
18931c7a958bSStefano Zampini         for (i = 0; i < nf; i++) ctxs[i][0] = d;
189451ab8ad6SStefano Zampini         PetscCall(PetscSNPrintf(name, sizeof(name), "bddc_coords_%d", (int)d));
189551ab8ad6SStefano Zampini         PetscCall(PetscObjectSetName((PetscObject)vcoords, name));
18969566063dSJacob Faibussowitsch         PetscCall(DMProjectFunction(dm, 0.0, funcs, (void **)ctxs, INSERT_VALUES, vcoords));
189751ab8ad6SStefano Zampini         if (flg) PetscCall(VecView(vcoords, viewer));
18989566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vcoords, &v));
18991c7a958bSStefano Zampini         for (i = 0; i < nl; i++) coords[i * cdim + d] = PetscRealPart(v[i]);
19009566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vcoords, &v));
19011c7a958bSStefano Zampini       }
19029566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&vcoords));
19039566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc, cdim, nl, coords));
19049566063dSJacob Faibussowitsch       PetscCall(PetscFree(coords));
19059566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctxs[0]));
19069566063dSJacob Faibussowitsch       PetscCall(PetscFree2(funcs, ctxs));
190751ab8ad6SStefano Zampini       if (flg) {
190851ab8ad6SStefano Zampini         PetscCall(PetscViewerPopFormat(viewer));
1909cd791dc2SBarry Smith         PetscCall(PetscOptionsRestoreViewer(&viewer));
191051ab8ad6SStefano Zampini       }
19111c7a958bSStefano Zampini     }
19121c7a958bSStefano Zampini   }
19133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19147a0e7b2cSstefano_zampini }
19157a0e7b2cSstefano_zampini 
1916d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConsistencyCheckIS(PC pc, MPI_Op mop, IS *is)
1917d71ae5a4SJacob Faibussowitsch {
1918f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
19197a0e7b2cSstefano_zampini   IS              nis;
19207a0e7b2cSstefano_zampini   const PetscInt *idxs;
19217a0e7b2cSstefano_zampini   PetscInt        i, nd, n = matis->A->rmap->n, *nidxs, nnd;
19227a0e7b2cSstefano_zampini 
19237a0e7b2cSstefano_zampini   PetscFunctionBegin;
19247827d75bSBarry Smith   PetscCheck(mop == MPI_LAND || mop == MPI_LOR, PetscObjectComm((PetscObject)(pc)), PETSC_ERR_SUP, "Supported are MPI_LAND and MPI_LOR");
19257a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
19267a0e7b2cSstefano_zampini     /* init rootdata with true */
19271bd50df1SStefano Zampini     for (i = 0; i < pc->pmat->rmap->n; i++) matis->sf_rootdata[i] = 1;
19287a0e7b2cSstefano_zampini   } else {
19299566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, pc->pmat->rmap->n));
19307a0e7b2cSstefano_zampini   }
19319566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, n));
19329566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(*is, &nd));
19339566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(*is, &idxs));
19347a0e7b2cSstefano_zampini   for (i = 0; i < nd; i++)
19359371c9d4SSatish Balay     if (-1 < idxs[i] && idxs[i] < n) matis->sf_leafdata[idxs[i]] = 1;
19369566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(*is, &idxs));
19379566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
19389566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, mop));
19399566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
19409566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
19417a0e7b2cSstefano_zampini   if (mop == MPI_LAND) {
19429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nd, &nidxs));
19437a0e7b2cSstefano_zampini   } else {
19449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nidxs));
19457a0e7b2cSstefano_zampini   }
19467a0e7b2cSstefano_zampini   for (i = 0, nnd = 0; i < n; i++)
19479371c9d4SSatish Balay     if (matis->sf_leafdata[i]) nidxs[nnd++] = i;
1948f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)*is), nnd, nidxs, PETSC_OWN_POINTER, &nis));
19499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(is));
19507a0e7b2cSstefano_zampini   *is = nis;
19513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19521f4df5f7SStefano Zampini }
19531f4df5f7SStefano Zampini 
1954d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignRemoveInterior(PC pc, Vec r, Vec z)
1955d71ae5a4SJacob Faibussowitsch {
1956f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
1957f4f49eeaSPierre Jolivet   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
19583e589ea0SStefano Zampini 
19593e589ea0SStefano Zampini   PetscFunctionBegin;
19603ba16761SJacob Faibussowitsch   if (!pcbddc->benign_have_null) PetscFunctionReturn(PETSC_SUCCESS);
19613e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
19623e589ea0SStefano Zampini     Vec swap;
19633e589ea0SStefano Zampini 
19649566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
19653e589ea0SStefano Zampini     swap                = pcbddc->work_change;
19663e589ea0SStefano Zampini     pcbddc->work_change = r;
19673e589ea0SStefano Zampini     r                   = swap;
19683e589ea0SStefano Zampini   }
19699566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
19709566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
19719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
19729566063dSJacob Faibussowitsch   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
19739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
19749566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
19759566063dSJacob Faibussowitsch   PetscCall(VecSet(z, 0.));
19769566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
19779566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
19783e589ea0SStefano Zampini   if (pcbddc->ChangeOfBasisMatrix) {
1979f913dca9SStefano Zampini     pcbddc->work_change = r;
19809566063dSJacob Faibussowitsch     PetscCall(VecCopy(z, pcbddc->work_change));
19819566063dSJacob Faibussowitsch     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
19823e589ea0SStefano Zampini   }
19833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19843e589ea0SStefano Zampini }
19853e589ea0SStefano Zampini 
1986ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private_Private(Mat A, Vec x, Vec y, PetscBool transpose)
1987d71ae5a4SJacob Faibussowitsch {
1988a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
1989a3df083aSStefano Zampini   PetscBool               apply_right, apply_left, reset_x;
1990a3df083aSStefano Zampini 
1991a3df083aSStefano Zampini   PetscFunctionBegin;
19929566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
1993a3df083aSStefano Zampini   if (transpose) {
1994a3df083aSStefano Zampini     apply_right = ctx->apply_left;
1995a3df083aSStefano Zampini     apply_left  = ctx->apply_right;
1996a3df083aSStefano Zampini   } else {
1997a3df083aSStefano Zampini     apply_right = ctx->apply_right;
1998a3df083aSStefano Zampini     apply_left  = ctx->apply_left;
1999a3df083aSStefano Zampini   }
2000a3df083aSStefano Zampini   reset_x = PETSC_FALSE;
2001a3df083aSStefano Zampini   if (apply_right) {
2002a3df083aSStefano Zampini     const PetscScalar *ax;
2003a3df083aSStefano Zampini     PetscInt           nl, i;
2004a3df083aSStefano Zampini 
20059566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(x, &nl));
20069566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &ax));
20079566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(ctx->work, ax, nl));
20089566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &ax));
2009a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2010a3df083aSStefano Zampini       PetscScalar     sum, val;
2011a3df083aSStefano Zampini       const PetscInt *idxs;
2012a3df083aSStefano Zampini       PetscInt        nz, j;
20139566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
20149566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2015a3df083aSStefano Zampini       sum = 0.;
2016a3df083aSStefano Zampini       if (ctx->apply_p0) {
2017a3df083aSStefano Zampini         val = ctx->work[idxs[nz - 1]];
2018a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2019a3df083aSStefano Zampini           sum += ctx->work[idxs[j]];
2020a3df083aSStefano Zampini           ctx->work[idxs[j]] += val;
2021a3df083aSStefano Zampini         }
2022a3df083aSStefano Zampini       } else {
2023ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) sum += ctx->work[idxs[j]];
2024a3df083aSStefano Zampini       }
2025a3df083aSStefano Zampini       ctx->work[idxs[nz - 1]] -= sum;
20269566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2027a3df083aSStefano Zampini     }
20289566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(x, ctx->work));
2029a3df083aSStefano Zampini     reset_x = PETSC_TRUE;
2030a3df083aSStefano Zampini   }
2031a3df083aSStefano Zampini   if (transpose) {
20329566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->A, x, y));
2033a3df083aSStefano Zampini   } else {
20349566063dSJacob Faibussowitsch     PetscCall(MatMult(ctx->A, x, y));
2035a3df083aSStefano Zampini   }
20361baa6e33SBarry Smith   if (reset_x) PetscCall(VecResetArray(x));
2037a3df083aSStefano Zampini   if (apply_left) {
2038a3df083aSStefano Zampini     PetscScalar *ay;
2039a3df083aSStefano Zampini     PetscInt     i;
2040a3df083aSStefano Zampini 
20419566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &ay));
2042a3df083aSStefano Zampini     for (i = 0; i < ctx->benign_n; i++) {
2043a3df083aSStefano Zampini       PetscScalar     sum, val;
2044a3df083aSStefano Zampini       const PetscInt *idxs;
2045a3df083aSStefano Zampini       PetscInt        nz, j;
20469566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ctx->benign_zerodiag_subs[i], &nz));
20479566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ctx->benign_zerodiag_subs[i], &idxs));
2048a3df083aSStefano Zampini       val = -ay[idxs[nz - 1]];
2049a3df083aSStefano Zampini       if (ctx->apply_p0) {
2050a3df083aSStefano Zampini         sum = 0.;
2051a3df083aSStefano Zampini         for (j = 0; j < nz - 1; j++) {
2052a3df083aSStefano Zampini           sum += ay[idxs[j]];
2053a3df083aSStefano Zampini           ay[idxs[j]] += val;
2054a3df083aSStefano Zampini         }
2055a3df083aSStefano Zampini         ay[idxs[nz - 1]] += sum;
2056a3df083aSStefano Zampini       } else {
2057ad540459SPierre Jolivet         for (j = 0; j < nz - 1; j++) ay[idxs[j]] += val;
2058a3df083aSStefano Zampini         ay[idxs[nz - 1]] = 0.;
2059a3df083aSStefano Zampini       }
20609566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ctx->benign_zerodiag_subs[i], &idxs));
2061a3df083aSStefano Zampini     }
20629566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &ay));
2063a3df083aSStefano Zampini   }
20643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2065a3df083aSStefano Zampini }
2066a3df083aSStefano Zampini 
2067ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMultTranspose_Private(Mat A, Vec x, Vec y)
2068d71ae5a4SJacob Faibussowitsch {
2069a3df083aSStefano Zampini   PetscFunctionBegin;
20709566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_TRUE));
20713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2072a3df083aSStefano Zampini }
2073a3df083aSStefano Zampini 
2074ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignMatMult_Private(Mat A, Vec x, Vec y)
2075d71ae5a4SJacob Faibussowitsch {
2076a3df083aSStefano Zampini   PetscFunctionBegin;
20779566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignMatMult_Private_Private(A, x, y, PETSC_FALSE));
20783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2079a3df083aSStefano Zampini }
2080a3df083aSStefano Zampini 
2081d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignShellMat(PC pc, PetscBool restore)
2082d71ae5a4SJacob Faibussowitsch {
2083a3df083aSStefano Zampini   PC_IS                  *pcis   = (PC_IS *)pc->data;
2084a3df083aSStefano Zampini   PC_BDDC                *pcbddc = (PC_BDDC *)pc->data;
2085a3df083aSStefano Zampini   PCBDDCBenignMatMult_ctx ctx;
2086a3df083aSStefano Zampini 
2087a3df083aSStefano Zampini   PetscFunctionBegin;
2088a3df083aSStefano Zampini   if (!restore) {
20891dd7afcfSStefano Zampini     Mat                A_IB, A_BI;
2090a3df083aSStefano Zampini     PetscScalar       *work;
2091b334f244SStefano Zampini     PCBDDCReuseSolvers reuse = pcbddc->sub_schurs ? pcbddc->sub_schurs->reuse_solver : NULL;
2092a3df083aSStefano Zampini 
209328b400f6SJacob Faibussowitsch     PetscCheck(!pcbddc->benign_original_mat, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Benign original mat has not been restored");
20943ba16761SJacob Faibussowitsch     if (!pcbddc->benign_change || !pcbddc->benign_n || pcbddc->benign_change_explicit) PetscFunctionReturn(PETSC_SUCCESS);
20959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &work));
20969566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &A_IB));
20979566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(A_IB, pcis->n - pcis->n_B, pcis->n_B, PETSC_DECIDE, PETSC_DECIDE));
20989566063dSJacob Faibussowitsch     PetscCall(MatSetType(A_IB, MATSHELL));
20999566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT, (void (*)(void))PCBDDCBenignMatMult_Private));
21009566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(A_IB, MATOP_MULT_TRANSPOSE, (void (*)(void))PCBDDCBenignMatMultTranspose_Private));
21019566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
21029566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(A_IB, ctx));
2103a3df083aSStefano Zampini     ctx->apply_left  = PETSC_TRUE;
2104a3df083aSStefano Zampini     ctx->apply_right = PETSC_FALSE;
2105a3df083aSStefano Zampini     ctx->apply_p0    = PETSC_FALSE;
2106a3df083aSStefano Zampini     ctx->benign_n    = pcbddc->benign_n;
2107059032f7SStefano Zampini     if (reuse) {
2108a3df083aSStefano Zampini       ctx->benign_zerodiag_subs = reuse->benign_zerodiag_subs;
21091dd7afcfSStefano Zampini       ctx->free                 = PETSC_FALSE;
2110059032f7SStefano Zampini     } else { /* TODO: could be optimized for successive solves */
2111059032f7SStefano Zampini       ISLocalToGlobalMapping N_to_D;
2112059032f7SStefano Zampini       PetscInt               i;
2113059032f7SStefano Zampini 
21149566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(pcis->is_I_local, &N_to_D));
21159566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->benign_n, &ctx->benign_zerodiag_subs));
211648a46eb9SPierre 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]));
21179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&N_to_D));
21181dd7afcfSStefano Zampini       ctx->free = PETSC_TRUE;
2119059032f7SStefano Zampini     }
2120a3df083aSStefano Zampini     ctx->A    = pcis->A_IB;
2121a3df083aSStefano Zampini     ctx->work = work;
21229566063dSJacob Faibussowitsch     PetscCall(MatSetUp(A_IB));
21239566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A_IB, MAT_FINAL_ASSEMBLY));
21249566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A_IB, MAT_FINAL_ASSEMBLY));
2125a3df083aSStefano Zampini     pcis->A_IB = A_IB;
2126a3df083aSStefano Zampini 
2127a3df083aSStefano Zampini     /* A_BI as A_IB^T */
21289566063dSJacob Faibussowitsch     PetscCall(MatCreateTranspose(A_IB, &A_BI));
2129a3df083aSStefano Zampini     pcbddc->benign_original_mat = pcis->A_BI;
2130a3df083aSStefano Zampini     pcis->A_BI                  = A_BI;
2131a3df083aSStefano Zampini   } else {
21323ba16761SJacob Faibussowitsch     if (!pcbddc->benign_original_mat) PetscFunctionReturn(PETSC_SUCCESS);
21339566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(pcis->A_IB, &ctx));
21349566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_IB));
2135a3df083aSStefano Zampini     pcis->A_IB = ctx->A;
21361dd7afcfSStefano Zampini     ctx->A     = NULL;
21379566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcis->A_BI));
21381dd7afcfSStefano Zampini     pcis->A_BI                  = pcbddc->benign_original_mat;
21391dd7afcfSStefano Zampini     pcbddc->benign_original_mat = NULL;
21401dd7afcfSStefano Zampini     if (ctx->free) {
2141059032f7SStefano Zampini       PetscInt i;
214248a46eb9SPierre Jolivet       for (i = 0; i < ctx->benign_n; i++) PetscCall(ISDestroy(&ctx->benign_zerodiag_subs[i]));
21439566063dSJacob Faibussowitsch       PetscCall(PetscFree(ctx->benign_zerodiag_subs));
2144059032f7SStefano Zampini     }
21459566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx->work));
21469566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
2147a3df083aSStefano Zampini   }
21483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2149a3df083aSStefano Zampini }
2150a3df083aSStefano Zampini 
2151a3df083aSStefano Zampini /* used just in bddc debug mode */
2152ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCBenignProject(PC pc, IS is1, IS is2, Mat *B)
2153d71ae5a4SJacob Faibussowitsch {
2154a3df083aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2155a3df083aSStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
2156a3df083aSStefano Zampini   Mat      An;
2157a3df083aSStefano Zampini 
2158a3df083aSStefano Zampini   PetscFunctionBegin;
21599566063dSJacob Faibussowitsch   PetscCall(MatPtAP(matis->A, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &An));
21609566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns(An, pcbddc->benign_n, pcbddc->benign_p0_lidx, 1.0, NULL, NULL));
2161a3df083aSStefano Zampini   if (is1) {
21629566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(An, is1, is2, MAT_INITIAL_MATRIX, B));
21639566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&An));
2164a3df083aSStefano Zampini   } else {
2165a3df083aSStefano Zampini     *B = An;
2166a3df083aSStefano Zampini   }
21673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2168a3df083aSStefano Zampini }
2169a3df083aSStefano Zampini 
21701cf9b237SStefano Zampini /* TODO: add reuse flag */
2171d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSeqAIJCompress(Mat A, Mat *B)
2172d71ae5a4SJacob Faibussowitsch {
21731cf9b237SStefano Zampini   Mat             Bt;
21741cf9b237SStefano Zampini   PetscScalar    *a, *bdata;
21751cf9b237SStefano Zampini   const PetscInt *ii, *ij;
21761cf9b237SStefano Zampini   PetscInt        m, n, i, nnz, *bii, *bij;
21771cf9b237SStefano Zampini   PetscBool       flg_row;
21781cf9b237SStefano Zampini 
21791cf9b237SStefano Zampini   PetscFunctionBegin;
21809566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &m));
21819566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
21829566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(A, &a));
21831cf9b237SStefano Zampini   nnz = n;
21841cf9b237SStefano Zampini   for (i = 0; i < ii[n]; i++) {
21851cf9b237SStefano Zampini     if (PetscLikely(PetscAbsScalar(a[i]) > PETSC_SMALL)) nnz++;
21861cf9b237SStefano Zampini   }
21879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n + 1, &bii));
21889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bij));
21899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &bdata));
21901cf9b237SStefano Zampini   nnz    = 0;
21911cf9b237SStefano Zampini   bii[0] = 0;
21921cf9b237SStefano Zampini   for (i = 0; i < n; i++) {
21931cf9b237SStefano Zampini     PetscInt j;
21941cf9b237SStefano Zampini     for (j = ii[i]; j < ii[i + 1]; j++) {
21951cf9b237SStefano Zampini       PetscScalar entry = a[j];
21963272d46bSStefano Zampini       if (PetscLikely(PetscAbsScalar(entry) > PETSC_SMALL) || (n == m && ij[j] == i)) {
21971cf9b237SStefano Zampini         bij[nnz]   = ij[j];
21981cf9b237SStefano Zampini         bdata[nnz] = entry;
21991cf9b237SStefano Zampini         nnz++;
22001cf9b237SStefano Zampini       }
22011cf9b237SStefano Zampini     }
22021cf9b237SStefano Zampini     bii[i + 1] = nnz;
22031cf9b237SStefano Zampini   }
22049566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(A, &a));
22059566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, m, bii, bij, bdata, &Bt));
22069566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &ij, &flg_row));
22071cf9b237SStefano Zampini   {
2208f4f49eeaSPierre Jolivet     Mat_SeqAIJ *b = (Mat_SeqAIJ *)Bt->data;
22091cf9b237SStefano Zampini     b->free_a     = PETSC_TRUE;
22101cf9b237SStefano Zampini     b->free_ij    = PETSC_TRUE;
22111cf9b237SStefano Zampini   }
221248a46eb9SPierre Jolivet   if (*B == A) PetscCall(MatDestroy(&A));
22131cf9b237SStefano Zampini   *B = Bt;
22143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22151cf9b237SStefano Zampini }
22161cf9b237SStefano Zampini 
2217d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDetectDisconnectedComponents(PC pc, PetscBool filter, PetscInt *ncc, IS *cc[], IS *primalv)
2218d71ae5a4SJacob Faibussowitsch {
2219c80a6c00SStefano Zampini   Mat                    B = NULL;
2220c80a6c00SStefano Zampini   DM                     dm;
22214f1b2e48SStefano Zampini   IS                     is_dummy, *cc_n;
22224f1b2e48SStefano Zampini   ISLocalToGlobalMapping l2gmap_dummy;
22234f1b2e48SStefano Zampini   PCBDDCGraph            graph;
2224c80a6c00SStefano Zampini   PetscInt              *xadj_filtered = NULL, *adjncy_filtered = NULL;
22254f1b2e48SStefano Zampini   PetscInt               i, n;
22264f1b2e48SStefano Zampini   PetscInt              *xadj, *adjncy;
2227c80a6c00SStefano Zampini   PetscBool              isplex = PETSC_FALSE;
22284f1b2e48SStefano Zampini 
22294f1b2e48SStefano Zampini   PetscFunctionBegin;
2230a2eca866SStefano Zampini   if (ncc) *ncc = 0;
2231a2eca866SStefano Zampini   if (cc) *cc = NULL;
2232a2eca866SStefano Zampini   if (primalv) *primalv = NULL;
22339566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphCreate(&graph));
22349566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pc->pmat, &dm));
223548a46eb9SPierre Jolivet   if (!dm) PetscCall(PCGetDM(pc, &dm));
2236f9635d15SStefano Zampini   if (dm) PetscCall(PetscObjectTypeCompareAny((PetscObject)dm, &isplex, DMPLEX, DMP4EST, DMP8EST, ""));
22378361f951SStefano Zampini   if (filter) isplex = PETSC_FALSE;
22388361f951SStefano Zampini 
2239c80a6c00SStefano Zampini   if (isplex) { /* this code has been modified from plexpartition.c */
2240c80a6c00SStefano Zampini     PetscInt        p, pStart, pEnd, a, adjSize, idx, size, nroots;
2241c80a6c00SStefano Zampini     PetscInt       *adj = NULL;
2242c80a6c00SStefano Zampini     IS              cellNumbering;
2243c80a6c00SStefano Zampini     const PetscInt *cellNum;
2244c80a6c00SStefano Zampini     PetscBool       useCone, useClosure;
2245c80a6c00SStefano Zampini     PetscSection    section;
2246c80a6c00SStefano Zampini     PetscSegBuffer  adjBuffer;
2247c80a6c00SStefano Zampini     PetscSF         sfPoint;
2248c80a6c00SStefano Zampini 
2249f9635d15SStefano Zampini     PetscCall(DMConvert(dm, DMPLEX, &dm));
22509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
22519566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sfPoint));
22529566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
2253c80a6c00SStefano Zampini     /* Build adjacency graph via a section/segbuffer */
22549566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
22559566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, pStart, pEnd));
22569566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
2257c80a6c00SStefano Zampini     /* Always use FVM adjacency to create partitioner graph */
22589566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
22599566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
22609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(dm, &cellNumbering));
22619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellNumbering, &cellNum));
2262c80a6c00SStefano Zampini     for (n = 0, p = pStart; p < pEnd; p++) {
2263c80a6c00SStefano Zampini       /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
22649371c9d4SSatish Balay       if (nroots > 0) {
22659371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
22669371c9d4SSatish Balay       }
2267c80a6c00SStefano Zampini       adjSize = PETSC_DETERMINE;
22689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
2269c80a6c00SStefano Zampini       for (a = 0; a < adjSize; ++a) {
2270c80a6c00SStefano Zampini         const PetscInt point = adj[a];
22715cef3d0dSStefano Zampini         if (pStart <= point && point < pEnd) {
2272c80a6c00SStefano Zampini           PetscInt *PETSC_RESTRICT pBuf;
22739566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
22749566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2275c80a6c00SStefano Zampini           *pBuf = point;
2276c80a6c00SStefano Zampini         }
2277c80a6c00SStefano Zampini       }
2278c80a6c00SStefano Zampini       n++;
2279c80a6c00SStefano Zampini     }
22809566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2281c80a6c00SStefano Zampini     /* Derive CSR graph from section/segbuffer */
22829566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
22839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
22849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n + 1, &xadj));
2285c80a6c00SStefano Zampini     for (idx = 0, p = pStart; p < pEnd; p++) {
22869371c9d4SSatish Balay       if (nroots > 0) {
22879371c9d4SSatish Balay         if (cellNum[p] < 0) continue;
22889371c9d4SSatish Balay       }
2289f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetOffset(section, p, &xadj[idx++]));
2290c80a6c00SStefano Zampini     }
2291c80a6c00SStefano Zampini     xadj[n] = size;
22929566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &adjncy));
2293c80a6c00SStefano Zampini     /* Clean up */
22949566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferDestroy(&adjBuffer));
22959566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
22969566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
2297c80a6c00SStefano Zampini     graph->xadj   = xadj;
2298c80a6c00SStefano Zampini     graph->adjncy = adjncy;
2299c80a6c00SStefano Zampini   } else {
2300c80a6c00SStefano Zampini     Mat       A;
23018361f951SStefano Zampini     PetscBool isseqaij, flg_row;
2302c80a6c00SStefano Zampini 
23039566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
230463c961adSStefano Zampini     if (!A->rmap->N || !A->cmap->N) {
23059566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphDestroy(&graph));
23063ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
230763c961adSStefano Zampini     }
23089566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij));
23094f1b2e48SStefano Zampini     if (!isseqaij && filter) {
23101cf9b237SStefano Zampini       PetscBool isseqdense;
23111cf9b237SStefano Zampini 
23129566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A, MATSEQDENSE, &isseqdense));
23131cf9b237SStefano Zampini       if (!isseqdense) {
23149566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
23151cf9b237SStefano Zampini       } else { /* TODO: rectangular case and LDA */
23161cf9b237SStefano Zampini         PetscScalar *array;
23171cf9b237SStefano Zampini         PetscReal    chop = 1.e-6;
23181cf9b237SStefano Zampini 
23199566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
23209566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(B, &array));
23219566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &n, NULL));
23221cf9b237SStefano Zampini         for (i = 0; i < n; i++) {
23231cf9b237SStefano Zampini           PetscInt j;
23241cf9b237SStefano Zampini           for (j = i + 1; j < n; j++) {
23251cf9b237SStefano Zampini             PetscReal thresh = chop * (PetscAbsScalar(array[i * (n + 1)]) + PetscAbsScalar(array[j * (n + 1)]));
23261cf9b237SStefano Zampini             if (PetscAbsScalar(array[i * n + j]) < thresh) array[i * n + j] = 0.;
23271cf9b237SStefano Zampini             if (PetscAbsScalar(array[j * n + i]) < thresh) array[j * n + i] = 0.;
23281cf9b237SStefano Zampini           }
23291cf9b237SStefano Zampini         }
23309566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(B, &array));
23319566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, MATSEQAIJ, MAT_INPLACE_MATRIX, &B));
23321cf9b237SStefano Zampini       }
23334f1b2e48SStefano Zampini     } else {
23349566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A));
23354f1b2e48SStefano Zampini       B = A;
23364f1b2e48SStefano Zampini     }
23379566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
23384f1b2e48SStefano Zampini 
23394f1b2e48SStefano Zampini     /* if filter is true, then removes entries lower than PETSC_SMALL in magnitude */
23404f1b2e48SStefano Zampini     if (filter) {
23414f1b2e48SStefano Zampini       PetscScalar *data;
23424f1b2e48SStefano Zampini       PetscInt     j, cum;
23434f1b2e48SStefano Zampini 
23449566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(n + 1, &xadj_filtered, xadj[n], &adjncy_filtered));
23459566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(B, &data));
23464f1b2e48SStefano Zampini       cum = 0;
23474f1b2e48SStefano Zampini       for (i = 0; i < n; i++) {
23484f1b2e48SStefano Zampini         PetscInt t;
23494f1b2e48SStefano Zampini 
23504f1b2e48SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) {
2351ad540459SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(data[j]) < PETSC_SMALL)) continue;
23524f1b2e48SStefano Zampini           adjncy_filtered[cum + xadj_filtered[i]++] = adjncy[j];
23534f1b2e48SStefano Zampini         }
23544f1b2e48SStefano Zampini         t                = xadj_filtered[i];
23554f1b2e48SStefano Zampini         xadj_filtered[i] = cum;
23564f1b2e48SStefano Zampini         cum += t;
23574f1b2e48SStefano Zampini       }
23589566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(B, &data));
23594f1b2e48SStefano Zampini       graph->xadj   = xadj_filtered;
23604f1b2e48SStefano Zampini       graph->adjncy = adjncy_filtered;
23614f1b2e48SStefano Zampini     } else {
23624f1b2e48SStefano Zampini       graph->xadj   = xadj;
23634f1b2e48SStefano Zampini       graph->adjncy = adjncy;
23644f1b2e48SStefano Zampini     }
2365c80a6c00SStefano Zampini   }
2366c80a6c00SStefano Zampini   /* compute local connected components using PCBDDCGraph */
23679de2952eSStefano Zampini   graph->seq_graph = PETSC_TRUE; /* analyze local connected components (i.e. disconnected subdomains) irrespective of dofs count */
23689566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &is_dummy));
23699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is_dummy, &l2gmap_dummy));
23709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_dummy));
23719566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphInit(graph, l2gmap_dummy, n, PETSC_MAX_INT));
23729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap_dummy));
23739566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphSetUp(graph, 1, NULL, NULL, 0, NULL, NULL));
23749566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
2375c80a6c00SStefano Zampini 
23764f1b2e48SStefano Zampini   /* partial clean up */
23779566063dSJacob Faibussowitsch   PetscCall(PetscFree2(xadj_filtered, adjncy_filtered));
2378c80a6c00SStefano Zampini   if (B) {
2379c80a6c00SStefano Zampini     PetscBool flg_row;
23809566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(B, 0, PETSC_TRUE, PETSC_FALSE, &n, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
23819566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
23824f1b2e48SStefano Zampini   }
2383c80a6c00SStefano Zampini   if (isplex) {
23849566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
23859566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
2386c80a6c00SStefano Zampini   }
23874f1b2e48SStefano Zampini 
23884f1b2e48SStefano Zampini   /* get back data */
2389c80a6c00SStefano Zampini   if (isplex) {
2390c80a6c00SStefano Zampini     if (ncc) *ncc = graph->ncc;
2391c80a6c00SStefano Zampini     if (cc || primalv) {
2392c80a6c00SStefano Zampini       Mat          A;
2393f9635d15SStefano Zampini       PetscBT      btv, btvt, btvc;
2394c80a6c00SStefano Zampini       PetscSection subSection;
2395c80a6c00SStefano Zampini       PetscInt    *ids, cum, cump, *cids, *pids;
2396f9635d15SStefano Zampini       PetscInt     dim, cStart, cEnd, fStart, fEnd, vStart, vEnd, pStart, pEnd;
2397c80a6c00SStefano Zampini 
2398f9635d15SStefano Zampini       PetscCall(DMGetDimension(dm, &dim));
23999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSubdomainSection(dm, &subSection));
2400f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2401f9635d15SStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2402f9635d15SStefano Zampini       PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2403f9635d15SStefano Zampini       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
24049566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(pc->pmat, &A));
24059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(A->rmap->n, &ids, graph->ncc + 1, &cids, A->rmap->n, &pids));
24069566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btv));
24079566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(A->rmap->n, &btvt));
2408f9635d15SStefano Zampini       PetscCall(PetscBTCreate(pEnd - pStart, &btvc));
2409f9635d15SStefano Zampini 
2410f9635d15SStefano Zampini       /* First see if we find corners for the subdomains, i.e. a vertex
2411f9635d15SStefano Zampini          shared by at least dim subdomain boundary faces. This does not
2412f9635d15SStefano Zampini          cover all the possible cases with simplices but it is enough
2413f9635d15SStefano Zampini          for tensor cells */
2414f9635d15SStefano Zampini       if (vStart != fStart && dim <= 3) {
2415f9635d15SStefano Zampini         for (PetscInt c = cStart; c < cEnd; c++) {
2416f9635d15SStefano Zampini           PetscInt        nf, cnt = 0, mcnt = dim, *cfaces;
2417f9635d15SStefano Zampini           const PetscInt *faces;
2418f9635d15SStefano Zampini 
2419f9635d15SStefano Zampini           PetscCall(DMPlexGetConeSize(dm, c, &nf));
2420f9635d15SStefano Zampini           PetscCall(DMGetWorkArray(dm, nf, MPIU_INT, &cfaces));
2421f9635d15SStefano Zampini           PetscCall(DMPlexGetCone(dm, c, &faces));
2422f9635d15SStefano Zampini           for (PetscInt f = 0; f < nf; f++) {
2423f9635d15SStefano Zampini             PetscInt nc, ff;
2424f9635d15SStefano Zampini 
2425f9635d15SStefano Zampini             PetscCall(DMPlexGetSupportSize(dm, faces[f], &nc));
2426f9635d15SStefano Zampini             PetscCall(DMPlexGetTreeParent(dm, faces[f], &ff, NULL));
2427f9635d15SStefano Zampini             if (nc == 1 && faces[f] == ff) cfaces[cnt++] = faces[f];
2428f9635d15SStefano Zampini           }
2429f9635d15SStefano Zampini           if (cnt >= mcnt) {
2430f9635d15SStefano Zampini             PetscInt size, *closure = NULL;
2431f9635d15SStefano Zampini 
2432f9635d15SStefano Zampini             PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2433f9635d15SStefano Zampini             for (PetscInt k = 0; k < 2 * size; k += 2) {
2434f9635d15SStefano Zampini               PetscInt v = closure[k];
2435f9635d15SStefano Zampini               if (v >= vStart && v < vEnd) {
2436f9635d15SStefano Zampini                 PetscInt vsize, *vclosure = NULL;
2437f9635d15SStefano Zampini 
2438f9635d15SStefano Zampini                 cnt = 0;
2439f9635d15SStefano Zampini                 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2440f9635d15SStefano Zampini                 for (PetscInt vk = 0; vk < 2 * vsize; vk += 2) {
2441f9635d15SStefano Zampini                   PetscInt f = vclosure[vk];
2442f9635d15SStefano Zampini                   if (f >= fStart && f < fEnd) {
2443f9635d15SStefano Zampini                     PetscInt  nc, ff;
2444f9635d15SStefano Zampini                     PetscBool valid = PETSC_FALSE;
2445f9635d15SStefano Zampini 
2446f9635d15SStefano Zampini                     for (PetscInt fk = 0; fk < nf; fk++)
2447f9635d15SStefano Zampini                       if (f == cfaces[fk]) valid = PETSC_TRUE;
2448f9635d15SStefano Zampini                     if (!valid) continue;
2449f9635d15SStefano Zampini                     PetscCall(DMPlexGetSupportSize(dm, f, &nc));
2450f9635d15SStefano Zampini                     PetscCall(DMPlexGetTreeParent(dm, f, &ff, NULL));
2451f9635d15SStefano Zampini                     if (nc == 1 && f == ff) cnt++;
2452f9635d15SStefano Zampini                   }
2453f9635d15SStefano Zampini                 }
2454f9635d15SStefano Zampini                 if (cnt >= mcnt) PetscCall(PetscBTSet(btvc, v - pStart));
2455f9635d15SStefano Zampini                 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &vsize, &vclosure));
2456f9635d15SStefano Zampini               }
2457f9635d15SStefano Zampini             }
2458f9635d15SStefano Zampini             PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &size, &closure));
2459f9635d15SStefano Zampini           }
2460f9635d15SStefano Zampini           PetscCall(DMRestoreWorkArray(dm, nf, MPIU_INT, &cfaces));
2461f9635d15SStefano Zampini         }
2462f9635d15SStefano Zampini       }
2463c80a6c00SStefano Zampini 
2464c80a6c00SStefano Zampini       cids[0] = 0;
2465c80a6c00SStefano Zampini       for (i = 0, cump = 0, cum = 0; i < graph->ncc; i++) {
2466c80a6c00SStefano Zampini         PetscInt j;
2467c80a6c00SStefano Zampini 
24689566063dSJacob Faibussowitsch         PetscCall(PetscBTMemzero(A->rmap->n, btvt));
2469c80a6c00SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
2470c80a6c00SStefano Zampini           PetscInt k, size, *closure = NULL, cell = graph->queue[j];
2471c80a6c00SStefano Zampini 
24729566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2473c80a6c00SStefano Zampini           for (k = 0; k < 2 * size; k += 2) {
247420c3699dSStefano Zampini             PetscInt s, pp, p = closure[k], off, dof, cdof;
2475c80a6c00SStefano Zampini 
24769566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetConstraintDof(subSection, p, &cdof));
24779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(subSection, p, &off));
24789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(subSection, p, &dof));
2479c80a6c00SStefano Zampini             for (s = 0; s < dof - cdof; s++) {
2480c80a6c00SStefano Zampini               if (PetscBTLookupSet(btvt, off + s)) continue;
2481f9635d15SStefano Zampini               if (PetscBTLookup(btvc, p - pStart)) pids[cump++] = off + s; /* subdomain corner */
2482f9635d15SStefano Zampini               else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2483e432b41dSStefano Zampini               else pids[cump++] = off + s; /* cross-vertex */
2484c80a6c00SStefano Zampini             }
24859566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
248620c3699dSStefano Zampini             if (pp != p) {
24879566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetConstraintDof(subSection, pp, &cdof));
24889566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(subSection, pp, &off));
24899566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(subSection, pp, &dof));
249020c3699dSStefano Zampini               for (s = 0; s < dof - cdof; s++) {
249120c3699dSStefano Zampini                 if (PetscBTLookupSet(btvt, off + s)) continue;
2492f9635d15SStefano Zampini                 if (PetscBTLookup(btvc, pp - pStart)) pids[cump++] = off + s; /* subdomain corner */
2493f9635d15SStefano Zampini                 else if (!PetscBTLookup(btv, off + s)) ids[cum++] = off + s;
2494e432b41dSStefano Zampini                 else pids[cump++] = off + s; /* cross-vertex */
249520c3699dSStefano Zampini               }
249620c3699dSStefano Zampini             }
2497c80a6c00SStefano Zampini           }
24989566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &size, &closure));
2499c80a6c00SStefano Zampini         }
2500c80a6c00SStefano Zampini         cids[i + 1] = cum;
2501c80a6c00SStefano Zampini         /* mark dofs as already assigned */
250248a46eb9SPierre Jolivet         for (j = cids[i]; j < cids[i + 1]; j++) PetscCall(PetscBTSet(btv, ids[j]));
2503c80a6c00SStefano Zampini       }
2504c80a6c00SStefano Zampini       if (cc) {
25059566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(graph->ncc, &cc_n));
250648a46eb9SPierre 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]));
2507c80a6c00SStefano Zampini         *cc = cc_n;
2508c80a6c00SStefano Zampini       }
25091baa6e33SBarry Smith       if (primalv) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), cump, pids, PETSC_COPY_VALUES, primalv));
25109566063dSJacob Faibussowitsch       PetscCall(PetscFree3(ids, cids, pids));
25119566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btv));
25129566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&btvt));
2513f9635d15SStefano Zampini       PetscCall(PetscBTDestroy(&btvc));
2514f9635d15SStefano Zampini       PetscCall(DMDestroy(&dm));
2515c80a6c00SStefano Zampini     }
2516c80a6c00SStefano Zampini   } else {
25171cf9b237SStefano Zampini     if (ncc) *ncc = graph->ncc;
25181cf9b237SStefano Zampini     if (cc) {
25199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(graph->ncc, &cc_n));
252048a46eb9SPierre 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]));
25214f1b2e48SStefano Zampini       *cc = cc_n;
25221cf9b237SStefano Zampini     }
2523c80a6c00SStefano Zampini   }
25244f1b2e48SStefano Zampini   /* clean up graph */
25250a545947SLisandro Dalcin   graph->xadj   = NULL;
25260a545947SLisandro Dalcin   graph->adjncy = NULL;
25279566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&graph));
25283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25294f1b2e48SStefano Zampini }
25304f1b2e48SStefano Zampini 
2531d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignCheck(PC pc, IS zerodiag)
2532d71ae5a4SJacob Faibussowitsch {
25335408967cSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2534f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
2535dee84bffSStefano Zampini   IS       dirIS  = NULL;
25364f1b2e48SStefano Zampini   PetscInt i;
25375408967cSStefano Zampini 
25385408967cSStefano Zampini   PetscFunctionBegin;
25399566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
25405408967cSStefano Zampini   if (zerodiag) {
25415408967cSStefano Zampini     Mat             A;
25425408967cSStefano Zampini     Vec             vec3_N;
25435408967cSStefano Zampini     PetscScalar    *vals;
25445408967cSStefano Zampini     const PetscInt *idxs;
2545d12d3064SStefano Zampini     PetscInt        nz, *count;
25465408967cSStefano Zampini 
25475408967cSStefano Zampini     /* p0 */
25489566063dSJacob Faibussowitsch     PetscCall(VecSet(pcis->vec1_N, 0.));
25499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &vals));
25509566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zerodiag, &nz));
25519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
25524f1b2e48SStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 1.;
25539566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec1_N, nz, idxs, vals, INSERT_VALUES));
25549566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec1_N));
25559566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec1_N));
25565408967cSStefano Zampini     /* v_I */
25579566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(pcis->vec2_N, NULL));
25585408967cSStefano Zampini     for (i = 0; i < nz; i++) vals[i] = 0.;
25599566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, nz, idxs, vals, INSERT_VALUES));
25609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
25619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
25625408967cSStefano Zampini     for (i = 0; i < pcis->n_B; i++) vals[i] = 0.;
25639566063dSJacob Faibussowitsch     PetscCall(VecSetValues(pcis->vec2_N, pcis->n_B, idxs, vals, INSERT_VALUES));
25649566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
25655408967cSStefano Zampini     if (dirIS) {
25665408967cSStefano Zampini       PetscInt n;
25675408967cSStefano Zampini 
25689566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(dirIS, &n));
25699566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(dirIS, &idxs));
25705408967cSStefano Zampini       for (i = 0; i < n; i++) vals[i] = 0.;
25719566063dSJacob Faibussowitsch       PetscCall(VecSetValues(pcis->vec2_N, n, idxs, vals, INSERT_VALUES));
25729566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(dirIS, &idxs));
25735408967cSStefano Zampini     }
25749566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcis->vec2_N));
25759566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcis->vec2_N));
25769566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcis->vec1_N, &vec3_N));
25779566063dSJacob Faibussowitsch     PetscCall(VecSet(vec3_N, 0.));
25789566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
25799566063dSJacob Faibussowitsch     PetscCall(MatMult(A, pcis->vec1_N, vec3_N));
25809566063dSJacob Faibussowitsch     PetscCall(VecDot(vec3_N, pcis->vec2_N, &vals[0]));
25817827d75bSBarry 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]));
25829566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
25839566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&vec3_N));
2584d12d3064SStefano Zampini 
2585d12d3064SStefano Zampini     /* there should not be any pressure dofs lying on the interface */
25869566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pcis->n, &count));
25879566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, &idxs));
2588d12d3064SStefano Zampini     for (i = 0; i < pcis->n_B; i++) count[idxs[i]]++;
25899566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, &idxs));
25909566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zerodiag, &idxs));
259163a3b9bcSJacob 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]);
25929566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zerodiag, &idxs));
25939566063dSJacob Faibussowitsch     PetscCall(PetscFree(count));
25945408967cSStefano Zampini   }
25959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dirIS));
25965408967cSStefano Zampini 
25975408967cSStefano Zampini   /* check PCBDDCBenignGetOrSetP0 */
25989566063dSJacob Faibussowitsch   PetscCall(VecSetRandom(pcis->vec1_global, NULL));
25994f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = -PetscGlobalRank - i;
26009566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_FALSE));
26014f1b2e48SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) pcbddc->benign_p0[i] = 1;
26029566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignGetOrSetP0(pc, pcis->vec1_global, PETSC_TRUE));
2603f2a566d8SStefano Zampini   for (i = 0; i < pcbddc->benign_n; i++) {
2604f2a566d8SStefano Zampini     PetscInt val = PetscRealPart(pcbddc->benign_p0[i]);
260563a3b9bcSJacob 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));
2606f2a566d8SStefano Zampini   }
26073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26085408967cSStefano Zampini }
26095408967cSStefano Zampini 
2610d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignDetectSaddlePoint(PC pc, PetscBool reuse, IS *zerodiaglocal)
2611d71ae5a4SJacob Faibussowitsch {
2612339f8db1SStefano Zampini   PC_BDDC  *pcbddc    = (PC_BDDC *)pc->data;
2613f4f49eeaSPierre Jolivet   Mat_IS   *matis     = (Mat_IS *)pc->pmat->data;
26143b03f7bbSStefano Zampini   IS        pressures = NULL, zerodiag = NULL, *bzerodiag = NULL, zerodiag_save, *zerodiag_subs;
26153b03f7bbSStefano Zampini   PetscInt  nz, n, benign_n, bsp = 1;
26164edc6404Sstefano_zampini   PetscInt *interior_dofs, n_interior_dofs, nneu;
26174edc6404Sstefano_zampini   PetscBool sorted, have_null, has_null_pressures, recompute_zerodiag, checkb;
2618339f8db1SStefano Zampini 
2619339f8db1SStefano Zampini   PetscFunctionBegin;
26203b03f7bbSStefano Zampini   if (reuse) goto project_b0;
26219566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
26229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
262348a46eb9SPierre Jolivet   for (n = 0; n < pcbddc->benign_n; n++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[n]));
26249566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
26253b03f7bbSStefano Zampini   has_null_pressures = PETSC_TRUE;
26263b03f7bbSStefano Zampini   have_null          = PETSC_TRUE;
26273b03f7bbSStefano Zampini   /* if a local information on dofs is present, gets pressure dofs from command line (uses the last field is not provided)
26283b03f7bbSStefano Zampini      Without local information, it uses only the zerodiagonal dofs (ok if the pressure block is all zero and it is a scalar field)
26294f1b2e48SStefano Zampini      Checks if all the pressure dofs in each subdomain have a zero diagonal
26304f1b2e48SStefano Zampini      If not, a change of basis on pressures is not needed
26311ae86dd6SStefano Zampini      since the local Schur complements are already SPD
26324f1b2e48SStefano Zampini   */
263340fa8d13SStefano Zampini   if (pcbddc->n_ISForDofsLocal) {
26347fbe2174Sstefano_zampini     IS        iP = NULL;
26353b03f7bbSStefano Zampini     PetscInt  p, *pp;
26363b03f7bbSStefano Zampini     PetscBool flg;
26374f1b2e48SStefano Zampini 
26389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->n_ISForDofsLocal, &pp));
26393b03f7bbSStefano Zampini     n = pcbddc->n_ISForDofsLocal;
2640d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)pc), ((PetscObject)pc)->prefix, "BDDC benign options", "PC");
26419566063dSJacob Faibussowitsch     PetscCall(PetscOptionsIntArray("-pc_bddc_pressure_field", "Field id for pressures", NULL, pp, &n, &flg));
2642d0609cedSBarry Smith     PetscOptionsEnd();
26433b03f7bbSStefano Zampini     if (!flg) {
26443b03f7bbSStefano Zampini       n     = 1;
26453b03f7bbSStefano Zampini       pp[0] = pcbddc->n_ISForDofsLocal - 1;
26463b03f7bbSStefano Zampini     }
26473b03f7bbSStefano Zampini 
26483b03f7bbSStefano Zampini     bsp = 0;
26493b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
26503b03f7bbSStefano Zampini       PetscInt bs;
26513b03f7bbSStefano Zampini 
265263a3b9bcSJacob 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]);
26539566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
26543b03f7bbSStefano Zampini       bsp += bs;
26553b03f7bbSStefano Zampini     }
26569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bsp, &bzerodiag));
26573b03f7bbSStefano Zampini     bsp = 0;
26583b03f7bbSStefano Zampini     for (p = 0; p < n; p++) {
26593b03f7bbSStefano Zampini       const PetscInt *idxs;
26603b03f7bbSStefano Zampini       PetscInt        b, bs, npl, *bidxs;
26613b03f7bbSStefano Zampini 
26629566063dSJacob Faibussowitsch       PetscCall(ISGetBlockSize(pcbddc->ISForDofsLocal[pp[p]], &bs));
26639566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[pp[p]], &npl));
26649566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
26659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(npl / bs, &bidxs));
26663b03f7bbSStefano Zampini       for (b = 0; b < bs; b++) {
26673b03f7bbSStefano Zampini         PetscInt i;
26683b03f7bbSStefano Zampini 
26693b03f7bbSStefano Zampini         for (i = 0; i < npl / bs; i++) bidxs[i] = idxs[bs * i + b];
26709566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npl / bs, bidxs, PETSC_COPY_VALUES, &bzerodiag[bsp]));
26713b03f7bbSStefano Zampini         bsp++;
26723b03f7bbSStefano Zampini       }
26739566063dSJacob Faibussowitsch       PetscCall(PetscFree(bidxs));
26749566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[pp[p]], &idxs));
26753b03f7bbSStefano Zampini     }
26769566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PETSC_COMM_SELF, bsp, bzerodiag, &pressures));
26773b03f7bbSStefano Zampini 
26787fbe2174Sstefano_zampini     /* remove zeroed out pressures if we are setting up a BDDC solver for a saddle-point FETI-DP */
26799566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&iP));
26807fbe2174Sstefano_zampini     if (iP) {
26817fbe2174Sstefano_zampini       IS newpressures;
26827fbe2174Sstefano_zampini 
26839566063dSJacob Faibussowitsch       PetscCall(ISDifference(pressures, iP, &newpressures));
26849566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pressures));
26857fbe2174Sstefano_zampini       pressures = newpressures;
26867fbe2174Sstefano_zampini     }
26879566063dSJacob Faibussowitsch     PetscCall(ISSorted(pressures, &sorted));
268848a46eb9SPierre Jolivet     if (!sorted) PetscCall(ISSort(pressures));
26899566063dSJacob Faibussowitsch     PetscCall(PetscFree(pp));
269040fa8d13SStefano Zampini   }
26913b03f7bbSStefano Zampini 
269297d764eeSStefano Zampini   /* pcis has not been setup yet, so get the local size from the subdomain matrix */
26939566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
269427b6a85dSStefano Zampini   if (!n) pcbddc->benign_change_explicit = PETSC_TRUE;
26959566063dSJacob Faibussowitsch   PetscCall(MatFindZeroDiagonals(pcbddc->local_mat, &zerodiag));
26969566063dSJacob Faibussowitsch   PetscCall(ISSorted(zerodiag, &sorted));
269748a46eb9SPierre Jolivet   if (!sorted) PetscCall(ISSort(zerodiag));
26989566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)zerodiag));
26994edc6404Sstefano_zampini   zerodiag_save = zerodiag;
27009566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(zerodiag, &nz));
27014f1b2e48SStefano Zampini   if (!nz) {
27024f1b2e48SStefano Zampini     if (n) have_null = PETSC_FALSE;
27034f1b2e48SStefano Zampini     has_null_pressures = PETSC_FALSE;
27049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
270540fa8d13SStefano Zampini   }
27064f1b2e48SStefano Zampini   recompute_zerodiag = PETSC_FALSE;
27073b03f7bbSStefano Zampini 
27084f1b2e48SStefano Zampini   /* in case disconnected subdomains info is present, split the pressures accordingly (otherwise the benign trick could fail) */
27094f1b2e48SStefano Zampini   zerodiag_subs   = NULL;
27103b03f7bbSStefano Zampini   benign_n        = 0;
27111f4df5f7SStefano Zampini   n_interior_dofs = 0;
27121f4df5f7SStefano Zampini   interior_dofs   = NULL;
27134edc6404Sstefano_zampini   nneu            = 0;
271448a46eb9SPierre Jolivet   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &nneu));
27153369cb78Sstefano_zampini   checkb = (PetscBool)(!pcbddc->NeumannBoundariesLocal || pcbddc->current_level);
27164edc6404Sstefano_zampini   if (checkb) { /* need to compute interior nodes */
27179de2952eSStefano Zampini     PetscInt               n, i;
27189de2952eSStefano Zampini     PetscInt              *count;
27199de2952eSStefano Zampini     ISLocalToGlobalMapping mapping;
27201f4df5f7SStefano Zampini 
27219de2952eSStefano Zampini     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &mapping, NULL));
27229de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetNodeInfo(mapping, &n, &count, NULL));
27239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &interior_dofs));
27241f4df5f7SStefano Zampini     for (i = 0; i < n; i++)
27259de2952eSStefano Zampini       if (count[i] < 2) interior_dofs[n_interior_dofs++] = i;
27269de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(mapping, &n, &count, NULL));
27271f4df5f7SStefano Zampini   }
27284f1b2e48SStefano Zampini   if (has_null_pressures) {
27294f1b2e48SStefano Zampini     IS             *subs;
27304edc6404Sstefano_zampini     PetscInt        nsubs, i, j, nl;
27311f4df5f7SStefano Zampini     const PetscInt *idxs;
27321f4df5f7SStefano Zampini     PetscScalar    *array;
27331f4df5f7SStefano Zampini     Vec            *work;
27344f1b2e48SStefano Zampini 
27354f1b2e48SStefano Zampini     subs  = pcbddc->local_subs;
27364f1b2e48SStefano Zampini     nsubs = pcbddc->n_local_subs;
27371f4df5f7SStefano 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) */
27384edc6404Sstefano_zampini     if (checkb) {
27399566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(matis->y, 2, &work));
27409566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zerodiag, &nl));
27419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zerodiag, &idxs));
27421f4df5f7SStefano Zampini       /* work[0] = 1_p */
27439566063dSJacob Faibussowitsch       PetscCall(VecSet(work[0], 0.));
27449566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[0], &array));
27451f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
27469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[0], &array));
27471f4df5f7SStefano Zampini       /* work[0] = 1_v */
27489566063dSJacob Faibussowitsch       PetscCall(VecSet(work[1], 1.));
27499566063dSJacob Faibussowitsch       PetscCall(VecGetArray(work[1], &array));
27501f4df5f7SStefano Zampini       for (j = 0; j < nl; j++) array[idxs[j]] = 0.;
27519566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(work[1], &array));
27529566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zerodiag, &idxs));
27531f4df5f7SStefano Zampini     }
27543b03f7bbSStefano Zampini 
27553b03f7bbSStefano Zampini     if (nsubs > 1 || bsp > 1) {
27563b03f7bbSStefano Zampini       IS      *is;
27573b03f7bbSStefano Zampini       PetscInt b, totb;
27583b03f7bbSStefano Zampini 
27593b03f7bbSStefano Zampini       totb  = bsp;
27603b03f7bbSStefano Zampini       is    = bsp > 1 ? bzerodiag : &zerodiag;
27613b03f7bbSStefano Zampini       nsubs = PetscMax(nsubs, 1);
27629566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nsubs * totb, &zerodiag_subs));
27633b03f7bbSStefano Zampini       for (b = 0; b < totb; b++) {
27644f1b2e48SStefano Zampini         for (i = 0; i < nsubs; i++) {
27654f1b2e48SStefano Zampini           ISLocalToGlobalMapping l2g;
27664f1b2e48SStefano Zampini           IS                     t_zerodiag_subs;
27674f1b2e48SStefano Zampini           PetscInt               nl;
27684f1b2e48SStefano Zampini 
27693b03f7bbSStefano Zampini           if (subs) {
27709566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(subs[i], &l2g));
27713b03f7bbSStefano Zampini           } else {
27723b03f7bbSStefano Zampini             IS tis;
27733b03f7bbSStefano Zampini 
27749566063dSJacob Faibussowitsch             PetscCall(MatGetLocalSize(pcbddc->local_mat, &nl, NULL));
27759566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PETSC_COMM_SELF, nl, 0, 1, &tis));
27769566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(tis, &l2g));
27779566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&tis));
27783b03f7bbSStefano Zampini           }
27799566063dSJacob Faibussowitsch           PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, is[b], &t_zerodiag_subs));
27809566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(t_zerodiag_subs, &nl));
27814f1b2e48SStefano Zampini           if (nl) {
27824f1b2e48SStefano Zampini             PetscBool valid = PETSC_TRUE;
27834f1b2e48SStefano Zampini 
27844edc6404Sstefano_zampini             if (checkb) {
27859566063dSJacob Faibussowitsch               PetscCall(VecSet(matis->x, 0));
27869566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(subs[i], &nl));
27879566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(subs[i], &idxs));
27889566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->x, &array));
27891f4df5f7SStefano Zampini               for (j = 0; j < nl; j++) array[idxs[j]] = 1.;
27909566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->x, &array));
27919566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(subs[i], &idxs));
27929566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->x, work[0], matis->x));
27939566063dSJacob Faibussowitsch               PetscCall(MatMult(matis->A, matis->x, matis->y));
27949566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(matis->y, work[1], matis->y));
27959566063dSJacob Faibussowitsch               PetscCall(VecGetArray(matis->y, &array));
27961f4df5f7SStefano Zampini               for (j = 0; j < n_interior_dofs; j++) {
27971f4df5f7SStefano Zampini                 if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
27981f4df5f7SStefano Zampini                   valid = PETSC_FALSE;
27991f4df5f7SStefano Zampini                   break;
28001f4df5f7SStefano Zampini                 }
28011f4df5f7SStefano Zampini               }
28029566063dSJacob Faibussowitsch               PetscCall(VecRestoreArray(matis->y, &array));
28031f4df5f7SStefano Zampini             }
28046632bad2Sstefano_zampini             if (valid && nneu) {
28056632bad2Sstefano_zampini               const PetscInt *idxs;
28061f4df5f7SStefano Zampini               PetscInt        nzb;
28071f4df5f7SStefano Zampini 
28089566063dSJacob Faibussowitsch               PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
28099566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_DROP, nneu, idxs, &nzb, NULL));
28109566063dSJacob Faibussowitsch               PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
28111f4df5f7SStefano Zampini               if (nzb) valid = PETSC_FALSE;
28121f4df5f7SStefano Zampini             }
28131f4df5f7SStefano Zampini             if (valid && pressures) {
28143b03f7bbSStefano Zampini               IS       t_pressure_subs, tmp;
28153b03f7bbSStefano Zampini               PetscInt i1, i2;
28163b03f7bbSStefano Zampini 
28179566063dSJacob Faibussowitsch               PetscCall(ISGlobalToLocalMappingApplyIS(l2g, IS_GTOLM_DROP, pressures, &t_pressure_subs));
28189566063dSJacob Faibussowitsch               PetscCall(ISEmbed(t_zerodiag_subs, t_pressure_subs, PETSC_TRUE, &tmp));
28199566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(tmp, &i1));
28209566063dSJacob Faibussowitsch               PetscCall(ISGetLocalSize(t_zerodiag_subs, &i2));
28213b03f7bbSStefano Zampini               if (i2 != i1) valid = PETSC_FALSE;
28229566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&t_pressure_subs));
28239566063dSJacob Faibussowitsch               PetscCall(ISDestroy(&tmp));
28244f1b2e48SStefano Zampini             }
28254f1b2e48SStefano Zampini             if (valid) {
28269566063dSJacob Faibussowitsch               PetscCall(ISLocalToGlobalMappingApplyIS(l2g, t_zerodiag_subs, &zerodiag_subs[benign_n]));
28273b03f7bbSStefano Zampini               benign_n++;
28283b03f7bbSStefano Zampini             } else recompute_zerodiag = PETSC_TRUE;
28294f1b2e48SStefano Zampini           }
28309566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&t_zerodiag_subs));
28319566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
28324f1b2e48SStefano Zampini         }
28333b03f7bbSStefano Zampini       }
28344f1b2e48SStefano Zampini     } else { /* there's just one subdomain (or zero if they have not been detected */
28354f1b2e48SStefano Zampini       PetscBool valid = PETSC_TRUE;
28361f4df5f7SStefano Zampini 
28376632bad2Sstefano_zampini       if (nneu) valid = PETSC_FALSE;
283848a46eb9SPierre Jolivet       if (valid && pressures) PetscCall(ISEqual(pressures, zerodiag, &valid));
28394edc6404Sstefano_zampini       if (valid && checkb) {
28409566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, work[0], matis->x));
28419566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(matis->x, work[1], matis->x));
28429566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->x, &array));
28431f4df5f7SStefano Zampini         for (j = 0; j < n_interior_dofs; j++) {
28441f4df5f7SStefano Zampini           if (PetscAbsScalar(array[interior_dofs[j]]) > PETSC_SMALL) {
28451f4df5f7SStefano Zampini             valid = PETSC_FALSE;
28461f4df5f7SStefano Zampini             break;
28471f4df5f7SStefano Zampini           }
28481f4df5f7SStefano Zampini         }
28499566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->x, &array));
28501f4df5f7SStefano Zampini       }
28514f1b2e48SStefano Zampini       if (valid) {
28523b03f7bbSStefano Zampini         benign_n = 1;
28539566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(benign_n, &zerodiag_subs));
28549566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)zerodiag));
28554f1b2e48SStefano Zampini         zerodiag_subs[0] = zerodiag;
28564f1b2e48SStefano Zampini       }
28574f1b2e48SStefano Zampini     }
285848a46eb9SPierre Jolivet     if (checkb) PetscCall(VecDestroyVecs(2, &work));
28591f4df5f7SStefano Zampini   }
28609566063dSJacob Faibussowitsch   PetscCall(PetscFree(interior_dofs));
28614f1b2e48SStefano Zampini 
28623b03f7bbSStefano Zampini   if (!benign_n) {
2863b9b0e38cSStefano Zampini     PetscInt n;
2864b9b0e38cSStefano Zampini 
28659566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
28664f1b2e48SStefano Zampini     recompute_zerodiag = PETSC_FALSE;
28679566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
286876a58201SStefano Zampini     if (n) have_null = PETSC_FALSE;
2869b9b0e38cSStefano Zampini   }
28704f1b2e48SStefano Zampini 
28714f1b2e48SStefano Zampini   /* final check for null pressures */
287248a46eb9SPierre Jolivet   if (zerodiag && pressures) PetscCall(ISEqual(pressures, zerodiag, &have_null));
28734f1b2e48SStefano Zampini 
28744f1b2e48SStefano Zampini   if (recompute_zerodiag) {
28759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&zerodiag));
28763b03f7bbSStefano Zampini     if (benign_n == 1) {
28779566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)zerodiag_subs[0]));
28784f1b2e48SStefano Zampini       zerodiag = zerodiag_subs[0];
28794f1b2e48SStefano Zampini     } else {
28804f1b2e48SStefano Zampini       PetscInt i, nzn, *new_idxs;
28814f1b2e48SStefano Zampini 
28824f1b2e48SStefano Zampini       nzn = 0;
28833b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
28844f1b2e48SStefano Zampini         PetscInt ns;
28859566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
28864f1b2e48SStefano Zampini         nzn += ns;
28874f1b2e48SStefano Zampini       }
28889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzn, &new_idxs));
28894f1b2e48SStefano Zampini       nzn = 0;
28903b03f7bbSStefano Zampini       for (i = 0; i < benign_n; i++) {
28914f1b2e48SStefano Zampini         PetscInt ns, *idxs;
28929566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(zerodiag_subs[i], &ns));
28939566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
28949566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(new_idxs + nzn, idxs, ns));
28959566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(zerodiag_subs[i], (const PetscInt **)&idxs));
28964f1b2e48SStefano Zampini         nzn += ns;
28974f1b2e48SStefano Zampini       }
28989566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(nzn, new_idxs));
28999566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nzn, new_idxs, PETSC_OWN_POINTER, &zerodiag));
29004f1b2e48SStefano Zampini     }
29014f1b2e48SStefano Zampini     have_null = PETSC_FALSE;
29024f1b2e48SStefano Zampini   }
29034f1b2e48SStefano Zampini 
29043b03f7bbSStefano Zampini   /* determines if the coarse solver will be singular or not */
29051c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_null, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)pc)));
29063b03f7bbSStefano Zampini 
2907669cc0f4SStefano Zampini   /* Prepare matrix to compute no-net-flux */
2908a198735bSStefano Zampini   if (pcbddc->compute_nonetflux && !pcbddc->divudotp) {
2909a198735bSStefano Zampini     Mat                    A, loc_divudotp;
2910a198735bSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g, l2gmap;
2911a198735bSStefano Zampini     IS                     row, col, isused = NULL;
2912a198735bSStefano Zampini     PetscInt               M, N, n, st, n_isused;
2913a198735bSStefano Zampini 
29141f4df5f7SStefano Zampini     if (pressures) {
29151f4df5f7SStefano Zampini       isused = pressures;
29161f4df5f7SStefano Zampini     } else {
29174edc6404Sstefano_zampini       isused = zerodiag_save;
29181f4df5f7SStefano Zampini     }
29199566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &l2gmap, NULL));
29209566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pc->pmat, &A));
29219566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &n, NULL));
29227827d75bSBarry 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");
2923a198735bSStefano Zampini     n_isused = 0;
292448a46eb9SPierre Jolivet     if (isused) PetscCall(ISGetLocalSize(isused, &n_isused));
29259566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&n_isused, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
2926a198735bSStefano Zampini     st = st - n_isused;
29271ae86dd6SStefano Zampini     if (n) {
2928a198735bSStefano Zampini       const PetscInt *gidxs;
2929a198735bSStefano Zampini 
29309566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, isused, NULL, MAT_INITIAL_MATRIX, &loc_divudotp));
29319566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
2932a198735bSStefano Zampini       /* TODO: extend ISCreateStride with st = PETSC_DECIDE */
29339566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
29349566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), n, gidxs, PETSC_COPY_VALUES, &col));
29359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
29361ae86dd6SStefano Zampini     } else {
29379566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &loc_divudotp));
29389566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), n_isused, st, 1, &row));
29399566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), 0, NULL, PETSC_COPY_VALUES, &col));
2940a198735bSStefano Zampini     }
29419566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, NULL, &N));
29429566063dSJacob Faibussowitsch     PetscCall(ISGetSize(row, &M));
29439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
29449566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
29459566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
29469566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
29479566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->divudotp));
29489566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->divudotp, MATIS));
29499566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->divudotp, PETSC_DECIDE, PETSC_DECIDE, M, N));
29509566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(pcbddc->divudotp, rl2g, cl2g));
29519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
29529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
29539566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(pcbddc->divudotp, loc_divudotp));
29549566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&loc_divudotp));
29559566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
29569566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->divudotp, MAT_FINAL_ASSEMBLY));
29571ae86dd6SStefano Zampini   }
29589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zerodiag_save));
29599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pressures));
29603b03f7bbSStefano Zampini   if (bzerodiag) {
29613b03f7bbSStefano Zampini     PetscInt i;
2962b3afcdbeSStefano Zampini 
296348a46eb9SPierre Jolivet     for (i = 0; i < bsp; i++) PetscCall(ISDestroy(&bzerodiag[i]));
29649566063dSJacob Faibussowitsch     PetscCall(PetscFree(bzerodiag));
29653b03f7bbSStefano Zampini   }
29663b03f7bbSStefano Zampini   pcbddc->benign_n             = benign_n;
29673b03f7bbSStefano Zampini   pcbddc->benign_zerodiag_subs = zerodiag_subs;
29683b03f7bbSStefano Zampini 
29693b03f7bbSStefano Zampini   /* determines if the problem has subdomains with 0 pressure block */
29703b03f7bbSStefano Zampini   have_null = (PetscBool)(!!pcbddc->benign_n);
29711c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&have_null, &pcbddc->benign_have_null, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
29723b03f7bbSStefano Zampini 
29733b03f7bbSStefano Zampini project_b0:
29749566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pcbddc->local_mat, &n, NULL));
2975b3afcdbeSStefano Zampini   /* change of basis and p0 dofs */
29763b03f7bbSStefano Zampini   if (pcbddc->benign_n) {
29774f1b2e48SStefano Zampini     PetscInt i, s, *nnz;
29784f1b2e48SStefano Zampini 
2979339f8db1SStefano Zampini     /* local change of basis for pressures */
29809566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->benign_change));
29819566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_change));
29829566063dSJacob Faibussowitsch     PetscCall(MatSetType(pcbddc->benign_change, MATAIJ));
29839566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(pcbddc->benign_change, n, n, PETSC_DECIDE, PETSC_DECIDE));
29849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &nnz));
2985aa0d93e9SStefano Zampini     for (i = 0; i < n; i++) nnz[i] = 1; /* defaults to identity */
29864f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
2987aa0d93e9SStefano Zampini       const PetscInt *idxs;
29884f1b2e48SStefano Zampini       PetscInt        nzs, j;
29894f1b2e48SStefano Zampini 
29909566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nzs));
29919566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
29924f1b2e48SStefano Zampini       for (j = 0; j < nzs - 1; j++) nnz[idxs[j]] = 2; /* change on pressures */
29934f1b2e48SStefano Zampini       nnz[idxs[nzs - 1]] = nzs;                       /* last local pressure dof in subdomain */
29949566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], &idxs));
29954f1b2e48SStefano Zampini     }
29969566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_change, 0, nnz));
29979566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pcbddc->benign_change, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
29989566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
2999aa0d93e9SStefano Zampini     /* set identity by default */
300048a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(MatSetValue(pcbddc->benign_change, i, i, 1., INSERT_VALUES));
30019566063dSJacob Faibussowitsch     PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
30029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(pcbddc->benign_n, &pcbddc->benign_p0_lidx, pcbddc->benign_n, &pcbddc->benign_p0_gidx, pcbddc->benign_n, &pcbddc->benign_p0));
3003339f8db1SStefano Zampini     /* set change on pressures */
30044f1b2e48SStefano Zampini     for (s = 0; s < pcbddc->benign_n; s++) {
30054f1b2e48SStefano Zampini       PetscScalar    *array;
3006aa0d93e9SStefano Zampini       const PetscInt *idxs;
30074f1b2e48SStefano Zampini       PetscInt        nzs;
30084f1b2e48SStefano Zampini 
30099566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[s], &nzs));
30109566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
30114f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) {
3012339f8db1SStefano Zampini         PetscScalar vals[2];
3013339f8db1SStefano Zampini         PetscInt    cols[2];
3014339f8db1SStefano Zampini 
3015339f8db1SStefano Zampini         cols[0] = idxs[i];
30164f1b2e48SStefano Zampini         cols[1] = idxs[nzs - 1];
3017339f8db1SStefano Zampini         vals[0] = 1.;
3018b0f5fe93SStefano Zampini         vals[1] = 1.;
30199566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_change, 1, cols, 2, cols, vals, INSERT_VALUES));
3020339f8db1SStefano Zampini       }
30219566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nzs, &array));
30224f1b2e48SStefano Zampini       for (i = 0; i < nzs - 1; i++) array[i] = -1.;
30234f1b2e48SStefano Zampini       array[nzs - 1] = 1.;
30249566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->benign_change, 1, idxs + nzs - 1, nzs, idxs, array, INSERT_VALUES));
30254f1b2e48SStefano Zampini       /* store local idxs for p0 */
30264f1b2e48SStefano Zampini       pcbddc->benign_p0_lidx[s] = idxs[nzs - 1];
30279566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[s], &idxs));
30289566063dSJacob Faibussowitsch       PetscCall(PetscFree(array));
30294f1b2e48SStefano Zampini     }
30309566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
30319566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->benign_change, MAT_FINAL_ASSEMBLY));
30323b03f7bbSStefano Zampini 
3033a3df083aSStefano Zampini     /* project if needed */
3034a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
30351dd7afcfSStefano Zampini       Mat M;
30361dd7afcfSStefano Zampini 
30379566063dSJacob Faibussowitsch       PetscCall(MatPtAP(pcbddc->local_mat, pcbddc->benign_change, MAT_INITIAL_MATRIX, 2.0, &M));
30389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->local_mat));
30399566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJCompress(M, &pcbddc->local_mat));
30409566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&M));
3041a3df083aSStefano Zampini     }
30424f1b2e48SStefano Zampini     /* store global idxs for p0 */
30439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(matis->rmapping, pcbddc->benign_n, pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx));
3044339f8db1SStefano Zampini   }
3045339f8db1SStefano Zampini   *zerodiaglocal = zerodiag;
30463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3047339f8db1SStefano Zampini }
3048339f8db1SStefano Zampini 
3049d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignGetOrSetP0(PC pc, Vec v, PetscBool get)
3050d71ae5a4SJacob Faibussowitsch {
3051efc2fbd9SStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
3052de9d7bd0SStefano Zampini   PetscScalar *array;
3053efc2fbd9SStefano Zampini 
3054efc2fbd9SStefano Zampini   PetscFunctionBegin;
3055efc2fbd9SStefano Zampini   if (!pcbddc->benign_sf) {
30569566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &pcbddc->benign_sf));
30579566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(pcbddc->benign_sf, pc->pmat->rmap, pcbddc->benign_n, NULL, PETSC_OWN_POINTER, pcbddc->benign_p0_gidx));
3058efc2fbd9SStefano Zampini   }
3059de9d7bd0SStefano Zampini   if (get) {
30609566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, (const PetscScalar **)&array));
30619566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
30629566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(pcbddc->benign_sf, MPIU_SCALAR, array, pcbddc->benign_p0, MPI_REPLACE));
30639566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, (const PetscScalar **)&array));
3064de9d7bd0SStefano Zampini   } else {
30659566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &array));
30669566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
30679566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(pcbddc->benign_sf, MPIU_SCALAR, pcbddc->benign_p0, array, MPI_REPLACE));
30689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &array));
3069efc2fbd9SStefano Zampini   }
30703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3071efc2fbd9SStefano Zampini }
3072efc2fbd9SStefano Zampini 
3073d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCBenignPopOrPushB0(PC pc, PetscBool pop)
3074d71ae5a4SJacob Faibussowitsch {
3075c263805aSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3076c263805aSStefano Zampini 
3077c263805aSStefano Zampini   PetscFunctionBegin;
3078c263805aSStefano Zampini   /* TODO: add error checking
3079c263805aSStefano Zampini     - avoid nested pop (or push) calls.
3080c263805aSStefano Zampini     - cannot push before pop.
30811c604dc7SStefano Zampini     - cannot call this if pcbddc->local_mat is NULL
3082c263805aSStefano Zampini   */
30833ba16761SJacob Faibussowitsch   if (!pcbddc->benign_n) PetscFunctionReturn(PETSC_SUCCESS);
3084c263805aSStefano Zampini   if (pop) {
3085a3df083aSStefano Zampini     if (pcbddc->benign_change_explicit) {
30864f1b2e48SStefano Zampini       IS       is_p0;
30874f1b2e48SStefano Zampini       MatReuse reuse;
3088c263805aSStefano Zampini 
3089c263805aSStefano Zampini       /* extract B_0 */
30904f1b2e48SStefano Zampini       reuse = MAT_INITIAL_MATRIX;
3091ad540459SPierre Jolivet       if (pcbddc->benign_B0) reuse = MAT_REUSE_MATRIX;
30929566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->benign_n, pcbddc->benign_p0_lidx, PETSC_COPY_VALUES, &is_p0));
30939566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_p0, NULL, reuse, &pcbddc->benign_B0));
3094c263805aSStefano Zampini       /* remove rows and cols from local problem */
30959566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE));
30969566063dSJacob Faibussowitsch       PetscCall(MatSetOption(pcbddc->local_mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
30979566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(pcbddc->local_mat, is_p0, 1.0, NULL, NULL));
30989566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_p0));
3099a3df083aSStefano Zampini     } else {
3100a3df083aSStefano Zampini       Mat_IS      *matis = (Mat_IS *)pc->pmat->data;
3101a3df083aSStefano Zampini       PetscScalar *vals;
3102a3df083aSStefano Zampini       PetscInt     i, n, *idxs_ins;
3103a3df083aSStefano Zampini 
31049566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(matis->y, &n));
31059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n, &idxs_ins, n, &vals));
3106a3df083aSStefano Zampini       if (!pcbddc->benign_B0) {
31070b5adadeSStefano Zampini         PetscInt *nnz;
31089566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)pcbddc->local_mat), &pcbddc->benign_B0));
31099566063dSJacob Faibussowitsch         PetscCall(MatSetType(pcbddc->benign_B0, MATAIJ));
31109566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(pcbddc->benign_B0, pcbddc->benign_n, n, PETSC_DECIDE, PETSC_DECIDE));
31119566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &nnz));
3112331e053bSStefano Zampini         for (i = 0; i < pcbddc->benign_n; i++) {
31139566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nnz[i]));
3114331e053bSStefano Zampini           nnz[i] = n - nnz[i];
3115331e053bSStefano Zampini         }
31169566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(pcbddc->benign_B0, 0, nnz));
31179566063dSJacob Faibussowitsch         PetscCall(MatSetOption(pcbddc->benign_B0, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
31189566063dSJacob Faibussowitsch         PetscCall(PetscFree(nnz));
3119331e053bSStefano Zampini       }
3120a3df083aSStefano Zampini 
3121a3df083aSStefano Zampini       for (i = 0; i < pcbddc->benign_n; i++) {
3122a3df083aSStefano Zampini         PetscScalar *array;
3123a3df083aSStefano Zampini         PetscInt    *idxs, j, nz, cum;
3124a3df083aSStefano Zampini 
31259566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->x, 0.));
31269566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->benign_zerodiag_subs[i], &nz));
31279566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3128a3df083aSStefano Zampini         for (j = 0; j < nz; j++) vals[j] = 1.;
31299566063dSJacob Faibussowitsch         PetscCall(VecSetValues(matis->x, nz, idxs, vals, INSERT_VALUES));
31309566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(matis->x));
31319566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(matis->x));
31329566063dSJacob Faibussowitsch         PetscCall(VecSet(matis->y, 0.));
31339566063dSJacob Faibussowitsch         PetscCall(MatMult(matis->A, matis->x, matis->y));
31349566063dSJacob Faibussowitsch         PetscCall(VecGetArray(matis->y, &array));
3135a3df083aSStefano Zampini         cum = 0;
3136a3df083aSStefano Zampini         for (j = 0; j < n; j++) {
313722db5ddcSStefano Zampini           if (PetscUnlikely(PetscAbsScalar(array[j]) > PETSC_SMALL)) {
3138a3df083aSStefano Zampini             vals[cum]     = array[j];
3139a3df083aSStefano Zampini             idxs_ins[cum] = j;
3140a3df083aSStefano Zampini             cum++;
3141a3df083aSStefano Zampini           }
3142a3df083aSStefano Zampini         }
31439566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->benign_B0, 1, &i, cum, idxs_ins, vals, INSERT_VALUES));
31449566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(matis->y, &array));
31459566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->benign_zerodiag_subs[i], (const PetscInt **)&idxs));
3146a3df083aSStefano Zampini       }
31479566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
31489566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(pcbddc->benign_B0, MAT_FINAL_ASSEMBLY));
31499566063dSJacob Faibussowitsch       PetscCall(PetscFree2(idxs_ins, vals));
3150a3df083aSStefano Zampini     }
3151c263805aSStefano Zampini   } else { /* push */
31524f1b2e48SStefano Zampini 
31530fdf79fbSJacob Faibussowitsch     PetscCheck(pcbddc->benign_change_explicit, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot push B0!");
31540fdf79fbSJacob Faibussowitsch     for (PetscInt i = 0; i < pcbddc->benign_n; i++) {
31554f1b2e48SStefano Zampini       PetscScalar *B0_vals;
31564f1b2e48SStefano Zampini       PetscInt    *B0_cols, B0_ncol;
31574f1b2e48SStefano Zampini 
31589566063dSJacob Faibussowitsch       PetscCall(MatGetRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
31599566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, 1, pcbddc->benign_p0_lidx + i, B0_ncol, B0_cols, B0_vals, INSERT_VALUES));
31609566063dSJacob Faibussowitsch       PetscCall(MatSetValues(pcbddc->local_mat, B0_ncol, B0_cols, 1, pcbddc->benign_p0_lidx + i, B0_vals, INSERT_VALUES));
31619566063dSJacob Faibussowitsch       PetscCall(MatSetValue(pcbddc->local_mat, pcbddc->benign_p0_lidx[i], pcbddc->benign_p0_lidx[i], 0.0, INSERT_VALUES));
31629566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(pcbddc->benign_B0, i, &B0_ncol, (const PetscInt **)&B0_cols, (const PetscScalar **)&B0_vals));
31634f1b2e48SStefano Zampini     }
31649566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
31659566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pcbddc->local_mat, MAT_FINAL_ASSEMBLY));
3166c263805aSStefano Zampini   }
31673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3168c263805aSStefano Zampini }
3169c263805aSStefano Zampini 
3170d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAdaptiveSelection(PC pc)
3171d71ae5a4SJacob Faibussowitsch {
3172b1b3d7a2SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
317308122e43SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
317408122e43SStefano Zampini   PetscBLASInt    B_dummyint, B_neigs, B_ierr, B_lwork;
317508122e43SStefano Zampini   PetscBLASInt   *B_iwork, *B_ifail;
317608122e43SStefano Zampini   PetscScalar    *work, lwork;
317708122e43SStefano Zampini   PetscScalar    *St, *S, *eigv;
317808122e43SStefano Zampini   PetscScalar    *Sarray, *Starray;
3179bd2a564bSStefano Zampini   PetscReal      *eigs, thresh, lthresh, uthresh;
31801b968477SStefano Zampini   PetscInt        i, nmax, nmin, nv, cum, mss, cum2, cumarray, maxneigs;
318132fe681dSStefano Zampini   PetscBool       allocated_S_St, upart;
318208122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
318308122e43SStefano Zampini   PetscReal *rwork;
318408122e43SStefano Zampini #endif
3185b1b3d7a2SStefano Zampini 
3186b1b3d7a2SStefano Zampini   PetscFunctionBegin;
31873ba16761SJacob Faibussowitsch   if (!pcbddc->adaptive_selection) PetscFunctionReturn(PETSC_SUCCESS);
318828b400f6SJacob Faibussowitsch   PetscCheck(sub_schurs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Adaptive selection of constraints requires SubSchurs data");
318932fe681dSStefano 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");
31909371c9d4SSatish 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,
31919371c9d4SSatish Balay              sub_schurs->is_posdef);
31929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
319306a4e24aSStefano Zampini 
3194fd14bc51SStefano Zampini   if (pcbddc->dbg_flag) {
319532fe681dSStefano Zampini     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
31969566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
31979566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
31989566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check adaptive selection of constraints\n"));
31999566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
3200fd14bc51SStefano Zampini   }
3201fd14bc51SStefano Zampini 
320248a46eb9SPierre 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));
3203e496cd5dSStefano Zampini 
320408122e43SStefano Zampini   /* max size of subsets */
320508122e43SStefano Zampini   mss = 0;
320608122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
320708122e43SStefano Zampini     PetscInt subset_size;
3208862806e4SStefano Zampini 
32099566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
321008122e43SStefano Zampini     mss = PetscMax(mss, subset_size);
321108122e43SStefano Zampini   }
321208122e43SStefano Zampini 
321308122e43SStefano Zampini   /* min/max and threshold */
321408122e43SStefano Zampini   nmax           = pcbddc->adaptive_nmax > 0 ? pcbddc->adaptive_nmax : mss;
3215f6f667cfSStefano Zampini   nmin           = pcbddc->adaptive_nmin > 0 ? pcbddc->adaptive_nmin : 0;
321608122e43SStefano Zampini   nmax           = PetscMax(nmin, nmax);
3217f6f667cfSStefano Zampini   allocated_S_St = PETSC_FALSE;
3218bd2a564bSStefano Zampini   if (nmin || !sub_schurs->is_posdef) { /* XXX */
3219f6f667cfSStefano Zampini     allocated_S_St = PETSC_TRUE;
3220f6f667cfSStefano Zampini   }
322108122e43SStefano Zampini 
322208122e43SStefano Zampini   /* allocate lapack workspace */
322308122e43SStefano Zampini   cum = cum2 = 0;
322408122e43SStefano Zampini   maxneigs   = 0;
322508122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
322608122e43SStefano Zampini     PetscInt n, subset_size;
3227f6f667cfSStefano Zampini 
32289566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
322908122e43SStefano Zampini     n = PetscMin(subset_size, nmax);
32309162d606SStefano Zampini     cum += subset_size;
32319162d606SStefano Zampini     cum2 += subset_size * n;
323208122e43SStefano Zampini     maxneigs = PetscMax(maxneigs, n);
323308122e43SStefano Zampini   }
32347ebab0bbSStefano Zampini   lwork = 0;
323508122e43SStefano Zampini   if (mss) {
32367ebab0bbSStefano Zampini     PetscScalar  sdummy  = 0.;
323708122e43SStefano Zampini     PetscBLASInt B_itype = 1;
32387ebab0bbSStefano Zampini     PetscBLASInt B_N = mss, idummy = 0;
32397ebab0bbSStefano Zampini     PetscReal    rdummy = 0., zero = 0.0;
32404c6709b3SStefano Zampini     PetscReal    eps = 0.0; /* dlamch? */
324108122e43SStefano Zampini 
32420fdf79fbSJacob Faibussowitsch     PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
324308122e43SStefano Zampini     B_lwork = -1;
32447ebab0bbSStefano Zampini     /* some implementations may complain about NULL pointers, even if we are querying */
32457ebab0bbSStefano Zampini     S       = &sdummy;
32467ebab0bbSStefano Zampini     St      = &sdummy;
32477ebab0bbSStefano Zampini     eigs    = &rdummy;
32487ebab0bbSStefano Zampini     eigv    = &sdummy;
32497ebab0bbSStefano Zampini     B_iwork = &idummy;
32507ebab0bbSStefano Zampini     B_ifail = &idummy;
3251d1710679SStefano Zampini #if defined(PETSC_USE_COMPLEX)
32527ebab0bbSStefano Zampini     rwork = &rdummy;
3253d1710679SStefano Zampini #endif
32548bec7fa6SStefano Zampini     thresh = 1.0;
32559566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
325608122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3257792fecdfSBarry 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));
325808122e43SStefano Zampini #else
3259792fecdfSBarry 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));
326008122e43SStefano Zampini #endif
326108401ef6SPierre Jolivet     PetscCheck(B_ierr == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYGVX Lapack routine %d", (int)B_ierr);
32629566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
326308122e43SStefano Zampini   }
326408122e43SStefano Zampini 
326508122e43SStefano Zampini   nv = 0;
3266d62866d3SStefano 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) */
32679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &nv));
326808122e43SStefano Zampini   }
32699566063dSJacob Faibussowitsch   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lwork), &B_lwork));
327048a46eb9SPierre Jolivet   if (allocated_S_St) PetscCall(PetscMalloc2(mss * mss, &S, mss * mss, &St));
32719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(mss * mss, &eigv, mss, &eigs, B_lwork, &work, 5 * mss, &B_iwork, mss, &B_ifail));
327208122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
32739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(7 * mss, &rwork));
327408122e43SStefano Zampini #endif
32759371c9d4SSatish 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,
32769371c9d4SSatish Balay                          &pcbddc->adaptive_constraints_data));
32779566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(pcbddc->adaptive_constraints_n, nv + sub_schurs->n_subs));
327808122e43SStefano Zampini 
327908122e43SStefano Zampini   maxneigs = 0;
328072b8c272SStefano Zampini   cum = cumarray                           = 0;
32819162d606SStefano Zampini   pcbddc->adaptive_constraints_idxs_ptr[0] = 0;
32829162d606SStefano Zampini   pcbddc->adaptive_constraints_data_ptr[0] = 0;
3283d62866d3SStefano Zampini   if (sub_schurs->is_vertices && pcbddc->use_vertices) {
328408122e43SStefano Zampini     const PetscInt *idxs;
328508122e43SStefano Zampini 
32869566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_vertices, &idxs));
328708122e43SStefano Zampini     for (cum = 0; cum < nv; cum++) {
328808122e43SStefano Zampini       pcbddc->adaptive_constraints_n[cum]            = 1;
328908122e43SStefano Zampini       pcbddc->adaptive_constraints_idxs[cum]         = idxs[cum];
329008122e43SStefano Zampini       pcbddc->adaptive_constraints_data[cum]         = 1.0;
32919162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + 1;
32929162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + 1;
329308122e43SStefano Zampini     }
32949566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_vertices, &idxs));
329508122e43SStefano Zampini   }
329608122e43SStefano Zampini 
329708122e43SStefano Zampini   if (mss) { /* multilevel */
329832fe681dSStefano Zampini     if (sub_schurs->gdsw) {
329932fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
330032fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
330132fe681dSStefano Zampini     } else {
33029566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
33039566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
330408122e43SStefano Zampini     }
330532fe681dSStefano Zampini   }
330608122e43SStefano Zampini 
3307bd2a564bSStefano Zampini   lthresh = pcbddc->adaptive_threshold[0];
3308bd2a564bSStefano Zampini   uthresh = pcbddc->adaptive_threshold[1];
330932fe681dSStefano Zampini   upart   = pcbddc->use_deluxe_scaling;
331008122e43SStefano Zampini   for (i = 0; i < sub_schurs->n_subs; i++) {
331108122e43SStefano Zampini     const PetscInt *idxs;
33129d54b7f4SStefano Zampini     PetscReal       upper, lower;
3313862806e4SStefano Zampini     PetscInt        j, subset_size, eigs_start = 0;
331408122e43SStefano Zampini     PetscBLASInt    B_N;
3315aff50787SStefano Zampini     PetscBool       same_data = PETSC_FALSE;
3316bd2a564bSStefano Zampini     PetscBool       scal      = PETSC_FALSE;
331708122e43SStefano Zampini 
331832fe681dSStefano Zampini     if (upart) {
33199d54b7f4SStefano Zampini       upper = PETSC_MAX_REAL;
3320bd2a564bSStefano Zampini       lower = uthresh;
33219d54b7f4SStefano Zampini     } else {
332232fe681dSStefano Zampini       if (sub_schurs->gdsw) {
332332fe681dSStefano Zampini         upper = uthresh;
332432fe681dSStefano Zampini         lower = PETSC_MIN_REAL;
332532fe681dSStefano Zampini       } else {
332628b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->is_posdef, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented without deluxe scaling");
3327bd2a564bSStefano Zampini         upper = 1. / uthresh;
33289d54b7f4SStefano Zampini         lower = 0.;
33299d54b7f4SStefano Zampini       }
333032fe681dSStefano Zampini     }
33319566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(sub_schurs->is_subs[i], &subset_size));
33329566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(sub_schurs->is_subs[i], &idxs));
33339566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(subset_size, &B_N));
3334bd2a564bSStefano Zampini     /* this is experimental: we assume the dofs have been properly grouped to have
3335bd2a564bSStefano Zampini        the diagonal blocks Schur complements either positive or negative definite (true for Stokes) */
3336bd2a564bSStefano Zampini     if (!sub_schurs->is_posdef) {
3337bd2a564bSStefano Zampini       Mat T;
3338bd2a564bSStefano Zampini 
3339bd2a564bSStefano Zampini       for (j = 0; j < subset_size; j++) {
3340bd2a564bSStefano Zampini         if (PetscRealPart(*(Sarray + cumarray + j * (subset_size + 1))) < 0.0) {
33419566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Sarray + cumarray, &T));
33429566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
33439566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
33449566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, subset_size, Starray + cumarray, &T));
33459566063dSJacob Faibussowitsch           PetscCall(MatScale(T, -1.0));
33469566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&T));
3347bd2a564bSStefano Zampini           if (sub_schurs->change_primal_sub) {
3348bd2a564bSStefano Zampini             PetscInt        nz, k;
3349bd2a564bSStefano Zampini             const PetscInt *idxs;
3350bd2a564bSStefano Zampini 
33519566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nz));
33529566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->change_primal_sub[i], &idxs));
3353bd2a564bSStefano Zampini             for (k = 0; k < nz; k++) {
3354bd2a564bSStefano Zampini               *(Sarray + cumarray + idxs[k] * (subset_size + 1)) *= -1.0;
3355bd2a564bSStefano Zampini               *(Starray + cumarray + idxs[k] * (subset_size + 1)) = 0.0;
3356bd2a564bSStefano Zampini             }
33579566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->change_primal_sub[i], &idxs));
3358bd2a564bSStefano Zampini           }
3359bd2a564bSStefano Zampini           scal = PETSC_TRUE;
3360bd2a564bSStefano Zampini           break;
3361bd2a564bSStefano Zampini         }
3362bd2a564bSStefano Zampini       }
3363bd2a564bSStefano Zampini     }
3364bd2a564bSStefano Zampini 
3365f6f667cfSStefano Zampini     if (allocated_S_St) { /* S and S_t should be copied since we could need them later */
3366bd2a564bSStefano Zampini       if (sub_schurs->is_symmetric) {
3367aff50787SStefano Zampini         PetscInt j, k;
3368580bdb30SBarry Smith         if (sub_schurs->n_subs == 1) { /* zeroing memory to use PetscArraycmp() later */
33699566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(S, subset_size * subset_size));
33709566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(St, subset_size * subset_size));
337108122e43SStefano Zampini         }
337208122e43SStefano Zampini         for (j = 0; j < subset_size; j++) {
3373aff50787SStefano Zampini           for (k = j; k < subset_size; k++) {
3374aff50787SStefano Zampini             S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
3375aff50787SStefano Zampini             St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
3376aff50787SStefano Zampini           }
337708122e43SStefano Zampini         }
337808122e43SStefano Zampini       } else {
33799566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
33809566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
338108122e43SStefano Zampini       }
33828bec7fa6SStefano Zampini     } else {
3383f6f667cfSStefano Zampini       S  = Sarray + cumarray;
3384f6f667cfSStefano Zampini       St = Starray + cumarray;
33858bec7fa6SStefano Zampini     }
3386aff50787SStefano Zampini     /* see if we can save some work */
338748a46eb9SPierre Jolivet     if (sub_schurs->n_subs == 1 && pcbddc->use_deluxe_scaling) PetscCall(PetscArraycmp(S, St, subset_size * subset_size, &same_data));
3388aff50787SStefano Zampini 
3389b7ab4a40SStefano Zampini     if (same_data && !sub_schurs->change) { /* there's no need of constraints here */
3390aff50787SStefano Zampini       B_neigs = 0;
3391aff50787SStefano Zampini     } else {
339208122e43SStefano Zampini       PetscBLASInt B_itype = 1;
3393f6f667cfSStefano Zampini       PetscBLASInt B_IL, B_IU;
33944c6709b3SStefano Zampini       PetscReal    eps = -1.0; /* dlamch? */
33959552c7c7SStefano Zampini       PetscInt     nmin_s;
3396bd2a564bSStefano Zampini       PetscBool    compute_range;
3397bd2a564bSStefano Zampini 
33980fdf79fbSJacob Faibussowitsch       PetscCheck(sub_schurs->is_symmetric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
33999036ceccSStefano Zampini       B_neigs       = 0;
3400bd2a564bSStefano Zampini       compute_range = (PetscBool)!same_data;
3401bd2a564bSStefano Zampini       if (nmin >= subset_size) compute_range = PETSC_FALSE;
340208122e43SStefano Zampini 
3403fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
3404*a4cdd7efSStefano Zampini         PetscInt nc = 0, c = pcbddc->mat_graph->nodes[idxs[0]].count, w = pcbddc->mat_graph->nodes[idxs[0]].which_dof;
3405d16cbb6bSStefano Zampini 
340648a46eb9SPierre Jolivet         if (sub_schurs->change_primal_sub) PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nc));
34079de2952eSStefano Zampini         PetscCall(
34089de2952eSStefano Zampini           PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Computing for sub %" PetscInt_FMT "/%" PetscInt_FMT " size %" PetscInt_FMT " count %" PetscInt_FMT " fid %" PetscInt_FMT " (range %d) (change %" PetscInt_FMT ").\n", i, sub_schurs->n_subs, subset_size, c, w, compute_range, nc));
3409b7ab4a40SStefano Zampini       }
3410b7ab4a40SStefano Zampini 
34119566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
3412b7ab4a40SStefano Zampini       if (compute_range) {
3413d16cbb6bSStefano Zampini         /* ask for eigenvalues larger than thresh */
3414bd2a564bSStefano Zampini         if (sub_schurs->is_posdef) {
341508122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3416792fecdfSBarry 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));
341708122e43SStefano Zampini #else
3418792fecdfSBarry 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));
341908122e43SStefano Zampini #endif
34209566063dSJacob Faibussowitsch           PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3421bd2a564bSStefano Zampini         } else { /* no theory so far, but it works nicely */
34229036ceccSStefano Zampini           PetscInt  recipe = 0, recipe_m = 1;
3423bd2a564bSStefano Zampini           PetscReal bb[2];
3424bd2a564bSStefano Zampini 
34259566063dSJacob Faibussowitsch           PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe", &recipe, NULL));
3426bd2a564bSStefano Zampini           switch (recipe) {
3427bd2a564bSStefano Zampini           case 0:
34289371c9d4SSatish Balay             if (scal) {
34299371c9d4SSatish Balay               bb[0] = PETSC_MIN_REAL;
34309371c9d4SSatish Balay               bb[1] = lthresh;
34319371c9d4SSatish Balay             } else {
34329371c9d4SSatish Balay               bb[0] = uthresh;
34339371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
34349371c9d4SSatish Balay             }
3435bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3436792fecdfSBarry 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));
3437bd2a564bSStefano Zampini #else
3438792fecdfSBarry 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));
3439bd2a564bSStefano Zampini #endif
34409566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3441bd2a564bSStefano Zampini             break;
3442d71ae5a4SJacob Faibussowitsch           case 1:
3443d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3444d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh * lthresh;
3445bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3446792fecdfSBarry 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));
3447bd2a564bSStefano Zampini #else
3448792fecdfSBarry 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));
3449bd2a564bSStefano Zampini #endif
34509566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3451bd2a564bSStefano Zampini             if (!scal) {
34529036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
3453bd2a564bSStefano Zampini 
34549371c9d4SSatish Balay               bb[0] = PetscMax(lthresh * lthresh, uthresh);
34559371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
34569566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34579566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
3458bd2a564bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3459792fecdfSBarry 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));
3460bd2a564bSStefano Zampini #else
3461792fecdfSBarry 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));
3462bd2a564bSStefano Zampini #endif
34639566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3464bd2a564bSStefano Zampini               B_neigs += B_neigs2;
3465bd2a564bSStefano Zampini             }
3466bd2a564bSStefano Zampini             break;
34679036ceccSStefano Zampini           case 2:
34689036ceccSStefano Zampini             if (scal) {
34699036ceccSStefano Zampini               bb[0] = PETSC_MIN_REAL;
34709036ceccSStefano Zampini               bb[1] = 0;
34719036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3472792fecdfSBarry 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));
34739036ceccSStefano Zampini #else
3474792fecdfSBarry 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));
34759036ceccSStefano Zampini #endif
34769566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34779036ceccSStefano Zampini             } else {
34789036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
347913bcc0bdSJacob Faibussowitsch               PetscBool    do_copy  = PETSC_FALSE;
34809036ceccSStefano Zampini 
34819036ceccSStefano Zampini               lthresh = PetscMax(lthresh, 0.0);
34829036ceccSStefano Zampini               if (lthresh > 0.0) {
34839036ceccSStefano Zampini                 bb[0] = PETSC_MIN_REAL;
34849036ceccSStefano Zampini                 bb[1] = lthresh * lthresh;
34859036ceccSStefano Zampini 
348613bcc0bdSJacob Faibussowitsch                 do_copy = PETSC_TRUE;
34879036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3488792fecdfSBarry 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));
34899036ceccSStefano Zampini #else
3490792fecdfSBarry 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));
34919036ceccSStefano Zampini #endif
34929566063dSJacob Faibussowitsch                 PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
34939036ceccSStefano Zampini               }
34949036ceccSStefano Zampini               bb[0] = PetscMax(lthresh * lthresh, uthresh);
34959036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
349613bcc0bdSJacob Faibussowitsch               if (do_copy) {
34979566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
34989566063dSJacob Faibussowitsch                 PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
34999036ceccSStefano Zampini               }
35009036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3501792fecdfSBarry 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));
35029036ceccSStefano Zampini #else
3503792fecdfSBarry 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));
35049036ceccSStefano Zampini #endif
35059566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35069036ceccSStefano Zampini               B_neigs += B_neigs2;
35079036ceccSStefano Zampini             }
35089036ceccSStefano Zampini             break;
35099036ceccSStefano Zampini           case 3:
35109036ceccSStefano Zampini             if (scal) {
35119566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min_scal", &recipe_m, NULL));
35129036ceccSStefano Zampini             } else {
35139566063dSJacob Faibussowitsch               PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)pc)->prefix, "-pc_bddc_adaptive_recipe3_min", &recipe_m, NULL));
35149036ceccSStefano Zampini             }
35159036ceccSStefano Zampini             if (!scal) {
35169036ceccSStefano Zampini               bb[0] = uthresh;
35179036ceccSStefano Zampini               bb[1] = PETSC_MAX_REAL;
35189036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3519792fecdfSBarry 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));
35209036ceccSStefano Zampini #else
3521792fecdfSBarry 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));
35229036ceccSStefano Zampini #endif
35239566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35249036ceccSStefano Zampini             }
35259036ceccSStefano Zampini             if (recipe_m > 0 && B_N - B_neigs > 0) {
35269036ceccSStefano Zampini               PetscBLASInt B_neigs2 = 0;
35279036ceccSStefano Zampini 
35289036ceccSStefano Zampini               B_IL = 1;
35299566063dSJacob Faibussowitsch               PetscCall(PetscBLASIntCast(PetscMin(recipe_m, B_N - B_neigs), &B_IU));
35309566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35319566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
35329036ceccSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3533792fecdfSBarry 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));
35349036ceccSStefano Zampini #else
3535792fecdfSBarry 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));
35369036ceccSStefano Zampini #endif
35379566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
35389036ceccSStefano Zampini               B_neigs += B_neigs2;
35399036ceccSStefano Zampini             }
35409036ceccSStefano Zampini             break;
3541d71ae5a4SJacob Faibussowitsch           case 4:
3542d71ae5a4SJacob Faibussowitsch             bb[0] = PETSC_MIN_REAL;
3543d71ae5a4SJacob Faibussowitsch             bb[1] = lthresh;
354448cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3545792fecdfSBarry 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));
354648cebe81SStefano Zampini #else
3547792fecdfSBarry 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));
354848cebe81SStefano Zampini #endif
35499566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
355048cebe81SStefano Zampini             {
355148cebe81SStefano Zampini               PetscBLASInt B_neigs2 = 0;
355248cebe81SStefano Zampini 
35539371c9d4SSatish Balay               bb[0] = PetscMax(lthresh + PETSC_SMALL, uthresh);
35549371c9d4SSatish Balay               bb[1] = PETSC_MAX_REAL;
35559566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
35569566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
355748cebe81SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3558792fecdfSBarry 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));
355948cebe81SStefano Zampini #else
3560792fecdfSBarry 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));
356148cebe81SStefano Zampini #endif
35629566063dSJacob Faibussowitsch               PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
356348cebe81SStefano Zampini               B_neigs += B_neigs2;
356448cebe81SStefano Zampini             }
356548cebe81SStefano Zampini             break;
356680db8efeSStefano Zampini           case 5: /* same as before: first compute all eigenvalues, then filter */
356780db8efeSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3568792fecdfSBarry 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));
356980db8efeSStefano Zampini #else
3570792fecdfSBarry 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));
357180db8efeSStefano Zampini #endif
35729566063dSJacob Faibussowitsch             PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
357380db8efeSStefano Zampini             {
357480db8efeSStefano Zampini               PetscInt e, k, ne;
357580db8efeSStefano Zampini               for (e = 0, ne = 0; e < B_neigs; e++) {
357680db8efeSStefano Zampini                 if (eigs[e] < lthresh || eigs[e] > uthresh) {
357780db8efeSStefano Zampini                   for (k = 0; k < B_N; k++) S[ne * B_N + k] = eigv[e * B_N + k];
357880db8efeSStefano Zampini                   eigs[ne] = eigs[e];
357980db8efeSStefano Zampini                   ne++;
358080db8efeSStefano Zampini                 }
358180db8efeSStefano Zampini               }
35829566063dSJacob Faibussowitsch               PetscCall(PetscArraycpy(eigv, S, B_N * ne));
358380db8efeSStefano Zampini               B_neigs = ne;
358480db8efeSStefano Zampini             }
358580db8efeSStefano Zampini             break;
3586d71ae5a4SJacob Faibussowitsch           default:
3587d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unknown recipe %" PetscInt_FMT, recipe);
3588bd2a564bSStefano Zampini           }
3589bd2a564bSStefano Zampini         }
3590bd2a564bSStefano Zampini       } else if (!same_data) { /* this is just to see all the eigenvalues */
3591d16cbb6bSStefano Zampini         B_IU = PetscMax(1, PetscMin(B_N, nmax));
3592d16cbb6bSStefano Zampini         B_IL = 1;
3593d16cbb6bSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3594792fecdfSBarry 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));
3595d16cbb6bSStefano Zampini #else
3596792fecdfSBarry 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));
3597d16cbb6bSStefano Zampini #endif
35989566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
3599b03ebc13SStefano Zampini       } else { /* same_data is true, so just get the adaptive functional requested by the user */
3600b7ab4a40SStefano Zampini         PetscInt k;
360128b400f6SJacob Faibussowitsch         PetscCheck(sub_schurs->change_primal_sub, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
36029566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(sub_schurs->change_primal_sub[i], &nmax));
36039566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(nmax, &B_neigs));
3604b7ab4a40SStefano Zampini         nmin = nmax;
36059566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(eigv, subset_size * nmax));
3606b7ab4a40SStefano Zampini         for (k = 0; k < nmax; k++) {
3607b7ab4a40SStefano Zampini           eigs[k]                     = 1. / PETSC_SMALL;
3608b7ab4a40SStefano Zampini           eigv[k * (subset_size + 1)] = 1.0;
3609b7ab4a40SStefano Zampini         }
3610d16cbb6bSStefano Zampini       }
36119566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
361208122e43SStefano Zampini       if (B_ierr) {
361363a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
361463a3b9bcSJacob 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);
361563a3b9bcSJacob 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);
361608122e43SStefano Zampini       }
361708122e43SStefano Zampini 
361808122e43SStefano Zampini       if (B_neigs > nmax) {
361948a46eb9SPierre Jolivet         if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   found %" PetscBLASInt_FMT " eigs, more than maximum required %" PetscInt_FMT ".\n", B_neigs, nmax));
362032fe681dSStefano Zampini         if (upart) eigs_start = scal ? 0 : B_neigs - nmax;
362108122e43SStefano Zampini         B_neigs = nmax;
362208122e43SStefano Zampini       }
362308122e43SStefano Zampini 
36249552c7c7SStefano Zampini       nmin_s = PetscMin(nmin, B_N);
36259552c7c7SStefano Zampini       if (B_neigs < nmin_s) {
36269036ceccSStefano Zampini         PetscBLASInt B_neigs2 = 0;
362708122e43SStefano Zampini 
362832fe681dSStefano Zampini         if (upart) {
3629bd2a564bSStefano Zampini           if (scal) {
3630bd2a564bSStefano Zampini             B_IU = nmin_s;
3631bd2a564bSStefano Zampini             B_IL = B_neigs + 1;
3632bd2a564bSStefano Zampini           } else {
3633f6f667cfSStefano Zampini             B_IL = B_N - nmin_s + 1;
36349d54b7f4SStefano Zampini             B_IU = B_N - B_neigs;
3635bd2a564bSStefano Zampini           }
36369d54b7f4SStefano Zampini         } else {
36379d54b7f4SStefano Zampini           B_IL = B_neigs + 1;
36389d54b7f4SStefano Zampini           B_IU = nmin_s;
36399d54b7f4SStefano Zampini         }
3640fd14bc51SStefano Zampini         if (pcbddc->dbg_flag) {
364163a3b9bcSJacob 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));
3642fd14bc51SStefano Zampini         }
3643bd2a564bSStefano Zampini         if (sub_schurs->is_symmetric) {
36441ae86dd6SStefano Zampini           PetscInt j, k;
364508122e43SStefano Zampini           for (j = 0; j < subset_size; j++) {
36461ae86dd6SStefano Zampini             for (k = j; k < subset_size; k++) {
36471ae86dd6SStefano Zampini               S[j * subset_size + k]  = Sarray[cumarray + j * subset_size + k];
36481ae86dd6SStefano Zampini               St[j * subset_size + k] = Starray[cumarray + j * subset_size + k];
364908122e43SStefano Zampini             }
365008122e43SStefano Zampini           }
365108122e43SStefano Zampini         } else {
36529566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(S, Sarray + cumarray, subset_size * subset_size));
36539566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(St, Starray + cumarray, subset_size * subset_size));
365408122e43SStefano Zampini         }
36559566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
365608122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
3657792fecdfSBarry 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));
365808122e43SStefano Zampini #else
3659792fecdfSBarry 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));
366008122e43SStefano Zampini #endif
36619566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops((4.0 * subset_size * subset_size * subset_size) / 3.0));
36629566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
366308122e43SStefano Zampini         B_neigs += B_neigs2;
366408122e43SStefano Zampini       }
366508122e43SStefano Zampini       if (B_ierr) {
366663a3b9bcSJacob Faibussowitsch         PetscCheck(B_ierr >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYGVX Lapack routine: illegal value for argument %" PetscBLASInt_FMT, -B_ierr);
366763a3b9bcSJacob 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);
366863a3b9bcSJacob 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);
366908122e43SStefano Zampini       }
3670fd14bc51SStefano Zampini       if (pcbddc->dbg_flag) {
367163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Got %" PetscBLASInt_FMT " eigs\n", B_neigs));
367208122e43SStefano Zampini         for (j = 0; j < B_neigs; j++) {
367332fe681dSStefano Zampini           if (!sub_schurs->gdsw) {
367408122e43SStefano Zampini             if (eigs[j] == 0.0) {
36759566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     Inf\n"));
367608122e43SStefano Zampini             } else {
367732fe681dSStefano Zampini               if (upart) {
367863a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)eigs[j + eigs_start]));
36799d54b7f4SStefano Zampini               } else {
368063a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", (double)(1. / eigs[j + eigs_start])));
36819d54b7f4SStefano Zampini               }
3682fd14bc51SStefano Zampini             }
368332fe681dSStefano Zampini           } else {
368432fe681dSStefano Zampini             double pg = (double)eigs[j + eigs_start];
368532fe681dSStefano Zampini             if (pg < 2 * PETSC_SMALL) pg = 0.0;
368632fe681dSStefano Zampini             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "     %1.6e\n", pg));
368732fe681dSStefano Zampini           }
368808122e43SStefano Zampini         }
368908122e43SStefano Zampini       }
3690aff50787SStefano Zampini     }
36916c3e6151SStefano Zampini     /* change the basis back to the original one */
36926c3e6151SStefano Zampini     if (sub_schurs->change) {
369372b8c272SStefano Zampini       Mat change, phi, phit;
36946c3e6151SStefano Zampini 
369503dfb2d7SStefano Zampini       if (pcbddc->dbg_flag > 2) {
36966c3e6151SStefano Zampini         PetscInt ii;
36976c3e6151SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
369863a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector (old basis) %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
36996c3e6151SStefano Zampini           for (j = 0; j < B_N; j++) {
3700684229deSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3701684229deSStefano Zampini             PetscReal r = PetscRealPart(eigv[(ii + eigs_start) * subset_size + j]);
3702684229deSStefano Zampini             PetscReal c = PetscImaginaryPart(eigv[(ii + eigs_start) * subset_size + j]);
370363a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3704684229deSStefano Zampini #else
370563a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e\n", (double)(eigv[(ii + eigs_start) * subset_size + j])));
3706684229deSStefano Zampini #endif
37076c3e6151SStefano Zampini           }
37086c3e6151SStefano Zampini         }
37096c3e6151SStefano Zampini       }
37109566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(sub_schurs->change[i], &change, NULL));
37119566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, subset_size, B_neigs, eigv + eigs_start * subset_size, &phit));
37129566063dSJacob Faibussowitsch       PetscCall(MatMatMult(change, phit, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &phi));
37139566063dSJacob Faibussowitsch       PetscCall(MatCopy(phi, phit, SAME_NONZERO_PATTERN));
37149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phit));
37159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&phi));
37166c3e6151SStefano Zampini     }
37178bec7fa6SStefano Zampini     maxneigs                               = PetscMax(B_neigs, maxneigs);
37188bec7fa6SStefano Zampini     pcbddc->adaptive_constraints_n[i + nv] = B_neigs;
37199162d606SStefano Zampini     if (B_neigs) {
37209566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_data + pcbddc->adaptive_constraints_data_ptr[cum], eigv + eigs_start * subset_size, B_neigs * subset_size));
3721fd14bc51SStefano Zampini 
3722fd14bc51SStefano Zampini       if (pcbddc->dbg_flag > 1) {
37239552c7c7SStefano Zampini         PetscInt ii;
37249552c7c7SStefano Zampini         for (ii = 0; ii < B_neigs; ii++) {
372563a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "   -> Eigenvector %" PetscInt_FMT "/%" PetscBLASInt_FMT " (%" PetscBLASInt_FMT ")\n", ii, B_neigs, B_N));
37269552c7c7SStefano Zampini           for (j = 0; j < B_N; j++) {
3727ac47001eSStefano Zampini #if defined(PETSC_USE_COMPLEX)
3728ac47001eSStefano Zampini             PetscReal r = PetscRealPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
3729ac47001eSStefano Zampini             PetscReal c = PetscImaginaryPart(pcbddc->adaptive_constraints_data[ii * subset_size + j + pcbddc->adaptive_constraints_data_ptr[cum]]);
373063a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "       %1.4e + %1.4e i\n", (double)r, (double)c));
3731ac47001eSStefano Zampini #else
373263a3b9bcSJacob 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]])));
3733ac47001eSStefano Zampini #endif
37349552c7c7SStefano Zampini           }
37359552c7c7SStefano Zampini         }
3736fd14bc51SStefano Zampini       }
37379566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pcbddc->adaptive_constraints_idxs + pcbddc->adaptive_constraints_idxs_ptr[cum], idxs, subset_size));
37389162d606SStefano Zampini       pcbddc->adaptive_constraints_idxs_ptr[cum + 1] = pcbddc->adaptive_constraints_idxs_ptr[cum] + subset_size;
37399162d606SStefano Zampini       pcbddc->adaptive_constraints_data_ptr[cum + 1] = pcbddc->adaptive_constraints_data_ptr[cum] + subset_size * B_neigs;
37409162d606SStefano Zampini       cum++;
374108122e43SStefano Zampini     }
37429566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(sub_schurs->is_subs[i], &idxs));
374308122e43SStefano Zampini     /* shift for next computation */
374408122e43SStefano Zampini     cumarray += subset_size * subset_size;
374508122e43SStefano Zampini   }
37461baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
374708122e43SStefano Zampini 
374808122e43SStefano Zampini   if (mss) {
374932fe681dSStefano Zampini     if (sub_schurs->gdsw) {
375032fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_all, &Sarray));
375132fe681dSStefano Zampini       PetscCall(MatSeqAIJGetArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
375232fe681dSStefano Zampini     } else {
37539566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_inv_all, &Sarray));
37549566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(sub_schurs->sum_S_Ej_tilda_all, &Starray));
3755f6f667cfSStefano Zampini       /* destroy matrices (junk) */
37569566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_inv_all));
37579566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_tilda_all));
375808122e43SStefano Zampini     }
375932fe681dSStefano Zampini   }
37601baa6e33SBarry Smith   if (allocated_S_St) PetscCall(PetscFree2(S, St));
37619566063dSJacob Faibussowitsch   PetscCall(PetscFree5(eigv, eigs, work, B_iwork, B_ifail));
376208122e43SStefano Zampini #if defined(PETSC_USE_COMPLEX)
37639566063dSJacob Faibussowitsch   PetscCall(PetscFree(rwork));
376408122e43SStefano Zampini #endif
376508122e43SStefano Zampini   if (pcbddc->dbg_flag) {
37661b968477SStefano Zampini     PetscInt maxneigs_r;
37671c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&maxneigs, &maxneigs_r, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
376863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of constraints per cc %" PetscInt_FMT "\n", maxneigs_r));
376908122e43SStefano Zampini   }
37709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_AdaptiveSetUp[pcbddc->current_level], pc, 0, 0, 0));
37713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
377208122e43SStefano Zampini }
3773b1b3d7a2SStefano Zampini 
3774d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSolvers(PC pc)
3775d71ae5a4SJacob Faibussowitsch {
37769de2952eSStefano Zampini   Mat coarse_submat;
3777c8587f34SStefano Zampini 
3778c8587f34SStefano Zampini   PetscFunctionBegin;
3779f4ddd8eeSStefano Zampini   /* Setup local scatters R_to_B and (optionally) R_to_D */
37805e8657edSStefano Zampini   /* PCBDDCSetUpLocalWorkVectors should be called first! */
37819566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalScatters(pc));
3782c8587f34SStefano Zampini 
3783684f6988SStefano Zampini   /* Setup local neumann solver ksp_R */
37840fccc4e9SStefano Zampini   /* PCBDDCSetUpLocalScatters should be called first! */
37859566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_FALSE, PETSC_TRUE));
3786c8587f34SStefano Zampini 
37878629588bSStefano Zampini   /*
37888629588bSStefano Zampini      Setup local correction and local part of coarse basis.
37898629588bSStefano Zampini      Gives back the dense local part of the coarse matrix in column major ordering
37908629588bSStefano Zampini   */
37919de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCorrection(pc, &coarse_submat));
37928629588bSStefano Zampini 
37938629588bSStefano Zampini   /* Compute total number of coarse nodes and setup coarse solver */
37949de2952eSStefano Zampini   PetscCall(PCBDDCSetUpCoarseSolver(pc, coarse_submat));
37959de2952eSStefano Zampini   PetscCall(MatDestroy(&coarse_submat));
37963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3797c8587f34SStefano Zampini }
3798c8587f34SStefano Zampini 
3799d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetCustomization(PC pc)
3800d71ae5a4SJacob Faibussowitsch {
3801674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3802674ae819SStefano Zampini 
3803674ae819SStefano Zampini   PetscFunctionBegin;
38049566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
38059566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
38069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
38079566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
38089566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
38099566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
38109566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->onearnullvecs_state));
38119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
38129566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplitting(pc, 0, NULL));
38139566063dSJacob Faibussowitsch   PetscCall(PCBDDCSetDofsSplittingLocal(pc, 0, NULL));
38143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3815674ae819SStefano Zampini }
3816674ae819SStefano Zampini 
3817d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetTopography(PC pc)
3818d71ae5a4SJacob Faibussowitsch {
3819674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
38204f1b2e48SStefano Zampini   PetscInt i;
3821674ae819SStefano Zampini 
3822674ae819SStefano Zampini   PetscFunctionBegin;
38239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->nedcG));
38249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->nedclocal));
38259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->discretegradient));
38269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
38279566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
38289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
38299566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->work_change));
38309566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
38319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->divudotp));
38329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
38339566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphDestroy(&pcbddc->mat_graph));
383448a46eb9SPierre Jolivet   for (i = 0; i < pcbddc->n_local_subs; i++) PetscCall(ISDestroy(&pcbddc->local_subs[i]));
3835e68a0315Sstefano_zampini   pcbddc->n_local_subs = 0;
38369566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->local_subs));
38379566063dSJacob Faibussowitsch   PetscCall(PCBDDCSubSchursDestroy(&pcbddc->sub_schurs));
3838c703fcc7SStefano Zampini   pcbddc->graphanalyzed        = PETSC_FALSE;
38398af8fcf9SStefano Zampini   pcbddc->recompute_topography = PETSC_TRUE;
38401c7a958bSStefano Zampini   pcbddc->corner_selected      = PETSC_FALSE;
38413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3842674ae819SStefano Zampini }
3843674ae819SStefano Zampini 
3844d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCResetSolvers(PC pc)
3845d71ae5a4SJacob Faibussowitsch {
3846674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
3847674ae819SStefano Zampini 
3848674ae819SStefano Zampini   PetscFunctionBegin;
38499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->coarse_vec));
38509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
38519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
38529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
38539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
38549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_P));
38559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_C));
38569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
38579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
38589566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec1_R));
38599566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->vec2_R));
38609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
38619566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
38629566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
38639566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
38649566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_D));
38659566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->ksp_R));
38669566063dSJacob Faibussowitsch   PetscCall(KSPReset(pcbddc->coarse_ksp));
38679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
38689566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
38699566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
38709566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->global_primal_indices));
38719566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
38729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_change));
38739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pcbddc->benign_vec));
38749566063dSJacob Faibussowitsch   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
38759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->benign_B0));
38769566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pcbddc->benign_sf));
3877ca92afb2SStefano Zampini   if (pcbddc->benign_zerodiag_subs) {
3878ca92afb2SStefano Zampini     PetscInt i;
387948a46eb9SPierre Jolivet     for (i = 0; i < pcbddc->benign_n; i++) PetscCall(ISDestroy(&pcbddc->benign_zerodiag_subs[i]));
38809566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->benign_zerodiag_subs));
3881ca92afb2SStefano Zampini   }
38829566063dSJacob Faibussowitsch   PetscCall(PetscFree3(pcbddc->benign_p0_lidx, pcbddc->benign_p0_gidx, pcbddc->benign_p0));
38833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3884674ae819SStefano Zampini }
3885674ae819SStefano Zampini 
3886d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalWorkVectors(PC pc)
3887d71ae5a4SJacob Faibussowitsch {
38886bfb1811SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
38896bfb1811SStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
38906bfb1811SStefano Zampini   VecType  impVecType;
38914f1b2e48SStefano Zampini   PetscInt n_constraints, n_R, old_size;
38926bfb1811SStefano Zampini 
38936bfb1811SStefano Zampini   PetscFunctionBegin;
38944f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - pcbddc->n_vertices;
3895b371cd4fSStefano Zampini   n_R           = pcis->n - pcbddc->n_vertices;
38969566063dSJacob Faibussowitsch   PetscCall(VecGetType(pcis->vec1_N, &impVecType));
3897e7b262bdSStefano Zampini   /* local work vectors (try to avoid unneeded work)*/
3898e7b262bdSStefano Zampini   /* R nodes */
3899e7b262bdSStefano Zampini   old_size = -1;
390048a46eb9SPierre Jolivet   if (pcbddc->vec1_R) PetscCall(VecGetSize(pcbddc->vec1_R, &old_size));
3901e7b262bdSStefano Zampini   if (n_R != old_size) {
39029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_R));
39039566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec2_R));
39049566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_R));
39059566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_R, PETSC_DECIDE, n_R));
39069566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_R, impVecType));
39079566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(pcbddc->vec1_R, &pcbddc->vec2_R));
3908e7b262bdSStefano Zampini   }
3909e7b262bdSStefano Zampini   /* local primal dofs */
3910e7b262bdSStefano Zampini   old_size = -1;
391148a46eb9SPierre Jolivet   if (pcbddc->vec1_P) PetscCall(VecGetSize(pcbddc->vec1_P, &old_size));
3912e9189074SStefano Zampini   if (pcbddc->local_primal_size != old_size) {
39139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_P));
39149566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_P));
39159566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_P, PETSC_DECIDE, pcbddc->local_primal_size));
39169566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_P, impVecType));
3917e7b262bdSStefano Zampini   }
3918e7b262bdSStefano Zampini   /* local explicit constraints */
3919e7b262bdSStefano Zampini   old_size = -1;
392048a46eb9SPierre Jolivet   if (pcbddc->vec1_C) PetscCall(VecGetSize(pcbddc->vec1_C, &old_size));
3921e7b262bdSStefano Zampini   if (n_constraints && n_constraints != old_size) {
39229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->vec1_C));
39239566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &pcbddc->vec1_C));
39249566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->vec1_C, PETSC_DECIDE, n_constraints));
39259566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->vec1_C, impVecType));
392683b7ccabSStefano Zampini   }
39273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39286bfb1811SStefano Zampini }
39296bfb1811SStefano Zampini 
39309de2952eSStefano Zampini static PetscErrorCode MatSetValuesSubMat(Mat A, Mat S, PetscInt nr, const PetscInt rows[], PetscInt nc, const PetscInt cols[], InsertMode imode)
3931d71ae5a4SJacob Faibussowitsch {
39329de2952eSStefano Zampini   PetscBool          flg;
39339de2952eSStefano Zampini   const PetscScalar *a;
39349de2952eSStefano Zampini 
39359de2952eSStefano Zampini   PetscFunctionBegin;
39369de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQDENSE, &flg));
39379de2952eSStefano Zampini   if (flg) {
39389de2952eSStefano Zampini     PetscCall(MatDenseGetArrayRead(S, &a));
39399de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_FALSE));
39409de2952eSStefano Zampini     PetscCall(MatSetValues(A, nr, rows, nc, cols, a, imode));
39419de2952eSStefano Zampini     PetscCall(MatSetOption(A, MAT_ROW_ORIENTED, PETSC_TRUE));
39429de2952eSStefano Zampini     PetscCall(MatDenseRestoreArrayRead(S, &a));
39439de2952eSStefano Zampini   } else {
39449de2952eSStefano Zampini     const PetscInt *ii, *jj;
39459de2952eSStefano Zampini     PetscInt        n;
39469de2952eSStefano Zampini     PetscInt        buf[8192], *bufc = NULL;
39479de2952eSStefano Zampini     PetscBool       freeb = PETSC_FALSE;
39489de2952eSStefano Zampini     Mat             Sm    = S;
39499de2952eSStefano Zampini 
39509de2952eSStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)S, MATSEQAIJ, &flg));
39519de2952eSStefano Zampini     if (!flg) PetscCall(MatConvert(S, MATSEQAIJ, MAT_INITIAL_MATRIX, &Sm));
39529de2952eSStefano Zampini     else PetscCall(PetscObjectReference((PetscObject)S));
39539de2952eSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(Sm, &a));
39549de2952eSStefano Zampini     PetscCall(MatGetRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
39559de2952eSStefano Zampini     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot get IJ structure");
39569de2952eSStefano Zampini     if (nc <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
39579de2952eSStefano Zampini       bufc = buf;
39589de2952eSStefano Zampini     } else {
39599de2952eSStefano Zampini       PetscCall(PetscMalloc1(nc, &bufc));
39609de2952eSStefano Zampini       freeb = PETSC_TRUE;
39619de2952eSStefano Zampini     }
39629de2952eSStefano Zampini 
39639de2952eSStefano Zampini     for (PetscInt i = 0; i < n; i++) {
39649de2952eSStefano Zampini       const PetscInt nci = ii[i + 1] - ii[i];
39659de2952eSStefano Zampini 
39669de2952eSStefano Zampini       for (PetscInt j = 0; j < nci; j++) bufc[j] = cols[jj[ii[i] + j]];
39679de2952eSStefano Zampini       PetscCall(MatSetValues(A, 1, rows + i, nci, bufc, a + ii[i], imode));
39689de2952eSStefano Zampini     }
39699de2952eSStefano Zampini     PetscCall(MatRestoreRowIJ(Sm, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg));
39709de2952eSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(Sm, &a));
39719de2952eSStefano Zampini     PetscCall(MatDestroy(&Sm));
39729de2952eSStefano Zampini     if (freeb) PetscCall(PetscFree(bufc));
39739de2952eSStefano Zampini   }
39749de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY));
39759de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY));
39769de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
39779de2952eSStefano Zampini }
39789de2952eSStefano Zampini 
39799de2952eSStefano Zampini static PetscErrorCode MatCreateSeqAIJFromDenseExpand(Mat D, PetscInt n, const PetscInt j[], Mat *mat)
39809de2952eSStefano Zampini {
39819de2952eSStefano Zampini   Mat_SeqAIJ        *aij;
39829de2952eSStefano Zampini   PetscInt          *ii, *jj;
39839de2952eSStefano Zampini   PetscScalar       *aa;
39849de2952eSStefano Zampini   PetscInt           nnz = 0, m, nc;
39859de2952eSStefano Zampini   const PetscScalar *a;
39869de2952eSStefano Zampini   const PetscScalar  zero = 0.0;
39879de2952eSStefano Zampini 
39889de2952eSStefano Zampini   PetscFunctionBegin;
39899de2952eSStefano Zampini   PetscCall(MatGetLocalSize(D, &m, &nc));
39909de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(D, &a));
39919de2952eSStefano Zampini   PetscCall(PetscMalloc1(m + 1, &ii));
39929de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &jj));
39939de2952eSStefano Zampini   PetscCall(PetscMalloc1(m * nc, &aa));
39949de2952eSStefano Zampini   ii[0] = 0;
39959de2952eSStefano Zampini   for (PetscInt k = 0; k < m; k++) {
39969de2952eSStefano Zampini     for (PetscInt s = 0; s < nc; s++) {
39979de2952eSStefano Zampini       const PetscInt    c = s + k * nc;
39989de2952eSStefano Zampini       const PetscScalar v = a[k + s * m];
39999de2952eSStefano Zampini 
40009de2952eSStefano Zampini       if (PetscUnlikely(j[c] < 0 || v == zero)) continue;
40019de2952eSStefano Zampini       jj[nnz] = j[c];
40029de2952eSStefano Zampini       aa[nnz] = a[k + s * m];
40039de2952eSStefano Zampini       nnz++;
40049de2952eSStefano Zampini     }
40059de2952eSStefano Zampini     ii[k + 1] = nnz;
40069de2952eSStefano Zampini   }
40079de2952eSStefano Zampini 
40089de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)D), m, n, ii, jj, aa, mat));
40099de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(D, &a));
40109de2952eSStefano Zampini 
40119de2952eSStefano Zampini   aij          = (Mat_SeqAIJ *)(*mat)->data;
40129de2952eSStefano Zampini   aij->free_a  = PETSC_TRUE;
40139de2952eSStefano Zampini   aij->free_ij = PETSC_TRUE;
40149de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
40159de2952eSStefano Zampini }
40169de2952eSStefano Zampini 
40179de2952eSStefano Zampini /* adapted from MatInvertVariableBlockDiagonal_SeqAIJ */
40189de2952eSStefano Zampini static PetscErrorCode MatSeqAIJInvertVariableBlockDiagonalMat(Mat A, PetscInt nblocks, const PetscInt *bsizes, Mat *B)
40199de2952eSStefano Zampini {
40209de2952eSStefano Zampini   PetscInt        n = A->rmap->n, ncnt = 0, ncnt2 = 0, bsizemax = 0, *v_pivots = NULL;
40219de2952eSStefano Zampini   const PetscBool allowzeropivot    = PETSC_FALSE;
40229de2952eSStefano Zampini   PetscBool       zeropivotdetected = PETSC_FALSE;
40239de2952eSStefano Zampini   const PetscReal shift             = 0.0;
40249de2952eSStefano Zampini   PetscInt        ipvt[5], *ii, *jj, *indi, *indj;
40259de2952eSStefano Zampini   PetscScalar     work[25], *v_work = NULL, *aa, *diag;
40269de2952eSStefano Zampini   PetscLogDouble  flops = 0.0;
40279de2952eSStefano Zampini 
40289de2952eSStefano Zampini   PetscFunctionBegin;
40299de2952eSStefano Zampini   PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Not for rectangular matrices");
40309de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
40319de2952eSStefano Zampini     ncnt += bsizes[i];
40329de2952eSStefano Zampini     ncnt2 += PetscSqr(bsizes[i]);
40339de2952eSStefano Zampini   }
40349de2952eSStefano Zampini   PetscCheck(ncnt == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total blocksizes %" PetscInt_FMT " doesn't match number matrix rows %" PetscInt_FMT, ncnt, n);
40359de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]);
40369de2952eSStefano Zampini   if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots));
40379de2952eSStefano Zampini 
40389de2952eSStefano Zampini   PetscCall(PetscMalloc1(n + 1, &ii));
40399de2952eSStefano Zampini   PetscCall(PetscMalloc1(ncnt2, &jj));
40409de2952eSStefano Zampini   PetscCall(PetscCalloc1(ncnt2, &aa));
40419de2952eSStefano Zampini 
40429de2952eSStefano Zampini   ncnt  = 0;
40439de2952eSStefano Zampini   ii[0] = 0;
40449de2952eSStefano Zampini   indi  = ii;
40459de2952eSStefano Zampini   indj  = jj;
40469de2952eSStefano Zampini   diag  = aa;
40479de2952eSStefano Zampini   for (PetscInt i = 0; i < nblocks; i++) {
40489de2952eSStefano Zampini     const PetscInt bs = bsizes[i];
40499de2952eSStefano Zampini 
40509de2952eSStefano Zampini     for (PetscInt k = 0; k < bs; k++) {
40519de2952eSStefano Zampini       indi[k + 1] = indi[k] + bs;
40529de2952eSStefano Zampini       for (PetscInt j = 0; j < bs; j++) indj[k * bs + j] = ncnt + j;
40539de2952eSStefano Zampini     }
40549de2952eSStefano Zampini     PetscCall(MatGetValues(A, bs, indj, bs, indj, diag));
40559de2952eSStefano Zampini     switch (bs) {
40569de2952eSStefano Zampini     case 1:
40579de2952eSStefano Zampini       *diag = 1.0 / (*diag);
40589de2952eSStefano Zampini       break;
40599de2952eSStefano Zampini     case 2:
40609de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
40619de2952eSStefano Zampini       break;
40629de2952eSStefano Zampini     case 3:
40639de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
40649de2952eSStefano Zampini       break;
40659de2952eSStefano Zampini     case 4:
40669de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
40679de2952eSStefano Zampini       break;
40689de2952eSStefano Zampini     case 5:
40699de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
40709de2952eSStefano Zampini       break;
40719de2952eSStefano Zampini     case 6:
40729de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
40739de2952eSStefano Zampini       break;
40749de2952eSStefano Zampini     case 7:
40759de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
40769de2952eSStefano Zampini       break;
40779de2952eSStefano Zampini     default:
40789de2952eSStefano Zampini       PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
40799de2952eSStefano Zampini     }
40809de2952eSStefano Zampini     ncnt += bs;
40819de2952eSStefano Zampini     flops += 2.0 * PetscPowInt(bs, 3) / 3.0;
40829de2952eSStefano Zampini     diag += bs * bs;
40839de2952eSStefano Zampini     indj += bs * bs;
40849de2952eSStefano Zampini     indi += bs;
40859de2952eSStefano Zampini   }
40869de2952eSStefano Zampini   PetscCall(PetscLogFlops(flops));
40879de2952eSStefano Zampini   PetscCall(PetscFree2(v_work, v_pivots));
40889de2952eSStefano Zampini   PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), n, n, ii, jj, aa, B));
40899de2952eSStefano Zampini   {
40909de2952eSStefano Zampini     Mat_SeqAIJ *aij = (Mat_SeqAIJ *)(*B)->data;
40919de2952eSStefano Zampini     aij->free_a     = PETSC_TRUE;
40929de2952eSStefano Zampini     aij->free_ij    = PETSC_TRUE;
40939de2952eSStefano Zampini   }
40949de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
40959de2952eSStefano Zampini }
40969de2952eSStefano Zampini 
40979de2952eSStefano Zampini static PetscErrorCode MatDenseScatter(Mat A, PetscSF sf, Mat B)
40989de2952eSStefano Zampini {
40999de2952eSStefano Zampini   const PetscScalar *rarr;
41009de2952eSStefano Zampini   PetscScalar       *larr;
41019de2952eSStefano Zampini   PetscSF            vsf;
41029de2952eSStefano Zampini   PetscInt           n, rld, lld;
41039de2952eSStefano Zampini 
41049de2952eSStefano Zampini   PetscFunctionBegin;
41059de2952eSStefano Zampini   PetscCall(MatGetSize(A, NULL, &n));
41069de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(A, &rld));
41079de2952eSStefano Zampini   PetscCall(MatDenseGetLDA(B, &lld));
41089de2952eSStefano Zampini   PetscCall(MatDenseGetArrayRead(A, &rarr));
41099de2952eSStefano Zampini   PetscCall(MatDenseGetArrayWrite(B, &larr));
41109de2952eSStefano Zampini   PetscCall(PetscSFCreateStridedSF(sf, n, rld, lld, &vsf));
41119de2952eSStefano Zampini   PetscCall(PetscSFBcastBegin(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
41129de2952eSStefano Zampini   PetscCall(PetscSFBcastEnd(vsf, MPIU_SCALAR, rarr, larr, MPI_REPLACE));
41139de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayRead(A, &rarr));
41149de2952eSStefano Zampini   PetscCall(MatDenseRestoreArrayWrite(B, &larr));
41159de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&vsf));
41169de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
41179de2952eSStefano Zampini }
41189de2952eSStefano Zampini 
41199de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCorrection(PC pc, Mat *coarse_submat)
41209de2952eSStefano Zampini {
412188ebb749SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
412288ebb749SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
41239de2952eSStefano Zampini   PCBDDCGraph     graph      = pcbddc->mat_graph;
4124d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
412525084f0cSStefano Zampini   /* submatrices of local problem */
41269de2952eSStefano Zampini   Mat A_RV = NULL, A_VR, A_VV, local_auxmat2_R = NULL;
412706656605SStefano Zampini   /* submatrices of local coarse problem */
41289de2952eSStefano Zampini   Mat S_CV = NULL, S_VC = NULL, S_CC = NULL;
412925084f0cSStefano Zampini   /* working matrices */
413006656605SStefano Zampini   Mat C_CR;
41319de2952eSStefano Zampini 
413225084f0cSStefano Zampini   /* additional working stuff */
413306656605SStefano Zampini   PC              pc_R;
41349de2952eSStefano Zampini   IS              is_R, is_V, is_C;
41359de2952eSStefano Zampini   const PetscInt *idx_V, *idx_C;
4136c58f9fdbSStefano Zampini   Mat             F, Brhs = NULL;
41375cbda25cSStefano Zampini   Vec             dummy_vec;
41387ebab0bbSStefano Zampini   PetscBool       isLU, isCHOL, need_benign_correction, sparserhs;
413906656605SStefano Zampini   PetscInt       *idx_V_B;
41409de2952eSStefano Zampini   PetscInt        lda_rhs, n_vertices, n_constraints, *p0_lidx_I;
41419de2952eSStefano Zampini   PetscInt        n_eff_vertices, n_eff_constraints;
414206656605SStefano Zampini   PetscInt        i, n_R, n_D, n_B;
414306656605SStefano Zampini   PetscScalar     one = 1.0, m_one = -1.0;
414488ebb749SStefano Zampini 
41459de2952eSStefano Zampini   /* Multi-element support */
41469de2952eSStefano Zampini   PetscBool multi_element = graph->multi_element;
41479de2952eSStefano Zampini   PetscInt *V_to_eff_V = NULL, *C_to_eff_C = NULL;
41489de2952eSStefano Zampini   PetscInt *B_eff_V_J = NULL, *R_eff_V_J = NULL, *B_eff_C_J = NULL, *R_eff_C_J = NULL;
41499de2952eSStefano Zampini   IS        is_C_perm = NULL;
41509de2952eSStefano Zampini   PetscInt  n_C_bss = 0, *C_bss = NULL;
41519de2952eSStefano Zampini   Mat       coarse_phi_multi;
41529de2952eSStefano Zampini 
415388ebb749SStefano Zampini   PetscFunctionBegin;
41547827d75bSBarry 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");
41559566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
4156ffd830a3SStefano Zampini 
4157ffd830a3SStefano Zampini   /* Set Non-overlapping dimensions */
4158b371cd4fSStefano Zampini   n_vertices    = pcbddc->n_vertices;
41594f1b2e48SStefano Zampini   n_constraints = pcbddc->local_primal_size - pcbddc->benign_n - n_vertices;
4160b371cd4fSStefano Zampini   n_B           = pcis->n_B;
4161b371cd4fSStefano Zampini   n_D           = pcis->n - n_B;
416288ebb749SStefano Zampini   n_R           = pcis->n - n_vertices;
416388ebb749SStefano Zampini 
416488ebb749SStefano Zampini   /* vertices in boundary numbering */
41659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_vertices, &idx_V_B));
41669566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, n_vertices, pcbddc->local_primal_ref_node, &i, idx_V_B));
416763a3b9bcSJacob 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);
416888ebb749SStefano Zampini 
41699de2952eSStefano Zampini   /* these two cases still need to be optimized */
41709de2952eSStefano Zampini   if (pcbddc->benign_saddle_point || !pcbddc->symmetric_primal) multi_element = PETSC_FALSE;
41719de2952eSStefano Zampini 
417206656605SStefano Zampini   /* Subdomain contribution (Non-overlapping) to coarse matrix  */
41739de2952eSStefano Zampini   if (multi_element) {
41749de2952eSStefano Zampini     PetscCheck(!pcbddc->benign_n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
41759de2952eSStefano Zampini 
41769de2952eSStefano Zampini     PetscCall(MatCreate(PETSC_COMM_SELF, coarse_submat));
41779de2952eSStefano Zampini     PetscCall(MatSetSizes(*coarse_submat, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size, pcbddc->local_primal_size));
41789de2952eSStefano Zampini     PetscCall(MatSetType(*coarse_submat, MATSEQAIJ));
41799de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
41809de2952eSStefano Zampini     PetscCall(MatSetOption(*coarse_submat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
41819de2952eSStefano Zampini 
41829de2952eSStefano Zampini     /* group vertices and constraints by subdomain id */
41839de2952eSStefano Zampini     const PetscInt *vidxs = pcbddc->primal_indices_local_idxs;
41849de2952eSStefano Zampini     const PetscInt *cidxs = pcbddc->primal_indices_local_idxs + n_vertices;
41859de2952eSStefano Zampini     PetscInt       *count_eff, *V_eff_to_V, *C_eff_to_C, *nnz;
41869de2952eSStefano Zampini     PetscInt        n_el = PetscMax(graph->n_local_subs, 1);
41879de2952eSStefano Zampini 
41889de2952eSStefano Zampini     PetscCall(PetscCalloc1(2 * n_el, &count_eff));
41899de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices, &V_to_eff_V));
41909de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &C_to_eff_C));
41919de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
41929de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
41939de2952eSStefano Zampini 
41949de2952eSStefano Zampini       V_to_eff_V[i] = count_eff[s];
41959de2952eSStefano Zampini       count_eff[s] += 1;
41969de2952eSStefano Zampini     }
41979de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
41989de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub + 1;
41999de2952eSStefano Zampini 
42009de2952eSStefano Zampini       C_to_eff_C[i] = count_eff[s];
42019de2952eSStefano Zampini       count_eff[s] += 1;
42029de2952eSStefano Zampini     }
42039de2952eSStefano Zampini 
42049de2952eSStefano Zampini     /* preallocation */
42059de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_vertices + n_constraints, &nnz));
42069de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
42079de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[vidxs[i]].local_sub;
42089de2952eSStefano Zampini 
42099de2952eSStefano Zampini       nnz[i] = count_eff[s] + count_eff[s + 1];
42109de2952eSStefano Zampini     }
42119de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
42129de2952eSStefano Zampini       PetscInt s = 2 * graph->nodes[cidxs[i]].local_sub;
42139de2952eSStefano Zampini 
42149de2952eSStefano Zampini       nnz[i + n_vertices] = count_eff[s] + count_eff[s + 1];
42159de2952eSStefano Zampini     }
42169de2952eSStefano Zampini     PetscCall(MatSeqAIJSetPreallocation(*coarse_submat, 0, nnz));
42179de2952eSStefano Zampini     PetscCall(PetscFree(nnz));
42189de2952eSStefano Zampini 
42199de2952eSStefano Zampini     n_eff_vertices    = 0;
42209de2952eSStefano Zampini     n_eff_constraints = 0;
42219de2952eSStefano Zampini     for (PetscInt i = 0; i < n_el; i++) {
42229de2952eSStefano Zampini       n_eff_vertices       = PetscMax(n_eff_vertices, count_eff[2 * i]);
42239de2952eSStefano Zampini       n_eff_constraints    = PetscMax(n_eff_constraints, count_eff[2 * i + 1]);
42249de2952eSStefano Zampini       count_eff[2 * i]     = 0;
42259de2952eSStefano Zampini       count_eff[2 * i + 1] = 0;
42269de2952eSStefano Zampini     }
42279de2952eSStefano Zampini 
42289de2952eSStefano Zampini     const PetscInt *idx;
42299de2952eSStefano Zampini     PetscCall(PetscMalloc2(n_el * n_eff_vertices, &V_eff_to_V, n_el * n_eff_constraints, &C_eff_to_C));
42309de2952eSStefano Zampini 
42319de2952eSStefano Zampini     for (PetscInt i = 0; i < n_vertices; i++) {
42329de2952eSStefano Zampini       const PetscInt e = graph->nodes[vidxs[i]].local_sub;
42339de2952eSStefano Zampini       const PetscInt s = 2 * e;
42349de2952eSStefano Zampini 
42359de2952eSStefano Zampini       V_eff_to_V[e * n_eff_vertices + count_eff[s]] = i;
42369de2952eSStefano Zampini       count_eff[s] += 1;
42379de2952eSStefano Zampini     }
42389de2952eSStefano Zampini     for (PetscInt i = 0; i < n_constraints; i++) {
42399de2952eSStefano Zampini       const PetscInt e = graph->nodes[cidxs[i]].local_sub;
42409de2952eSStefano Zampini       const PetscInt s = 2 * e + 1;
42419de2952eSStefano Zampini 
42429de2952eSStefano Zampini       C_eff_to_C[e * n_eff_constraints + count_eff[s]] = i;
42439de2952eSStefano Zampini       count_eff[s] += 1;
42449de2952eSStefano Zampini     }
42459de2952eSStefano Zampini 
42469de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_vertices, &R_eff_V_J));
42479de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * n_eff_constraints, &R_eff_C_J));
42489de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_vertices, &B_eff_V_J));
42499de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_B * n_eff_constraints, &B_eff_C_J));
42509de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_vertices; i++) R_eff_V_J[i] = -1;
42519de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R * n_eff_constraints; i++) R_eff_C_J[i] = -1;
42529de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_vertices; i++) B_eff_V_J[i] = -1;
42539de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B * n_eff_constraints; i++) B_eff_C_J[i] = -1;
42549de2952eSStefano Zampini 
42559de2952eSStefano Zampini     PetscCall(ISGetIndices(pcbddc->is_R_local, &idx));
42569de2952eSStefano Zampini     for (PetscInt i = 0; i < n_R; i++) {
42579de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
42589de2952eSStefano Zampini       const PetscInt s = 2 * e;
42599de2952eSStefano Zampini       PetscInt       j;
42609de2952eSStefano Zampini 
42619de2952eSStefano Zampini       for (j = 0; j < count_eff[s]; j++) R_eff_V_J[i * n_eff_vertices + j] = V_eff_to_V[e * n_eff_vertices + j];
42629de2952eSStefano Zampini       for (j = 0; j < count_eff[s + 1]; j++) R_eff_C_J[i * n_eff_constraints + j] = C_eff_to_C[e * n_eff_constraints + j];
42639de2952eSStefano Zampini     }
42649de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idx));
42659de2952eSStefano Zampini     PetscCall(ISGetIndices(pcis->is_B_local, &idx));
42669de2952eSStefano Zampini     for (PetscInt i = 0; i < n_B; i++) {
42679de2952eSStefano Zampini       const PetscInt e = graph->nodes[idx[i]].local_sub;
42689de2952eSStefano Zampini       const PetscInt s = 2 * e;
42699de2952eSStefano Zampini       PetscInt       j;
42709de2952eSStefano Zampini 
42719de2952eSStefano Zampini       for (j = 0; j < count_eff[s]; j++) B_eff_V_J[i * n_eff_vertices + j] = V_eff_to_V[e * n_eff_vertices + j];
42729de2952eSStefano Zampini       for (j = 0; j < count_eff[s + 1]; j++) B_eff_C_J[i * n_eff_constraints + j] = C_eff_to_C[e * n_eff_constraints + j];
42739de2952eSStefano Zampini     }
42749de2952eSStefano Zampini     PetscCall(ISRestoreIndices(pcis->is_B_local, &idx));
42759de2952eSStefano Zampini 
42769de2952eSStefano Zampini     /* permutation and blocksizes for block invert of S_CC */
42779de2952eSStefano Zampini     PetscInt *idxp;
42789de2952eSStefano Zampini 
42799de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_constraints, &idxp));
42809de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_el, &C_bss));
42819de2952eSStefano Zampini     n_C_bss = 0;
42829de2952eSStefano Zampini     for (PetscInt e = 0, cnt = 0; e < n_el; e++) {
42839de2952eSStefano Zampini       const PetscInt nc = count_eff[2 * e + 1];
42849de2952eSStefano Zampini 
42859de2952eSStefano Zampini       if (nc) C_bss[n_C_bss++] = nc;
42869de2952eSStefano Zampini       for (PetscInt c = 0; c < nc; c++) { idxp[cnt + c] = C_eff_to_C[e * n_eff_constraints + c]; }
42879de2952eSStefano Zampini       cnt += nc;
42889de2952eSStefano Zampini     }
42899de2952eSStefano Zampini 
42909de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_constraints, idxp, PETSC_OWN_POINTER, &is_C_perm));
42919de2952eSStefano Zampini 
42929de2952eSStefano Zampini     PetscCall(PetscFree2(V_eff_to_V, C_eff_to_C));
42939de2952eSStefano Zampini     PetscCall(PetscFree(count_eff));
42949de2952eSStefano Zampini   } else {
42959de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcbddc->local_primal_size, pcbddc->local_primal_size, NULL, coarse_submat));
42969de2952eSStefano Zampini     n_eff_constraints = n_constraints;
42979de2952eSStefano Zampini     n_eff_vertices    = n_vertices;
42989de2952eSStefano Zampini   }
429906656605SStefano Zampini 
430006656605SStefano Zampini   /* determine if can use MatSolve routines instead of calling KSPSolve on ksp_R */
43019566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_R));
43029566063dSJacob Faibussowitsch   PetscCall(PCSetUp(pc_R));
43039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCLU, &isLU));
43049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc_R, PCCHOLESKY, &isCHOL));
4305ffd830a3SStefano Zampini   lda_rhs                = n_R;
4306a3df083aSStefano Zampini   need_benign_correction = PETSC_FALSE;
43077ebab0bbSStefano Zampini   if (isLU || isCHOL) {
43089566063dSJacob Faibussowitsch     PetscCall(PCFactorGetMatrix(pc_R, &F));
4309b334f244SStefano Zampini   } else if (sub_schurs && sub_schurs->reuse_solver) {
4310df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4311d62866d3SStefano Zampini     MatFactorType      type;
4312d62866d3SStefano Zampini 
4313df4d28bfSStefano Zampini     F = reuse_solver->F;
43149566063dSJacob Faibussowitsch     PetscCall(MatGetFactorType(F, &type));
4315d62866d3SStefano Zampini     if (type == MAT_FACTOR_CHOLESKY) isCHOL = PETSC_TRUE;
43167ebab0bbSStefano Zampini     if (type == MAT_FACTOR_LU) isLU = PETSC_TRUE;
43179566063dSJacob Faibussowitsch     PetscCall(MatGetSize(F, &lda_rhs, NULL));
431822db5ddcSStefano Zampini     need_benign_correction = (PetscBool)(!!reuse_solver->benign_n);
43197ebab0bbSStefano Zampini   } else F = NULL;
432006656605SStefano Zampini 
4321c58f9fdbSStefano Zampini   /* determine if we can use a sparse right-hand side */
4322c58f9fdbSStefano Zampini   sparserhs = PETSC_FALSE;
43239de2952eSStefano Zampini   if (F && !multi_element) {
4324ea799195SBarry Smith     MatSolverType solver;
4325c58f9fdbSStefano Zampini 
43269566063dSJacob Faibussowitsch     PetscCall(MatFactorGetSolverType(F, &solver));
43279566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(solver, MATSOLVERMUMPS, &sparserhs));
4328c58f9fdbSStefano Zampini   }
4329c58f9fdbSStefano Zampini 
43305cbda25cSStefano Zampini   /* create dummy vector to modify rhs and sol of MatMatSolve (work array will never be used) */
43315cbda25cSStefano Zampini   dummy_vec = NULL;
43325cbda25cSStefano Zampini   if (need_benign_correction && lda_rhs != n_R && F) {
43339566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcis->vec1_N), &dummy_vec));
43349566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(dummy_vec, lda_rhs, PETSC_DECIDE));
43359566063dSJacob Faibussowitsch     PetscCall(VecSetType(dummy_vec, ((PetscObject)pcis->vec1_N)->type_name));
43365cbda25cSStefano Zampini   }
43375cbda25cSStefano Zampini 
43389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat1));
43399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_auxmat2));
43407ebab0bbSStefano Zampini 
43419de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_R, 0, 1, &is_R));
43429de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_vertices, 0, 1, &is_V));
43439de2952eSStefano Zampini   PetscCall(ISCreateStride(PETSC_COMM_SELF, n_constraints, n_vertices, 1, &is_C));
43449de2952eSStefano Zampini   PetscCall(ISGetIndices(is_V, &idx_V));
43459de2952eSStefano Zampini   PetscCall(ISGetIndices(is_C, &idx_C));
43469de2952eSStefano Zampini 
434788ebb749SStefano Zampini   /* Precompute stuffs needed for preprocessing and application of BDDC*/
434888ebb749SStefano Zampini   if (n_constraints) {
43499de2952eSStefano Zampini     Mat C_B;
435006656605SStefano Zampini 
435125084f0cSStefano Zampini     /* Extract constraints on R nodes: C_{CR}  */
43529de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &C_CR));
43539de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_C, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
435488ebb749SStefano Zampini 
435580677318SStefano Zampini     /* Assemble         local_auxmat2_R =        (- A_{RR}^{-1} C^T_{CR}) needed by BDDC setup */
435680677318SStefano Zampini     /* Assemble pcbddc->local_auxmat2   = R_to_B (- A_{RR}^{-1} C^T_{CR}) needed by BDDC application */
4357c58f9fdbSStefano Zampini     if (!sparserhs) {
43589de2952eSStefano Zampini       PetscScalar *marr;
43599de2952eSStefano Zampini 
43609de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &Brhs));
43619de2952eSStefano Zampini       PetscCall(MatDenseGetArrayWrite(Brhs, &marr));
436288ebb749SStefano Zampini       for (i = 0; i < n_constraints; i++) {
436306656605SStefano Zampini         const PetscScalar *row_cmat_values;
436406656605SStefano Zampini         const PetscInt    *row_cmat_indices;
43659de2952eSStefano Zampini         PetscInt           size_of_constraint, j, col = C_to_eff_C ? C_to_eff_C[i] : i;
436688ebb749SStefano Zampini 
43679566063dSJacob Faibussowitsch         PetscCall(MatGetRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
43689de2952eSStefano Zampini         for (j = 0; j < size_of_constraint; j++) marr[row_cmat_indices[j] + col * lda_rhs] = -row_cmat_values[j];
43699566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(C_CR, i, &size_of_constraint, &row_cmat_indices, &row_cmat_values));
437006656605SStefano Zampini       }
43719de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayWrite(Brhs, &marr));
4372c58f9fdbSStefano Zampini     } else {
4373c58f9fdbSStefano Zampini       Mat tC_CR;
4374c58f9fdbSStefano Zampini 
43759566063dSJacob Faibussowitsch       PetscCall(MatScale(C_CR, -1.0));
4376c58f9fdbSStefano Zampini       if (lda_rhs != n_R) {
4377c58f9fdbSStefano Zampini         PetscScalar *aa;
4378c58f9fdbSStefano Zampini         PetscInt     r, *ii, *jj;
4379c58f9fdbSStefano Zampini         PetscBool    done;
4380c58f9fdbSStefano Zampini 
43819566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
438228b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
43839566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(C_CR, &aa));
43849566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_constraints, lda_rhs, ii, jj, aa, &tC_CR));
43859566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(C_CR, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
438628b400f6SJacob Faibussowitsch         PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4387c58f9fdbSStefano Zampini       } else {
43889566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)C_CR));
4389c58f9fdbSStefano Zampini         tC_CR = C_CR;
4390c58f9fdbSStefano Zampini       }
43919566063dSJacob Faibussowitsch       PetscCall(MatCreateTranspose(tC_CR, &Brhs));
43929566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tC_CR));
4393c58f9fdbSStefano Zampini     }
43949de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_constraints, NULL, &local_auxmat2_R));
439506656605SStefano Zampini     if (F) {
4396a3df083aSStefano Zampini       if (need_benign_correction) {
4397df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4398a3df083aSStefano Zampini 
439972b8c272SStefano Zampini         /* rhs is already zero on interior dofs, no need to change the rhs */
44009566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(reuse_solver->benign_save_vals, pcbddc->benign_n));
4401a3df083aSStefano Zampini       }
44029566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(F, Brhs, local_auxmat2_R));
4403a3df083aSStefano Zampini       if (need_benign_correction) {
4404a3df083aSStefano Zampini         PetscScalar       *marr;
4405df4d28bfSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4406a3df083aSStefano Zampini 
44079de2952eSStefano Zampini         /* XXX multi_element? */
44089566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
44095cbda25cSStefano Zampini         if (lda_rhs != n_R) {
44109de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
44119566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
44129566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
44139566063dSJacob Faibussowitsch             PetscCall(VecResetArray(dummy_vec));
44145cbda25cSStefano Zampini           }
44155cbda25cSStefano Zampini         } else {
44169de2952eSStefano Zampini           for (i = 0; i < n_eff_constraints; i++) {
44179566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
44189566063dSJacob Faibussowitsch             PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
44199566063dSJacob Faibussowitsch             PetscCall(VecResetArray(pcbddc->vec1_R));
4420a3df083aSStefano Zampini           }
44215cbda25cSStefano Zampini         }
44229566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
4423a3df083aSStefano Zampini       }
442406656605SStefano Zampini     } else {
44259de2952eSStefano Zampini       const PetscScalar *barr;
442680677318SStefano Zampini       PetscScalar       *marr;
442780677318SStefano Zampini 
44289de2952eSStefano Zampini       PetscCall(MatDenseGetArrayRead(Brhs, &barr));
44299566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(local_auxmat2_R, &marr));
44309de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
44319de2952eSStefano Zampini         PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
44329566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
44339566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
44349566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
44359566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
44369566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
443706656605SStefano Zampini       }
44389de2952eSStefano Zampini       PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
44399566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(local_auxmat2_R, &marr));
444006656605SStefano Zampini     }
44411baa6e33SBarry Smith     if (sparserhs) PetscCall(MatScale(C_CR, -1.0));
44429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Brhs));
44439de2952eSStefano Zampini     /* Assemble explicitly S_CC = ( C_{CR} A_{RR}^{-1} C^T_{CR})^{-1}  */
444480677318SStefano Zampini     if (!pcbddc->switch_static) {
44459de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_constraints, NULL, &pcbddc->local_auxmat2));
44469de2952eSStefano Zampini       for (i = 0; i < n_eff_constraints; i++) {
4447ab2d12f3SJunchao Zhang         Vec r, b;
44489566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVecRead(local_auxmat2_R, i, &r));
44499566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->local_auxmat2, i, &b));
44509566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
44519566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_B, r, b, INSERT_VALUES, SCATTER_FORWARD));
44529566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->local_auxmat2, i, &b));
44539566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVecRead(local_auxmat2_R, i, &r));
445480677318SStefano Zampini       }
44559de2952eSStefano Zampini       if (multi_element) {
44569de2952eSStefano Zampini         Mat T;
4457ffd830a3SStefano Zampini 
44589de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
44599de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
44609de2952eSStefano Zampini         local_auxmat2_R = T;
44619de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(pcbddc->local_auxmat2, n_constraints, B_eff_C_J, &T));
44629de2952eSStefano Zampini         PetscCall(MatDestroy(&pcbddc->local_auxmat2));
44639de2952eSStefano Zampini         pcbddc->local_auxmat2 = T;
44649de2952eSStefano Zampini       }
44659de2952eSStefano Zampini       PetscCall(MatMatMult(C_B, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_CC));
44669de2952eSStefano Zampini     } else {
44679de2952eSStefano Zampini       if (multi_element) {
44689de2952eSStefano Zampini         Mat T;
44699de2952eSStefano Zampini 
44709de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(local_auxmat2_R, n_constraints, R_eff_C_J, &T));
44719de2952eSStefano Zampini         PetscCall(MatDestroy(&local_auxmat2_R));
44729de2952eSStefano Zampini         local_auxmat2_R = T;
44739de2952eSStefano Zampini       }
44749de2952eSStefano Zampini       if (lda_rhs != n_R) {
44759de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(local_auxmat2_R, is_R, NULL, MAT_INITIAL_MATRIX, &pcbddc->local_auxmat2));
4476ffd830a3SStefano Zampini       } else {
44779566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)local_auxmat2_R));
447880677318SStefano Zampini         pcbddc->local_auxmat2 = local_auxmat2_R;
4479ffd830a3SStefano Zampini       }
44809de2952eSStefano Zampini       PetscCall(MatMatMult(C_CR, pcbddc->local_auxmat2, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_CC));
448180677318SStefano Zampini     }
44829de2952eSStefano Zampini     PetscCall(MatScale(S_CC, m_one));
44839de2952eSStefano Zampini     if (multi_element) {
44849de2952eSStefano Zampini       Mat T, T2;
44859de2952eSStefano Zampini       IS  isp, ispi;
44869de2952eSStefano Zampini 
44879de2952eSStefano Zampini       isp = is_C_perm;
44889de2952eSStefano Zampini 
44899de2952eSStefano Zampini       PetscCall(ISInvertPermutation(isp, PETSC_DECIDE, &ispi));
44909de2952eSStefano Zampini       PetscCall(MatPermute(S_CC, isp, isp, &T));
44919de2952eSStefano Zampini       PetscCall(MatSeqAIJInvertVariableBlockDiagonalMat(T, n_C_bss, C_bss, &T2));
44929de2952eSStefano Zampini       PetscCall(MatDestroy(&T));
44939de2952eSStefano Zampini       PetscCall(MatDestroy(&S_CC));
44949de2952eSStefano Zampini       PetscCall(MatPermute(T2, ispi, ispi, &S_CC));
44959de2952eSStefano Zampini       PetscCall(MatDestroy(&T2));
44969de2952eSStefano Zampini       PetscCall(ISDestroy(&ispi));
449780677318SStefano Zampini     } else {
44989de2952eSStefano Zampini       if (isCHOL) {
44999de2952eSStefano Zampini         PetscCall(MatCholeskyFactor(S_CC, NULL, NULL));
45009de2952eSStefano Zampini       } else {
45019de2952eSStefano Zampini         PetscCall(MatLUFactor(S_CC, NULL, NULL, NULL));
450280677318SStefano Zampini       }
45039de2952eSStefano Zampini       PetscCall(MatSeqDenseInvertFactors_Private(S_CC));
45049de2952eSStefano Zampini     }
450580677318SStefano Zampini     /* Assemble local_auxmat1 = S_CC*C_{CB} needed by BDDC application in KSP and in preproc */
45069de2952eSStefano Zampini     PetscCall(MatMatMult(S_CC, C_B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->local_auxmat1));
45079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
45089de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, S_CC, n_constraints, idx_C, n_constraints, idx_C, INSERT_VALUES));
4509f4ddd8eeSStefano Zampini   }
4510fc227af8SStefano Zampini 
4511fc227af8SStefano Zampini   /* Get submatrices from subdomain matrix */
451288ebb749SStefano Zampini   if (n_vertices) {
45137ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
45147ebab0bbSStefano Zampini     PetscBool oldpin;
45157ebab0bbSStefano Zampini #endif
451606656605SStefano Zampini     IS is_aux;
45173a50541eSStefano Zampini 
4518b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) { /* is_R_local is not sorted, ISComplement doesn't like it */
45196816873aSStefano Zampini       IS tis;
45206816873aSStefano Zampini 
45219566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(pcbddc->is_R_local, &tis));
45229566063dSJacob Faibussowitsch       PetscCall(ISSort(tis));
45239566063dSJacob Faibussowitsch       PetscCall(ISComplement(tis, 0, pcis->n, &is_aux));
45249566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
45256816873aSStefano Zampini     } else {
45269566063dSJacob Faibussowitsch       PetscCall(ISComplement(pcbddc->is_R_local, 0, pcis->n, &is_aux));
45276816873aSStefano Zampini     }
45287ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4529b470e4b4SRichard Tran Mills     oldpin = pcbddc->local_mat->boundtocpu;
45307ebab0bbSStefano Zampini #endif
45319566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, PETSC_TRUE));
45329566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, is_aux, MAT_INITIAL_MATRIX, &A_RV));
45339566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_VR));
45349de2952eSStefano Zampini     /* TODO REMOVE: MatMatMult(A_VR,A_RRmA_RV) below may raise an error */
45359566063dSJacob Faibussowitsch     PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
45369566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, is_aux, is_aux, MAT_INITIAL_MATRIX, &A_VV));
45377ebab0bbSStefano Zampini #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
45389566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pcbddc->local_mat, oldpin));
45397ebab0bbSStefano Zampini #endif
45409566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux));
454188ebb749SStefano Zampini   }
45429de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C_perm));
45439de2952eSStefano Zampini   PetscCall(PetscFree(C_bss));
454488ebb749SStefano Zampini 
45454f1b2e48SStefano Zampini   p0_lidx_I = NULL;
45464f1b2e48SStefano Zampini   if (pcbddc->benign_n && (pcbddc->switch_static || pcbddc->dbg_flag)) {
4547d12edf2fSStefano Zampini     const PetscInt *idxs;
4548d12edf2fSStefano Zampini 
45499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
45509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->benign_n, &p0_lidx_I));
455148a46eb9SPierre 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]));
45529566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
4553d12edf2fSStefano Zampini   }
4554d16cbb6bSStefano Zampini 
45559de2952eSStefano Zampini   /* We are now ready to evaluate coarse basis functions and subdomain contribution to coarse problem */
45569de2952eSStefano Zampini 
45579de2952eSStefano Zampini   /* Matrices of coarse basis functions (local) */
45589de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_B));
45599de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_B));
45609de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_phi_D));
45619de2952eSStefano Zampini   PetscCall(MatDestroy(&pcbddc->coarse_psi_D));
45629de2952eSStefano Zampini   if (!multi_element) {
45639de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_B));
45649de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_phi_D));
45659de2952eSStefano Zampini     coarse_phi_multi = NULL;
45669de2952eSStefano Zampini   } else { /* Create temporary NEST matrix to hold coarse basis functions blocks */
45679de2952eSStefano Zampini     IS is_rows[2] = {pcbddc->is_R_local, NULL};
45689de2952eSStefano Zampini     IS is_cols[2] = {is_V, is_C};
45699de2952eSStefano Zampini 
45709de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n_vertices, pcbddc->local_primal_ref_node, PETSC_USE_POINTER, &is_rows[1]));
45719de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, 2, is_rows, 2, is_cols, NULL, &coarse_phi_multi));
45729de2952eSStefano Zampini     PetscCall(ISDestroy(&is_rows[1]));
45739de2952eSStefano Zampini   }
45749de2952eSStefano Zampini 
457506656605SStefano Zampini   /* vertices */
457606656605SStefano Zampini   if (n_vertices) {
4577c58f9fdbSStefano Zampini     PetscBool restoreavr = PETSC_FALSE;
45789de2952eSStefano Zampini     Mat       A_RRmA_RV  = NULL;
457916f15bc4SStefano Zampini 
45809de2952eSStefano Zampini     PetscCall(MatSetValuesSubMat(*coarse_submat, A_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
45819de2952eSStefano Zampini     PetscCall(MatDestroy(&A_VV));
458204708bb6SStefano Zampini 
458316f15bc4SStefano Zampini     if (n_R) {
45849de2952eSStefano Zampini       Mat A_RV_bcorr = NULL, S_VV;
458506656605SStefano Zampini 
45869566063dSJacob Faibussowitsch       PetscCall(MatScale(A_RV, m_one));
458714393ed6SStefano Zampini       if (need_benign_correction) {
458814393ed6SStefano Zampini         ISLocalToGlobalMapping RtoN;
458914393ed6SStefano Zampini         IS                     is_p0;
459014393ed6SStefano Zampini         PetscInt              *idxs_p0, n;
459114393ed6SStefano Zampini 
45929566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->benign_n, &idxs_p0));
45939566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(pcbddc->is_R_local, &RtoN));
45949566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(RtoN, IS_GTOLM_DROP, pcbddc->benign_n, pcbddc->benign_p0_lidx, &n, idxs_p0));
459563a3b9bcSJacob 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);
45969566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&RtoN));
45979566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idxs_p0, PETSC_OWN_POINTER, &is_p0));
45989566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(A_RV, is_p0, NULL, MAT_INITIAL_MATRIX, &A_RV_bcorr));
45999566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is_p0));
460014393ed6SStefano Zampini       }
460114393ed6SStefano Zampini 
46029de2952eSStefano Zampini       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &A_RRmA_RV));
4603c58f9fdbSStefano Zampini       if (!sparserhs || need_benign_correction) {
46049de2952eSStefano Zampini         if (lda_rhs == n_R && !multi_element) {
46059566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATDENSE, MAT_INPLACE_MATRIX, &A_RV));
4606ffd830a3SStefano Zampini         } else {
46079de2952eSStefano Zampini           Mat             T;
4608ca92afb2SStefano Zampini           PetscScalar    *av, *array;
4609ca92afb2SStefano Zampini           const PetscInt *xadj, *adjncy;
4610ca92afb2SStefano Zampini           PetscInt        n;
4611ca92afb2SStefano Zampini           PetscBool       flg_row;
4612ffd830a3SStefano Zampini 
46139de2952eSStefano Zampini           PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, lda_rhs, n_eff_vertices, NULL, &T));
46149de2952eSStefano Zampini           PetscCall(MatDenseGetArrayWrite(T, &array));
46159566063dSJacob Faibussowitsch           PetscCall(MatConvert(A_RV, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_RV));
46169566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
46179566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RV, &av));
4618ca92afb2SStefano Zampini           for (i = 0; i < n; i++) {
4619ca92afb2SStefano Zampini             PetscInt j;
46209de2952eSStefano Zampini             for (j = xadj[i]; j < xadj[i + 1]; j++) array[lda_rhs * (V_to_eff_V ? V_to_eff_V[adjncy[j]] : adjncy[j]) + i] = av[j];
4621ffd830a3SStefano Zampini           }
46229566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RV, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
46239de2952eSStefano Zampini           PetscCall(MatDenseRestoreArrayWrite(T, &array));
46249566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RV));
46259de2952eSStefano Zampini           A_RV = T;
4626ffd830a3SStefano Zampini         }
4627a3df083aSStefano Zampini         if (need_benign_correction) {
4628df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4629a3df083aSStefano Zampini           PetscScalar       *marr;
4630a3df083aSStefano Zampini 
46319de2952eSStefano Zampini           /* XXX multi_element */
46329566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RV, &marr));
463314393ed6SStefano Zampini           /* need \Phi^T A_RV = (I+L)A_RV, L given by
463414393ed6SStefano Zampini 
463514393ed6SStefano Zampini                  | 0 0  0 | (V)
463614393ed6SStefano Zampini              L = | 0 0 -1 | (P-p0)
463714393ed6SStefano Zampini                  | 0 0 -1 | (p0)
463814393ed6SStefano Zampini 
463914393ed6SStefano Zampini           */
4640df4d28bfSStefano Zampini           for (i = 0; i < reuse_solver->benign_n; i++) {
464114393ed6SStefano Zampini             const PetscScalar *vals;
464214393ed6SStefano Zampini             const PetscInt    *idxs, *idxs_zero;
464314393ed6SStefano Zampini             PetscInt           n, j, nz;
464414393ed6SStefano Zampini 
46459566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
46469566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
46479566063dSJacob Faibussowitsch             PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
464814393ed6SStefano Zampini             for (j = 0; j < n; j++) {
464914393ed6SStefano Zampini               PetscScalar val = vals[j];
465014393ed6SStefano Zampini               PetscInt    k, col = idxs[j];
465114393ed6SStefano Zampini               for (k = 0; k < nz; k++) marr[idxs_zero[k] + lda_rhs * col] -= val;
465214393ed6SStefano Zampini             }
46539566063dSJacob Faibussowitsch             PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
46549566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
465514393ed6SStefano Zampini           }
46569566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RV, &marr));
465772b8c272SStefano Zampini         }
46589566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RV));
4659c58f9fdbSStefano Zampini         Brhs = A_RV;
4660c58f9fdbSStefano Zampini       } else {
4661c58f9fdbSStefano Zampini         Mat tA_RVT, A_RVT;
4662c58f9fdbSStefano Zampini 
4663c58f9fdbSStefano Zampini         if (!pcbddc->symmetric_primal) {
4664fb6280fbSStefano Zampini           /* A_RV already scaled by -1 */
46659566063dSJacob Faibussowitsch           PetscCall(MatTranspose(A_RV, MAT_INITIAL_MATRIX, &A_RVT));
4666c58f9fdbSStefano Zampini         } else {
4667c58f9fdbSStefano Zampini           restoreavr = PETSC_TRUE;
46689566063dSJacob Faibussowitsch           PetscCall(MatScale(A_VR, -1.0));
46699566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_VR));
4670c58f9fdbSStefano Zampini           A_RVT = A_VR;
4671c58f9fdbSStefano Zampini         }
4672c58f9fdbSStefano Zampini         if (lda_rhs != n_R) {
4673c58f9fdbSStefano Zampini           PetscScalar *aa;
4674c58f9fdbSStefano Zampini           PetscInt     r, *ii, *jj;
4675c58f9fdbSStefano Zampini           PetscBool    done;
4676c58f9fdbSStefano Zampini 
46779566063dSJacob Faibussowitsch           PetscCall(MatGetRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
467828b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "GetRowIJ failed");
46799566063dSJacob Faibussowitsch           PetscCall(MatSeqAIJGetArray(A_RVT, &aa));
46809566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, n_vertices, lda_rhs, ii, jj, aa, &tA_RVT));
46819566063dSJacob Faibussowitsch           PetscCall(MatRestoreRowIJ(A_RVT, 0, PETSC_FALSE, PETSC_FALSE, &r, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
468228b400f6SJacob Faibussowitsch           PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_PLIB, "RestoreRowIJ failed");
4683c58f9fdbSStefano Zampini         } else {
46849566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)A_RVT));
4685c58f9fdbSStefano Zampini           tA_RVT = A_RVT;
4686c58f9fdbSStefano Zampini         }
46879566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(tA_RVT, &Brhs));
46889566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tA_RVT));
46899566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RVT));
4690c58f9fdbSStefano Zampini       }
469172b8c272SStefano Zampini       if (F) {
469214393ed6SStefano Zampini         /* need to correct the rhs */
469372b8c272SStefano Zampini         if (need_benign_correction) {
469472b8c272SStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
469572b8c272SStefano Zampini           PetscScalar       *marr;
469672b8c272SStefano Zampini 
46979566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(Brhs, &marr));
46985cbda25cSStefano Zampini           if (lda_rhs != n_R) {
46999de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47009566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
47019566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_FALSE, PETSC_TRUE));
47029566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
47035cbda25cSStefano Zampini             }
47045cbda25cSStefano Zampini           } else {
47059de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47069566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
47079566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_FALSE, PETSC_TRUE));
47089566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4709a3df083aSStefano Zampini             }
47105cbda25cSStefano Zampini           }
47119566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(Brhs, &marr));
4712a3df083aSStefano Zampini         }
47139566063dSJacob Faibussowitsch         PetscCall(MatMatSolve(F, Brhs, A_RRmA_RV));
47141baa6e33SBarry Smith         if (restoreavr) PetscCall(MatScale(A_VR, -1.0));
471514393ed6SStefano Zampini         /* need to correct the solution */
4716a3df083aSStefano Zampini         if (need_benign_correction) {
4717df4d28bfSStefano Zampini           PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
4718a3df083aSStefano Zampini           PetscScalar       *marr;
4719a3df083aSStefano Zampini 
47209566063dSJacob Faibussowitsch           PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
47215cbda25cSStefano Zampini           if (lda_rhs != n_R) {
47229de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47239566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(dummy_vec, marr + i * lda_rhs));
47249566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, dummy_vec, NULL, PETSC_TRUE, PETSC_TRUE));
47259566063dSJacob Faibussowitsch               PetscCall(VecResetArray(dummy_vec));
47265cbda25cSStefano Zampini             }
47275cbda25cSStefano Zampini           } else {
47289de2952eSStefano Zampini             for (i = 0; i < n_eff_vertices; i++) {
47299566063dSJacob Faibussowitsch               PetscCall(VecPlaceArray(pcbddc->vec1_R, marr + i * lda_rhs));
47309566063dSJacob Faibussowitsch               PetscCall(PCBDDCReuseSolversBenignAdapt(reuse_solver, pcbddc->vec1_R, NULL, PETSC_TRUE, PETSC_TRUE));
47319566063dSJacob Faibussowitsch               PetscCall(VecResetArray(pcbddc->vec1_R));
4732a3df083aSStefano Zampini             }
47335cbda25cSStefano Zampini           }
47349566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
4735a3df083aSStefano Zampini         }
473606656605SStefano Zampini       } else {
47379de2952eSStefano Zampini         const PetscScalar *barr;
47389de2952eSStefano Zampini         PetscScalar       *marr;
47399de2952eSStefano Zampini 
47409de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(Brhs, &barr));
47419de2952eSStefano Zampini         PetscCall(MatDenseGetArray(A_RRmA_RV, &marr));
47429de2952eSStefano Zampini         for (i = 0; i < n_eff_vertices; i++) {
47439de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec1_R, barr + i * lda_rhs));
47449de2952eSStefano Zampini           PetscCall(VecPlaceArray(pcbddc->vec2_R, marr + i * lda_rhs));
47459566063dSJacob Faibussowitsch           PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
47469566063dSJacob Faibussowitsch           PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
47479566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec1_R));
47489566063dSJacob Faibussowitsch           PetscCall(VecResetArray(pcbddc->vec2_R));
474906656605SStefano Zampini         }
47509de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(Brhs, &barr));
47519de2952eSStefano Zampini         PetscCall(MatDenseRestoreArray(A_RRmA_RV, &marr));
475206656605SStefano Zampini       }
47539566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_RV));
47549566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Brhs));
4755ffd830a3SStefano Zampini       /* S_VV and S_CV */
475606656605SStefano Zampini       if (n_constraints) {
475706656605SStefano Zampini         Mat B;
475880677318SStefano Zampini 
47599de2952eSStefano Zampini         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, n_eff_vertices, NULL, &B));
47609de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, B));
47619de2952eSStefano Zampini 
47629de2952eSStefano Zampini         /* S_CV = pcbddc->local_auxmat1 * B */
47639de2952eSStefano Zampini         if (multi_element) {
47649de2952eSStefano Zampini           Mat T;
47659de2952eSStefano Zampini 
47669de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(B, n_vertices, B_eff_V_J, &T));
47679de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
47689de2952eSStefano Zampini           B = T;
476980677318SStefano Zampini         }
47709de2952eSStefano Zampini         PetscCall(MatProductCreate(pcbddc->local_auxmat1, B, NULL, &S_CV));
47719566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(S_CV, MATPRODUCT_AB));
47729566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(S_CV));
47739566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(S_CV));
47749566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(S_CV));
47759566063dSJacob Faibussowitsch         PetscCall(MatProductClear(S_CV));
47769566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
47779de2952eSStefano Zampini 
47789de2952eSStefano Zampini         /* B = local_auxmat2_R * S_CV */
47799de2952eSStefano Zampini         PetscCall(MatProductCreate(local_auxmat2_R, S_CV, NULL, &B));
47809566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(B, MATPRODUCT_AB));
47819566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(B));
47829566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(B));
47839566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(B));
47844222ddf1SHong Zhang 
47859566063dSJacob Faibussowitsch         PetscCall(MatScale(S_CV, m_one));
47869de2952eSStefano Zampini         PetscCall(MatSetValuesSubMat(*coarse_submat, S_CV, n_constraints, idx_C, n_vertices, idx_V, INSERT_VALUES));
478714393ed6SStefano Zampini 
47889de2952eSStefano Zampini         if (multi_element) {
47899de2952eSStefano Zampini           Mat T;
47909de2952eSStefano Zampini 
47919de2952eSStefano Zampini           PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
47929de2952eSStefano Zampini           PetscCall(MatDestroy(&A_RRmA_RV));
47939de2952eSStefano Zampini           A_RRmA_RV = T;
47949de2952eSStefano Zampini         }
47959de2952eSStefano Zampini         PetscCall(MatAXPY(A_RRmA_RV, 1.0, B, UNKNOWN_NONZERO_PATTERN)); /* XXX ? */
47969de2952eSStefano Zampini         PetscCall(MatDestroy(&B));
47979de2952eSStefano Zampini       } else if (multi_element) {
47989de2952eSStefano Zampini         Mat T;
47999de2952eSStefano Zampini 
48009de2952eSStefano Zampini         PetscCall(MatCreateSeqAIJFromDenseExpand(A_RRmA_RV, n_vertices, R_eff_V_J, &T));
48019de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
48029de2952eSStefano Zampini         A_RRmA_RV = T;
48039de2952eSStefano Zampini       }
48049de2952eSStefano Zampini 
48059de2952eSStefano Zampini       if (lda_rhs != n_R) {
48069de2952eSStefano Zampini         Mat T;
48079de2952eSStefano Zampini 
48089de2952eSStefano Zampini         PetscCall(MatCreateSubMatrix(A_RRmA_RV, is_R, NULL, MAT_INITIAL_MATRIX, &T));
48099de2952eSStefano Zampini         PetscCall(MatDestroy(&A_RRmA_RV));
48109de2952eSStefano Zampini         A_RRmA_RV = T;
48119de2952eSStefano Zampini       }
48129de2952eSStefano Zampini 
48139de2952eSStefano Zampini       /* need A_VR * \Phi * A_RRmA_RV = A_VR * (I+L)^T * A_RRmA_RV, L given as before */
48149de2952eSStefano Zampini       if (need_benign_correction) { /* XXX SPARSE */
48159de2952eSStefano Zampini         PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
48169de2952eSStefano Zampini         PetscScalar       *sums;
48179de2952eSStefano Zampini         const PetscScalar *marr;
48189de2952eSStefano Zampini 
48199de2952eSStefano Zampini         PetscCall(MatDenseGetArrayRead(A_RRmA_RV, &marr));
48209566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n_vertices, &sums));
4821df4d28bfSStefano Zampini         for (i = 0; i < reuse_solver->benign_n; i++) {
482214393ed6SStefano Zampini           const PetscScalar *vals;
482314393ed6SStefano Zampini           const PetscInt    *idxs, *idxs_zero;
482414393ed6SStefano Zampini           PetscInt           n, j, nz;
482514393ed6SStefano Zampini 
48269566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(reuse_solver->benign_zerodiag_subs[i], &nz));
48279566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
482814393ed6SStefano Zampini           for (j = 0; j < n_vertices; j++) {
482914393ed6SStefano Zampini             sums[j] = 0.;
48309de2952eSStefano Zampini             for (PetscInt k = 0; k < nz; k++) sums[j] += marr[idxs_zero[k] + j * n_R];
483114393ed6SStefano Zampini           }
48329566063dSJacob Faibussowitsch           PetscCall(MatGetRow(A_RV_bcorr, i, &n, &idxs, &vals));
483314393ed6SStefano Zampini           for (j = 0; j < n; j++) {
483414393ed6SStefano Zampini             PetscScalar val = vals[j];
48359de2952eSStefano Zampini             for (PetscInt k = 0; k < n_vertices; k++) PetscCall(MatSetValue(*coarse_submat, idx_V[idxs[j]], idx_V[k], val * sums[k], ADD_VALUES));
483614393ed6SStefano Zampini           }
48379566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(A_RV_bcorr, i, &n, &idxs, &vals));
48389566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(reuse_solver->benign_zerodiag_subs[i], &idxs_zero));
483914393ed6SStefano Zampini         }
48409566063dSJacob Faibussowitsch         PetscCall(PetscFree(sums));
48419566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RV_bcorr));
48429de2952eSStefano Zampini         PetscCall(MatDenseRestoreArrayRead(A_RRmA_RV, &marr));
484314393ed6SStefano Zampini       }
48449de2952eSStefano Zampini 
48459de2952eSStefano Zampini       PetscCall(MatMatMult(A_VR, A_RRmA_RV, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VV));
48469de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VV, n_vertices, idx_V, n_vertices, idx_V, ADD_VALUES));
48479de2952eSStefano Zampini       PetscCall(MatDestroy(&S_VV));
4848d16cbb6bSStefano Zampini     }
4849d16cbb6bSStefano Zampini 
485006656605SStefano Zampini     /* coarse basis functions */
48519de2952eSStefano Zampini     if (coarse_phi_multi) {
48529de2952eSStefano Zampini       Mat Vid;
485316f15bc4SStefano Zampini 
48549de2952eSStefano Zampini       PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, n_vertices, n_vertices, 1, NULL, &Vid));
48559de2952eSStefano Zampini       PetscCall(MatShift_Basic(Vid, 1.0));
48569de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 0, A_RRmA_RV));
48579de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 1, 0, Vid));
48589de2952eSStefano Zampini       PetscCall(MatDestroy(&Vid));
48599de2952eSStefano Zampini     } else {
48609de2952eSStefano Zampini       if (A_RRmA_RV) {
48619de2952eSStefano Zampini         PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_B, pcbddc->coarse_phi_B));
486206656605SStefano Zampini         if (pcbddc->switch_static || pcbddc->dbg_flag) {
48639de2952eSStefano Zampini           PetscCall(MatDenseScatter(A_RRmA_RV, pcbddc->R_to_D, pcbddc->coarse_phi_D));
48649de2952eSStefano Zampini           if (pcbddc->benign_n) {
48659de2952eSStefano Zampini             for (i = 0; i < n_vertices; i++) { PetscCall(MatSetValues(pcbddc->coarse_phi_D, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES)); }
4866ab2d12f3SJunchao Zhang           }
486706656605SStefano Zampini         }
486806656605SStefano Zampini       }
48699de2952eSStefano Zampini       for (i = 0; i < n_vertices; i++) PetscCall(MatSetValues(pcbddc->coarse_phi_B, 1, &idx_V_B[i], 1, &i, &one, INSERT_VALUES));
48709de2952eSStefano Zampini       PetscCall(MatAssemblyBegin(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
48719de2952eSStefano Zampini       PetscCall(MatAssemblyEnd(pcbddc->coarse_phi_B, MAT_FINAL_ASSEMBLY));
48729de2952eSStefano Zampini     }
48739de2952eSStefano Zampini     PetscCall(MatDestroy(&A_RRmA_RV));
48749de2952eSStefano Zampini   }
48759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RV));
48769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dummy_vec));
487706656605SStefano Zampini 
487806656605SStefano Zampini   if (n_constraints) {
48799de2952eSStefano Zampini     Mat B, B2;
488006656605SStefano Zampini 
48819566063dSJacob Faibussowitsch     PetscCall(MatScale(S_CC, m_one));
48829de2952eSStefano Zampini     PetscCall(MatProductCreate(local_auxmat2_R, S_CC, NULL, &B));
48839566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(B, MATPRODUCT_AB));
48849566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions(B));
48859566063dSJacob Faibussowitsch     PetscCall(MatProductSymbolic(B));
48869566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(B));
4887a961b312SStefano Zampini 
488806656605SStefano Zampini     if (n_vertices) {
488903dfb2d7SStefano Zampini       if (isCHOL || need_benign_correction) { /* if we can solve the interior problem with cholesky, we should also be fine with transposing here */
48909de2952eSStefano Zampini         PetscCall(MatTranspose(S_CV, MAT_INITIAL_MATRIX, &S_VC));
489180677318SStefano Zampini       } else {
4892ffd830a3SStefano Zampini         if (lda_rhs != n_R) {
48939de2952eSStefano Zampini           Mat tB;
489406656605SStefano Zampini 
48959de2952eSStefano Zampini           PetscCall(MatCreateSubMatrix(B, is_R, NULL, MAT_INITIAL_MATRIX, &tB));
48969de2952eSStefano Zampini           PetscCall(MatDestroy(&B));
48979de2952eSStefano Zampini           B = tB;
48989de2952eSStefano Zampini         }
48999de2952eSStefano Zampini         PetscCall(MatMatMult(A_VR, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &S_VC));
49009de2952eSStefano Zampini       }
49019de2952eSStefano Zampini       PetscCall(MatSetValuesSubMat(*coarse_submat, S_VC, n_vertices, idx_V, n_constraints, idx_C, INSERT_VALUES));
49029de2952eSStefano Zampini     }
49039de2952eSStefano Zampini 
49049de2952eSStefano Zampini     /* coarse basis functions */
49059de2952eSStefano Zampini     if (coarse_phi_multi) {
49069de2952eSStefano Zampini       PetscCall(MatNestSetSubMat(coarse_phi_multi, 0, 1, B));
49079de2952eSStefano Zampini     } else {
49089de2952eSStefano Zampini       PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_B, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
49099de2952eSStefano Zampini       PetscCall(MatDenseScatter(B, pcbddc->R_to_B, B2));
49109de2952eSStefano Zampini       PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_B, &B2));
491106656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
49129de2952eSStefano Zampini         PetscCall(MatDenseGetSubMatrix(pcbddc->coarse_phi_D, PETSC_DECIDE, PETSC_DECIDE, n_vertices, n_vertices + n_constraints, &B2));
49139de2952eSStefano Zampini         PetscCall(MatDenseScatter(B, pcbddc->R_to_D, B2));
49149de2952eSStefano Zampini         if (pcbddc->benign_n) {
49159de2952eSStefano Zampini           for (i = 0; i < n_constraints; i++) { PetscCall(MatSetValues(B2, pcbddc->benign_n, p0_lidx_I, 1, &i, NULL, INSERT_VALUES)); }
491606656605SStefano Zampini         }
49179de2952eSStefano Zampini         PetscCall(MatDenseRestoreSubMatrix(pcbddc->coarse_phi_D, &B2));
491806656605SStefano Zampini       }
491906656605SStefano Zampini     }
49209de2952eSStefano Zampini     PetscCall(MatDestroy(&B));
49219de2952eSStefano Zampini   }
49229de2952eSStefano Zampini 
49239de2952eSStefano Zampini   /* assemble sparse coarse basis functions */
49249de2952eSStefano Zampini   if (coarse_phi_multi) {
49259de2952eSStefano Zampini     Mat T;
49269de2952eSStefano Zampini 
49279de2952eSStefano Zampini     PetscCall(MatConvert(coarse_phi_multi, MATSEQAIJ, MAT_INITIAL_MATRIX, &T));
49289de2952eSStefano Zampini     PetscCall(MatDestroy(&coarse_phi_multi));
49299de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(T, pcis->is_B_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_B));
49309de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) { PetscCall(MatCreateSubMatrix(T, pcis->is_I_local, NULL, MAT_INITIAL_MATRIX, &pcbddc->coarse_phi_D)); }
49319de2952eSStefano Zampini     PetscCall(MatDestroy(&T));
49329de2952eSStefano Zampini   }
49339de2952eSStefano Zampini   PetscCall(MatDestroy(&local_auxmat2_R));
49349566063dSJacob Faibussowitsch   PetscCall(PetscFree(p0_lidx_I));
493572b8c272SStefano Zampini 
493672b8c272SStefano Zampini   /* coarse matrix entries relative to B_0 */
493772b8c272SStefano Zampini   if (pcbddc->benign_n) {
493872b8c272SStefano Zampini     Mat                B0_B, B0_BPHI;
493972b8c272SStefano Zampini     IS                 is_dummy;
49401683a169SBarry Smith     const PetscScalar *data;
494172b8c272SStefano Zampini     PetscInt           j;
494272b8c272SStefano Zampini 
49439566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
49449566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
49459566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
49469566063dSJacob Faibussowitsch     PetscCall(MatMatMult(B0_B, pcbddc->coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
49479566063dSJacob Faibussowitsch     PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
49489566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(B0_BPHI, &data));
494972b8c272SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) {
495072b8c272SStefano Zampini       PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
495172b8c272SStefano Zampini       for (i = 0; i < pcbddc->local_primal_size; i++) {
49529de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, primal_idx, i, data[i * pcbddc->benign_n + j], INSERT_VALUES));
49539de2952eSStefano Zampini         PetscCall(MatSetValue(*coarse_submat, i, primal_idx, data[i * pcbddc->benign_n + j], INSERT_VALUES));
495472b8c272SStefano Zampini       }
495572b8c272SStefano Zampini     }
49569566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data));
49579566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_B));
49589566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B0_BPHI));
495972b8c272SStefano Zampini   }
4960019a44ceSStefano Zampini 
496106656605SStefano Zampini   /* compute other basis functions for non-symmetric problems */
49623301b35fSStefano Zampini   if (!pcbddc->symmetric_primal) {
4963ffd830a3SStefano Zampini     Mat          B_V = NULL, B_C = NULL;
49649de2952eSStefano Zampini     PetscScalar *marray, *work;
496506656605SStefano Zampini 
49669de2952eSStefano Zampini     /* TODO multi_element MatDenseScatter */
496706656605SStefano Zampini     if (n_constraints) {
4968ffd830a3SStefano Zampini       Mat S_CCT, C_CRT;
496906656605SStefano Zampini 
49709de2952eSStefano Zampini       PetscCall(MatScale(S_CC, m_one));
49719566063dSJacob Faibussowitsch       PetscCall(MatTranspose(C_CR, MAT_INITIAL_MATRIX, &C_CRT));
49729566063dSJacob Faibussowitsch       PetscCall(MatTranspose(S_CC, MAT_INITIAL_MATRIX, &S_CCT));
49739566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_CRT, S_CCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_C));
49749de2952eSStefano Zampini       PetscCall(MatConvert(B_C, MATDENSE, MAT_INPLACE_MATRIX, &B_C));
49759566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&S_CCT));
497606656605SStefano Zampini       if (n_vertices) {
4977ffd830a3SStefano Zampini         Mat S_VCT;
497806656605SStefano Zampini 
49799566063dSJacob Faibussowitsch         PetscCall(MatTranspose(S_VC, MAT_INITIAL_MATRIX, &S_VCT));
49809566063dSJacob Faibussowitsch         PetscCall(MatMatMult(C_CRT, S_VCT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B_V));
49819566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&S_VCT));
49829de2952eSStefano Zampini         PetscCall(MatConvert(B_V, MATDENSE, MAT_INPLACE_MATRIX, &B_V));
498306656605SStefano Zampini       }
49849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&C_CRT));
49855b782168SStefano Zampini     } else {
49869566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_R, n_vertices, NULL, &B_V));
498706656605SStefano Zampini     }
498816f15bc4SStefano Zampini     if (n_vertices && n_R) {
4989ffd830a3SStefano Zampini       PetscScalar    *av, *marray;
4990ffd830a3SStefano Zampini       const PetscInt *xadj, *adjncy;
4991ffd830a3SStefano Zampini       PetscInt        n;
4992ffd830a3SStefano Zampini       PetscBool       flg_row;
499306656605SStefano Zampini 
4994ffd830a3SStefano Zampini       /* B_V = B_V - A_VR^T */
49959566063dSJacob Faibussowitsch       PetscCall(MatConvert(A_VR, MATSEQAIJ, MAT_INPLACE_MATRIX, &A_VR));
49969566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
49979566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(A_VR, &av));
49989566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
4999ffd830a3SStefano Zampini       for (i = 0; i < n; i++) {
5000ffd830a3SStefano Zampini         PetscInt j;
5001ffd830a3SStefano Zampini         for (j = xadj[i]; j < xadj[i + 1]; j++) marray[i * n_R + adjncy[j]] -= av[j];
5002ffd830a3SStefano Zampini       }
50039566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
50049566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A_VR, 0, PETSC_FALSE, PETSC_FALSE, &n, &xadj, &adjncy, &flg_row));
50059566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A_VR));
500606656605SStefano Zampini     }
500706656605SStefano Zampini 
5008ffd830a3SStefano Zampini     /* currently there's no support for MatTransposeMatSolve(F,B,X) */
50099de2952eSStefano Zampini     PetscCall(PetscMalloc1(n_R * pcbddc->local_primal_size, &work));
5010abc8f43dSstefano_zampini     if (n_vertices) {
50119566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_V, &marray));
5012ffd830a3SStefano Zampini       for (i = 0; i < n_vertices; i++) {
50139566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + i * n_R));
50149566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
50159566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
50169566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
50179566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
50189566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
501906656605SStefano Zampini       }
50209566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_V, &marray));
5021abc8f43dSstefano_zampini     }
50225b782168SStefano Zampini     if (B_C) {
50239566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(B_C, &marray));
5024ffd830a3SStefano Zampini       for (i = n_vertices; i < n_constraints + n_vertices; i++) {
50259566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_R, marray + (i - n_vertices) * n_R));
50269566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec2_R, work + i * n_R));
50279566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec2_R));
50289566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
50299566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_R));
50309566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec2_R));
503106656605SStefano Zampini       }
50329566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(B_C, &marray));
50335b782168SStefano Zampini     }
503406656605SStefano Zampini     /* coarse basis functions */
50359de2952eSStefano Zampini     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_B, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_B));
50369de2952eSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n_D, pcbddc->local_primal_size, NULL, &pcbddc->coarse_psi_D));
503706656605SStefano Zampini     for (i = 0; i < pcbddc->local_primal_size; i++) {
5038ab2d12f3SJunchao Zhang       Vec v;
503906656605SStefano Zampini 
50409566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(pcbddc->vec1_R, work + i * n_R));
50419566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_B, i, &v));
50429566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
50439566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
504406656605SStefano Zampini       if (i < n_vertices) {
5045ab2d12f3SJunchao Zhang         PetscScalar one = 1.0;
50469566063dSJacob Faibussowitsch         PetscCall(VecSetValues(v, 1, &idx_V_B[i], &one, INSERT_VALUES));
50479566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
50489566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
504906656605SStefano Zampini       }
50509566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_B, i, &v));
505106656605SStefano Zampini 
505206656605SStefano Zampini       if (pcbddc->switch_static || pcbddc->dbg_flag) {
50539566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumnVec(pcbddc->coarse_psi_D, i, &v));
50549566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
50559566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, v, INSERT_VALUES, SCATTER_FORWARD));
50569566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumnVec(pcbddc->coarse_psi_D, i, &v));
505706656605SStefano Zampini       }
50589566063dSJacob Faibussowitsch       PetscCall(VecResetArray(pcbddc->vec1_R));
505906656605SStefano Zampini     }
50609566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_V));
50619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B_C));
50629de2952eSStefano Zampini     PetscCall(PetscFree(work));
50639de2952eSStefano Zampini   } else {
50649de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_B));
50659de2952eSStefano Zampini     pcbddc->coarse_psi_B = pcbddc->coarse_phi_B;
50669de2952eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)pcbddc->coarse_phi_D));
50679de2952eSStefano Zampini     pcbddc->coarse_psi_D = pcbddc->coarse_phi_D;
506806656605SStefano Zampini   }
50699de2952eSStefano Zampini   PetscCall(MatAssemblyBegin(*coarse_submat, MAT_FINAL_ASSEMBLY));
50709de2952eSStefano Zampini   PetscCall(MatAssemblyEnd(*coarse_submat, MAT_FINAL_ASSEMBLY));
5071a6e023c1Sstefano_zampini 
5072d62866d3SStefano Zampini   /* free memory */
50739de2952eSStefano Zampini   PetscCall(PetscFree(V_to_eff_V));
50749de2952eSStefano Zampini   PetscCall(PetscFree(C_to_eff_C));
50759de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_V_J));
50769de2952eSStefano Zampini   PetscCall(PetscFree(R_eff_C_J));
50779de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_V_J));
50789de2952eSStefano Zampini   PetscCall(PetscFree(B_eff_C_J));
50799de2952eSStefano Zampini   PetscCall(ISDestroy(&is_R));
50809de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_V, &idx_V));
50819de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is_C, &idx_C));
50829de2952eSStefano Zampini   PetscCall(ISDestroy(&is_V));
50839de2952eSStefano Zampini   PetscCall(ISDestroy(&is_C));
50849566063dSJacob Faibussowitsch   PetscCall(PetscFree(idx_V_B));
50859566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CV));
50869566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_VC));
50879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_CC));
508848a46eb9SPierre Jolivet   if (n_vertices) PetscCall(MatDestroy(&A_VR));
508948a46eb9SPierre Jolivet   if (n_constraints) PetscCall(MatDestroy(&C_CR));
50909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CorrectionSetUp[pcbddc->current_level], pc, 0, 0, 0));
50918ead10e4SStefano Zampini 
5092da81f932SPierre Jolivet   /* Checking coarse_sub_mat and coarse basis functions */
509388ebb749SStefano Zampini   /* Symmetric case     : It should be \Phi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
509488ebb749SStefano Zampini   /* Non-symmetric case : It should be \Psi^{(j)^T} A^{(j)} \Phi^{(j)}=coarse_sub_mat */
5095d12edf2fSStefano Zampini   if (pcbddc->dbg_flag) {
509625084f0cSStefano Zampini     Mat       AUXMAT, TM1, TM2, TM3, TM4;
509788ebb749SStefano Zampini     Mat       coarse_phi_D, coarse_phi_B;
509888ebb749SStefano Zampini     Mat       coarse_psi_D, coarse_psi_B;
509988ebb749SStefano Zampini     Mat       A_II, A_BB, A_IB, A_BI;
51008bec7fa6SStefano Zampini     Mat       C_B, CPHI;
51018bec7fa6SStefano Zampini     IS        is_dummy;
51028bec7fa6SStefano Zampini     Vec       mones;
510388ebb749SStefano Zampini     MatType   checkmattype = MATSEQAIJ;
510488ebb749SStefano Zampini     PetscReal real_value;
510588ebb749SStefano Zampini 
5106a3df083aSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
5107a3df083aSStefano Zampini       Mat A;
51089566063dSJacob Faibussowitsch       PetscCall(PCBDDCBenignProject(pc, NULL, NULL, &A));
51099566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_II));
51109566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_IB));
51119566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &A_BI));
51129566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(A, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &A_BB));
51139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
5114a3df083aSStefano Zampini     } else {
51159566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_II, checkmattype, MAT_INITIAL_MATRIX, &A_II));
51169566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_IB, checkmattype, MAT_INITIAL_MATRIX, &A_IB));
51179566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BI, checkmattype, MAT_INITIAL_MATRIX, &A_BI));
51189566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcis->A_BB, checkmattype, MAT_INITIAL_MATRIX, &A_BB));
5119a3df083aSStefano Zampini     }
51209566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_D));
51219566063dSJacob Faibussowitsch     PetscCall(MatConvert(pcbddc->coarse_phi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_phi_B));
5122ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
51239566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_D, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_D));
51249566063dSJacob Faibussowitsch       PetscCall(MatConvert(pcbddc->coarse_psi_B, checkmattype, MAT_INITIAL_MATRIX, &coarse_psi_B));
512588ebb749SStefano Zampini     }
51269566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
51279566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Check coarse sub mat computation (symmetric %d)\n", pcbddc->symmetric_primal));
51289566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5129ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
51309566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51319566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM1));
51329566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
51339566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51349566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM2));
51359566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
51369566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51379566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
51389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
51399566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51409566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_psi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
51419566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
514288ebb749SStefano Zampini     } else {
51439566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_II, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &TM1));
51449566063dSJacob Faibussowitsch       PetscCall(MatPtAP(A_BB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &TM2));
51459566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_IB, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51469566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_D, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM3));
51479566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
51489566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A_BI, coarse_phi_D, MAT_INITIAL_MATRIX, 1.0, &AUXMAT));
51499566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(coarse_phi_B, AUXMAT, MAT_INITIAL_MATRIX, 1.0, &TM4));
51509566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&AUXMAT));
515188ebb749SStefano Zampini     }
51529566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM2, DIFFERENT_NONZERO_PATTERN));
51539566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM3, DIFFERENT_NONZERO_PATTERN));
51549566063dSJacob Faibussowitsch     PetscCall(MatAXPY(TM1, one, TM4, DIFFERENT_NONZERO_PATTERN));
51559566063dSJacob Faibussowitsch     PetscCall(MatConvert(TM1, MATSEQDENSE, MAT_INPLACE_MATRIX, &TM1));
51564f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
5157fc227af8SStefano Zampini       Mat                B0_B, B0_BPHI;
51581683a169SBarry Smith       const PetscScalar *data2;
51591683a169SBarry Smith       PetscScalar       *data;
51604f1b2e48SStefano Zampini       PetscInt           j;
5161d12edf2fSStefano Zampini 
51629566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->benign_n, 0, 1, &is_dummy));
51639566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->benign_B0, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B0_B));
51649566063dSJacob Faibussowitsch       PetscCall(MatMatMult(B0_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &B0_BPHI));
51659566063dSJacob Faibussowitsch       PetscCall(MatConvert(B0_BPHI, MATSEQDENSE, MAT_INPLACE_MATRIX, &B0_BPHI));
51669566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(TM1, &data));
51679566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(B0_BPHI, &data2));
51684f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) {
51694f1b2e48SStefano Zampini         PetscInt primal_idx = pcbddc->local_primal_size - pcbddc->benign_n + j;
5170d12edf2fSStefano Zampini         for (i = 0; i < pcbddc->local_primal_size; i++) {
51714f1b2e48SStefano Zampini           data[primal_idx * pcbddc->local_primal_size + i] += data2[i * pcbddc->benign_n + j];
51724f1b2e48SStefano Zampini           data[i * pcbddc->local_primal_size + primal_idx] += data2[i * pcbddc->benign_n + j];
51734f1b2e48SStefano Zampini         }
5174d12edf2fSStefano Zampini       }
51759566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(TM1, &data));
51769566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(B0_BPHI, &data2));
51779566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_B));
51789566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_dummy));
51799566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B0_BPHI));
5180d12edf2fSStefano Zampini     }
51819de2952eSStefano Zampini     PetscCall(MatAXPY(TM1, m_one, *coarse_submat, DIFFERENT_NONZERO_PATTERN));
51829566063dSJacob Faibussowitsch     PetscCall(MatNorm(TM1, NORM_FROBENIUS, &real_value));
51839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
518463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d          matrix error % 1.14e\n", PetscGlobalRank, (double)real_value));
51858bec7fa6SStefano Zampini 
51868bec7fa6SStefano Zampini     /* check constraints */
51879566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, pcbddc->local_primal_size - pcbddc->benign_n, 0, 1, &is_dummy));
51889566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(pcbddc->ConstraintMatrix, is_dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &C_B));
51894f1b2e48SStefano Zampini     if (!pcbddc->benign_n) { /* TODO: add benign case */
51909566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_phi_B, MAT_INITIAL_MATRIX, 1.0, &CPHI));
5191a00504b5SStefano Zampini     } else {
5192a00504b5SStefano Zampini       PetscScalar *data;
5193a00504b5SStefano Zampini       Mat          tmat;
51949566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArray(pcbddc->coarse_phi_B, &data));
51959566063dSJacob Faibussowitsch       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, pcis->n_B, pcbddc->local_primal_size - pcbddc->benign_n, data, &tmat));
51969566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArray(pcbddc->coarse_phi_B, &data));
51979566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, tmat, MAT_INITIAL_MATRIX, 1.0, &CPHI));
51989566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
5199a00504b5SStefano Zampini     }
52009566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(CPHI, &mones, NULL));
52019566063dSJacob Faibussowitsch     PetscCall(VecSet(mones, -1.0));
52029566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
52039566063dSJacob Faibussowitsch     PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
520463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d phi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
5205ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
52069566063dSJacob Faibussowitsch       PetscCall(MatMatMult(C_B, coarse_psi_B, MAT_REUSE_MATRIX, 1.0, &CPHI));
52079566063dSJacob Faibussowitsch       PetscCall(VecSet(mones, -1.0));
52089566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(CPHI, mones, ADD_VALUES));
52099566063dSJacob Faibussowitsch       PetscCall(MatNorm(CPHI, NORM_FROBENIUS, &real_value));
521063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d psi constraints error % 1.14e\n", PetscGlobalRank, (double)real_value));
521188ebb749SStefano Zampini     }
52129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C_B));
52139566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&CPHI));
52149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_dummy));
52159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mones));
52169566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
52179566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_II));
52189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BB));
52199566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_IB));
52209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A_BI));
52219566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM1));
52229566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM2));
52239566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM3));
52249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&TM4));
52259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_D));
52269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&coarse_phi_B));
5227ffd830a3SStefano Zampini     if (!pcbddc->symmetric_primal) {
52289566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_D));
52299566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&coarse_psi_B));
523088ebb749SStefano Zampini     }
523188ebb749SStefano Zampini   }
52327ebab0bbSStefano Zampini 
52339de2952eSStefano Zampini #if 0
52349de2952eSStefano Zampini   {
52359de2952eSStefano Zampini     PetscViewer viewer;
52369de2952eSStefano Zampini     char filename[256];
52379de2952eSStefano Zampini 
52389de2952eSStefano Zampini     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "details_local_coarse_mat%d_level%d.m",PetscGlobalRank,pcbddc->current_level));
52399de2952eSStefano Zampini     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&viewer));
52409de2952eSStefano Zampini     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
52419de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)*coarse_submat,"coarse submat"));
52429de2952eSStefano Zampini     PetscCall(MatView(*coarse_submat,viewer));
52439de2952eSStefano Zampini     if (pcbddc->coarse_phi_B) {
52449de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_B,"phi_B"));
52459de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_B,viewer));
52469de2952eSStefano Zampini     }
52479de2952eSStefano Zampini     if (pcbddc->coarse_phi_D) {
52489de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_phi_D,"phi_D"));
52499de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_phi_D,viewer));
52509de2952eSStefano Zampini     }
52519de2952eSStefano Zampini     if (pcbddc->coarse_psi_B) {
52529de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_B,"psi_B"));
52539de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_B,viewer));
52549de2952eSStefano Zampini     }
52559de2952eSStefano Zampini     if (pcbddc->coarse_psi_D) {
52569de2952eSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)pcbddc->coarse_psi_D,"psi_D"));
52579de2952eSStefano Zampini       PetscCall(MatView(pcbddc->coarse_psi_D,viewer));
52589de2952eSStefano Zampini     }
52599de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->local_mat,"A"));
52609de2952eSStefano Zampini     PetscCall(MatView(pcbddc->local_mat,viewer));
52619de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->ConstraintMatrix,"C"));
52629de2952eSStefano Zampini     PetscCall(MatView(pcbddc->ConstraintMatrix,viewer));
52639de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_I_local,"I"));
52649de2952eSStefano Zampini     PetscCall(ISView(pcis->is_I_local,viewer));
52659de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcis->is_B_local,"B"));
52669de2952eSStefano Zampini     PetscCall(ISView(pcis->is_B_local,viewer));
52679de2952eSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)pcbddc->is_R_local,"R"));
52689de2952eSStefano Zampini     PetscCall(ISView(pcbddc->is_R_local,viewer));
52699de2952eSStefano Zampini     PetscCall(PetscOptionsRestoreViewer(&viewer));
52709de2952eSStefano Zampini   }
52719de2952eSStefano Zampini #endif
52729de2952eSStefano Zampini 
52739de2952eSStefano Zampini   /* device support */
52749de2952eSStefano Zampini   {
52759de2952eSStefano Zampini     PetscBool iscuda, iship, iskokkos;
52769de2952eSStefano Zampini     MatType   mtype = NULL;
52779de2952eSStefano Zampini 
52789de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iscuda, VECCUDA, VECMPICUDA, VECSEQCUDA, ""));
52799de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iship, VECHIP, VECMPIHIP, VECSEQHIP, ""));
52809de2952eSStefano Zampini     PetscCall(PetscObjectTypeCompareAny((PetscObject)pcis->vec1_N, &iskokkos, VECKOKKOS, VECMPIKOKKOS, VECSEQKOKKOS, ""));
52819de2952eSStefano Zampini     if (iskokkos) {
52829de2952eSStefano Zampini       if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_CUDA)) iscuda = PETSC_TRUE;
52839de2952eSStefano Zampini       else if (PetscDefined(HAVE_MACRO_KOKKOS_ENABLE_HIP)) iship = PETSC_TRUE;
52849de2952eSStefano Zampini     }
52859de2952eSStefano Zampini     if (iskokkos) mtype = multi_element ? MATSEQAIJKOKKOS : (iscuda ? MATSEQDENSECUDA : MATSEQDENSEHIP);
52869de2952eSStefano Zampini     else if (iship) mtype = multi_element ? MATSEQAIJHIPSPARSE : MATSEQDENSEHIP;
52879de2952eSStefano Zampini     else if (iscuda) mtype = multi_element ? MATSEQAIJCUSPARSE : MATSEQDENSECUDA;
52889de2952eSStefano Zampini     if (mtype) {
52899de2952eSStefano Zampini       if (pcbddc->local_auxmat1) PetscCall(MatConvert(pcbddc->local_auxmat1, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat1));
52909de2952eSStefano Zampini       if (pcbddc->local_auxmat2) PetscCall(MatConvert(pcbddc->local_auxmat2, mtype, MAT_INPLACE_MATRIX, &pcbddc->local_auxmat2));
52919de2952eSStefano Zampini       if (pcbddc->coarse_phi_B) PetscCall(MatConvert(pcbddc->coarse_phi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_B));
52929de2952eSStefano Zampini       if (pcbddc->coarse_phi_D) PetscCall(MatConvert(pcbddc->coarse_phi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_phi_D));
52939de2952eSStefano Zampini       if (pcbddc->coarse_psi_B) PetscCall(MatConvert(pcbddc->coarse_psi_B, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_B));
52949de2952eSStefano Zampini       if (pcbddc->coarse_psi_D) PetscCall(MatConvert(pcbddc->coarse_psi_D, mtype, MAT_INPLACE_MATRIX, &pcbddc->coarse_psi_D));
52957ebab0bbSStefano Zampini     }
52967ebab0bbSStefano Zampini   }
52973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
529888ebb749SStefano Zampini }
529988ebb749SStefano Zampini 
5300d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSubMatrixUnsorted(Mat A, IS isrow, IS iscol, Mat *B)
5301d71ae5a4SJacob Faibussowitsch {
5302d65f70fdSStefano Zampini   Mat      *work_mat;
5303d65f70fdSStefano Zampini   IS        isrow_s, iscol_s;
5304d65f70fdSStefano Zampini   PetscBool rsorted, csorted;
5305c43ebad9SStefano Zampini   PetscInt  rsize, *idxs_perm_r = NULL, csize, *idxs_perm_c = NULL;
5306aa0d41d4SStefano Zampini 
5307aa0d41d4SStefano Zampini   PetscFunctionBegin;
53089566063dSJacob Faibussowitsch   PetscCall(ISSorted(isrow, &rsorted));
53099566063dSJacob Faibussowitsch   PetscCall(ISSorted(iscol, &csorted));
53109566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &rsize));
53119566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscol, &csize));
5312aa0d41d4SStefano Zampini 
5313d65f70fdSStefano Zampini   if (!rsorted) {
5314906d46d4SStefano Zampini     const PetscInt *idxs;
5315906d46d4SStefano Zampini     PetscInt       *idxs_sorted, i;
5316aa0d41d4SStefano Zampini 
53179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_perm_r));
53189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rsize, &idxs_sorted));
5319ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_perm_r[i] = i;
53209566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrow, &idxs));
53219566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithPermutation(rsize, idxs, idxs_perm_r));
5322ad540459SPierre Jolivet     for (i = 0; i < rsize; i++) idxs_sorted[i] = idxs[idxs_perm_r[i]];
53239566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrow, &idxs));
53249566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_sorted, PETSC_OWN_POINTER, &isrow_s));
5325d65f70fdSStefano Zampini   } else {
53269566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isrow));
5327d65f70fdSStefano Zampini     isrow_s = isrow;
5328aa0d41d4SStefano Zampini   }
5329906d46d4SStefano Zampini 
5330d65f70fdSStefano Zampini   if (!csorted) {
5331d65f70fdSStefano Zampini     if (isrow == iscol) {
53329566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)isrow_s));
5333d65f70fdSStefano Zampini       iscol_s = isrow_s;
5334d65f70fdSStefano Zampini     } else {
5335d65f70fdSStefano Zampini       const PetscInt *idxs;
5336d65f70fdSStefano Zampini       PetscInt       *idxs_sorted, i;
5337906d46d4SStefano Zampini 
53389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_perm_c));
53399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(csize, &idxs_sorted));
5340ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_perm_c[i] = i;
53419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol, &idxs));
53429566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithPermutation(csize, idxs, idxs_perm_c));
5343ad540459SPierre Jolivet       for (i = 0; i < csize; i++) idxs_sorted[i] = idxs[idxs_perm_c[i]];
53449566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol, &idxs));
53459566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_sorted, PETSC_OWN_POINTER, &iscol_s));
5346d65f70fdSStefano Zampini     }
5347d65f70fdSStefano Zampini   } else {
53489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)iscol));
5349d65f70fdSStefano Zampini     iscol_s = iscol;
5350d65f70fdSStefano Zampini   }
5351d65f70fdSStefano Zampini 
53529566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrow_s, &iscol_s, MAT_INITIAL_MATRIX, &work_mat));
5353d65f70fdSStefano Zampini 
5354d65f70fdSStefano Zampini   if (!rsorted || !csorted) {
5355906d46d4SStefano Zampini     Mat new_mat;
5356d65f70fdSStefano Zampini     IS  is_perm_r, is_perm_c;
5357906d46d4SStefano Zampini 
5358d65f70fdSStefano Zampini     if (!rsorted) {
5359d65f70fdSStefano Zampini       PetscInt *idxs_r, i;
53609566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rsize, &idxs_r));
5361ad540459SPierre Jolivet       for (i = 0; i < rsize; i++) idxs_r[idxs_perm_r[i]] = i;
53629566063dSJacob Faibussowitsch       PetscCall(PetscFree(idxs_perm_r));
53639566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, rsize, idxs_r, PETSC_OWN_POINTER, &is_perm_r));
5364d65f70fdSStefano Zampini     } else {
53659566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, rsize, 0, 1, &is_perm_r));
5366906d46d4SStefano Zampini     }
53679566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_r));
5368d65f70fdSStefano Zampini 
5369d65f70fdSStefano Zampini     if (!csorted) {
5370d65f70fdSStefano Zampini       if (isrow_s == iscol_s) {
53719566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)is_perm_r));
5372d65f70fdSStefano Zampini         is_perm_c = is_perm_r;
5373d65f70fdSStefano Zampini       } else {
5374d65f70fdSStefano Zampini         PetscInt *idxs_c, i;
537528b400f6SJacob Faibussowitsch         PetscCheck(idxs_perm_c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Permutation array not present");
53769566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(csize, &idxs_c));
5377ad540459SPierre Jolivet         for (i = 0; i < csize; i++) idxs_c[idxs_perm_c[i]] = i;
53789566063dSJacob Faibussowitsch         PetscCall(PetscFree(idxs_perm_c));
53799566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, csize, idxs_c, PETSC_OWN_POINTER, &is_perm_c));
5380d65f70fdSStefano Zampini       }
5381d65f70fdSStefano Zampini     } else {
53829566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, csize, 0, 1, &is_perm_c));
5383d65f70fdSStefano Zampini     }
53849566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(is_perm_c));
5385d65f70fdSStefano Zampini 
53869566063dSJacob Faibussowitsch     PetscCall(MatPermute(work_mat[0], is_perm_r, is_perm_c, &new_mat));
53879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat[0]));
5388d65f70fdSStefano Zampini     work_mat[0] = new_mat;
53899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_r));
53909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_perm_c));
5391d65f70fdSStefano Zampini   }
5392d65f70fdSStefano Zampini 
53939566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)work_mat[0]));
5394d65f70fdSStefano Zampini   *B = work_mat[0];
53959566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &work_mat));
53969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrow_s));
53979566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol_s));
53983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5399d65f70fdSStefano Zampini }
5400d65f70fdSStefano Zampini 
5401d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeLocalMatrix(PC pc, Mat ChangeOfBasisMatrix)
5402d71ae5a4SJacob Faibussowitsch {
5403aa0d41d4SStefano Zampini   Mat_IS   *matis  = (Mat_IS *)pc->pmat->data;
54045e8657edSStefano Zampini   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
5405022d8d2bSstefano_zampini   Mat       new_mat, lA;
54065e8657edSStefano Zampini   IS        is_local, is_global;
5407d65f70fdSStefano Zampini   PetscInt  local_size;
5408b94d7dedSBarry Smith   PetscBool isseqaij, issym, isset;
5409aa0d41d4SStefano Zampini 
5410aa0d41d4SStefano Zampini   PetscFunctionBegin;
54119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->local_mat));
54129566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_size, NULL));
54139de2952eSStefano Zampini   if (pcbddc->mat_graph->multi_element) {
54149de2952eSStefano Zampini     Mat     *mats, *bdiags;
54159de2952eSStefano Zampini     IS      *gsubs;
54169de2952eSStefano Zampini     PetscInt nsubs = pcbddc->n_local_subs;
54179de2952eSStefano Zampini 
54189de2952eSStefano Zampini     PetscCall(PetscCalloc1(nsubs * nsubs, &mats));
54199de2952eSStefano Zampini     PetscCall(PetscMalloc1(nsubs, &gsubs));
54209de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, pcbddc->local_subs[i], &gsubs[i]));
54219de2952eSStefano Zampini     PetscCall(MatCreateSubMatrices(ChangeOfBasisMatrix, nsubs, gsubs, gsubs, MAT_INITIAL_MATRIX, &bdiags));
54229de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) PetscCall(ISDestroy(&gsubs[i]));
54239de2952eSStefano Zampini     PetscCall(PetscFree(gsubs));
54249de2952eSStefano Zampini 
54259de2952eSStefano Zampini     for (PetscInt i = 0; i < nsubs; i++) mats[i * (1 + nsubs)] = bdiags[i];
54269de2952eSStefano Zampini     PetscCall(MatCreateNest(PETSC_COMM_SELF, nsubs, pcbddc->local_subs, nsubs, pcbddc->local_subs, mats, &new_mat));
54279de2952eSStefano Zampini     PetscCall(MatConvert(new_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &new_mat));
54289de2952eSStefano Zampini     PetscCall(MatDestroySubMatrices(nsubs, &bdiags));
54299de2952eSStefano Zampini     PetscCall(PetscFree(mats));
54309de2952eSStefano Zampini   } else {
54319566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)matis->A), local_size, 0, 1, &is_local));
54329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyIS(matis->rmapping, is_local, &is_global));
54339566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_local));
54349566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrixUnsorted(ChangeOfBasisMatrix, is_global, is_global, &new_mat));
54359566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_global));
54369de2952eSStefano Zampini   }
5437906d46d4SStefano Zampini   if (pcbddc->dbg_flag) {
5438906d46d4SStefano Zampini     Vec       x, x_change;
5439906d46d4SStefano Zampini     PetscReal error;
5440906d46d4SStefano Zampini 
54419566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(ChangeOfBasisMatrix, &x, &x_change));
54429566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(x, NULL));
54439566063dSJacob Faibussowitsch     PetscCall(MatMult(ChangeOfBasisMatrix, x, x_change));
54449566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
54459566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->cctx, x, matis->x, INSERT_VALUES, SCATTER_FORWARD));
54469566063dSJacob Faibussowitsch     PetscCall(MatMult(new_mat, matis->x, matis->y));
544788428137SStefano Zampini     if (!pcbddc->change_interior) {
544888428137SStefano Zampini       const PetscScalar *x, *y, *v;
544988428137SStefano Zampini       PetscReal          lerror = 0.;
545088428137SStefano Zampini       PetscInt           i;
545188428137SStefano Zampini 
54529566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->x, &x));
54539566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->y, &y));
54549566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(matis->counter, &v));
545588428137SStefano Zampini       for (i = 0; i < local_size; i++)
54569371c9d4SSatish Balay         if (PetscRealPart(v[i]) < 1.5 && PetscAbsScalar(x[i] - y[i]) > lerror) lerror = PetscAbsScalar(x[i] - y[i]);
54579566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->x, &x));
54589566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->y, &y));
54599566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(matis->counter, &v));
54601c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&lerror, &error, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)pc)));
5461637e8532SStefano Zampini       if (error > PETSC_SMALL) {
5462637e8532SStefano Zampini         if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
546363a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on I: %1.6e", (double)error);
5464637e8532SStefano Zampini         } else {
546563a3b9bcSJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on I: %1.6e", (double)error);
5466637e8532SStefano Zampini         }
5467637e8532SStefano Zampini       }
546888428137SStefano Zampini     }
54699566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
54709566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(matis->rctx, matis->y, x, INSERT_VALUES, SCATTER_REVERSE));
54719566063dSJacob Faibussowitsch     PetscCall(VecAXPY(x, -1.0, x_change));
54729566063dSJacob Faibussowitsch     PetscCall(VecNorm(x, NORM_INFINITY, &error));
5473637e8532SStefano Zampini     if (error > PETSC_SMALL) {
5474637e8532SStefano Zampini       if (!pcbddc->user_ChangeOfBasisMatrix || pcbddc->current_level) {
547563a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
5476637e8532SStefano Zampini       } else {
547763a3b9bcSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Error global vs local change on N: %1.6e", (double)error);
5478637e8532SStefano Zampini       }
5479637e8532SStefano Zampini     }
54809566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
54819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x_change));
5482906d46d4SStefano Zampini   }
5483906d46d4SStefano Zampini 
5484022d8d2bSstefano_zampini   /* lA is present if we are setting up an inner BDDC for a saddle point FETI-DP */
54859566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
5486022d8d2bSstefano_zampini 
548722d5777bSStefano Zampini   /* TODO: HOW TO WORK WITH BAIJ and SBAIJ and SEQDENSE? */
54889566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
548922d5777bSStefano Zampini   if (isseqaij) {
54909566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
54919566063dSJacob Faibussowitsch     PetscCall(MatPtAP(matis->A, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
5492022d8d2bSstefano_zampini     if (lA) {
5493022d8d2bSstefano_zampini       Mat work;
54949566063dSJacob Faibussowitsch       PetscCall(MatPtAP(lA, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
54959566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
54969566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5497022d8d2bSstefano_zampini     }
5498aa0d41d4SStefano Zampini   } else {
5499a00504b5SStefano Zampini     Mat work_mat;
55001cf9b237SStefano Zampini 
55019566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pcbddc->local_mat));
55029566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
55039566063dSJacob Faibussowitsch     PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &pcbddc->local_mat));
55049566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&work_mat));
5505022d8d2bSstefano_zampini     if (lA) {
5506022d8d2bSstefano_zampini       Mat work;
55079566063dSJacob Faibussowitsch       PetscCall(MatConvert(lA, MATSEQAIJ, MAT_INITIAL_MATRIX, &work_mat));
55089566063dSJacob Faibussowitsch       PetscCall(MatPtAP(work_mat, new_mat, MAT_INITIAL_MATRIX, 2.0, &work));
55099566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject)work));
55109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&work));
5511022d8d2bSstefano_zampini     }
5512aa0d41d4SStefano Zampini   }
5513b94d7dedSBarry Smith   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
5514b94d7dedSBarry Smith   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
55159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&new_mat));
55163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5517aa0d41d4SStefano Zampini }
5518aa0d41d4SStefano Zampini 
5519d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalScatters(PC pc)
5520d71ae5a4SJacob Faibussowitsch {
5521f4f49eeaSPierre Jolivet   PC_IS          *pcis        = (PC_IS *)pc->data;
5522a64d13efSStefano Zampini   PC_BDDC        *pcbddc      = (PC_BDDC *)pc->data;
5523d62866d3SStefano Zampini   PCBDDCSubSchurs sub_schurs  = pcbddc->sub_schurs;
552453892102SStefano Zampini   PetscInt       *idx_R_local = NULL;
55253a50541eSStefano Zampini   PetscInt        n_vertices, i, j, n_R, n_D, n_B;
55263a50541eSStefano Zampini   PetscInt        vbs, bs;
55276816873aSStefano Zampini   PetscBT         bitmask = NULL;
5528a64d13efSStefano Zampini 
5529a64d13efSStefano Zampini   PetscFunctionBegin;
5530b23d619eSStefano Zampini   /*
5531b23d619eSStefano Zampini     No need to setup local scatters if
5532b23d619eSStefano Zampini       - primal space is unchanged
5533b23d619eSStefano Zampini         AND
5534b23d619eSStefano Zampini       - we actually have locally some primal dofs (could not be true in multilevel or for isolated subdomains)
5535b23d619eSStefano Zampini         AND
5536b23d619eSStefano Zampini       - we are not in debugging mode (this is needed since there are Synchronized prints at the end of the subroutine
5537b23d619eSStefano Zampini   */
55383ba16761SJacob Faibussowitsch   if (!pcbddc->new_primal_space_local && pcbddc->local_primal_size && !pcbddc->dbg_flag) PetscFunctionReturn(PETSC_SUCCESS);
5539f4ddd8eeSStefano Zampini   /* destroy old objects */
55409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&pcbddc->is_R_local));
55419566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_B));
55429566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&pcbddc->R_to_D));
5543a64d13efSStefano Zampini   /* Set Non-overlapping dimensions */
5544b371cd4fSStefano Zampini   n_B        = pcis->n_B;
5545b371cd4fSStefano Zampini   n_D        = pcis->n - n_B;
5546b371cd4fSStefano Zampini   n_vertices = pcbddc->n_vertices;
55473a50541eSStefano Zampini 
5548e602f447SPierre Jolivet   /* Dohrmann's notation: dofs split in R (Remaining: all dofs but the vertices) and V (Vertices) */
55496816873aSStefano Zampini 
555053892102SStefano Zampini   /* create auxiliary bitmask and allocate workspace */
5551b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
55529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n - n_vertices, &idx_R_local));
55539566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n, &bitmask));
555448a46eb9SPierre Jolivet     for (i = 0; i < n_vertices; i++) PetscCall(PetscBTSet(bitmask, pcbddc->local_primal_ref_node[i]));
55554641a718SStefano Zampini 
5556a64d13efSStefano Zampini     for (i = 0, n_R = 0; i < pcis->n; i++) {
5557ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, i)) idx_R_local[n_R++] = i;
5558a64d13efSStefano Zampini     }
5559df4d28bfSStefano Zampini   } else { /* A different ordering (already computed) is present if we are reusing the Schur solver */
5560df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
55616816873aSStefano Zampini 
55629566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
55639566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_R, &n_R));
55646816873aSStefano Zampini   }
55653a50541eSStefano Zampini 
55663a50541eSStefano Zampini   /* Block code */
55673a50541eSStefano Zampini   vbs = 1;
55689566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pcbddc->local_mat, &bs));
55693a50541eSStefano Zampini   if (bs > 1 && !(n_vertices % bs)) {
55703a50541eSStefano Zampini     PetscBool is_blocked = PETSC_TRUE;
55713a50541eSStefano Zampini     PetscInt *vary;
5572b334f244SStefano Zampini     if (!sub_schurs || !sub_schurs->reuse_solver) {
55739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcis->n / bs, &vary));
55749566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(vary, pcis->n / bs));
5575d3df7717SStefano Zampini       /* Verify that the vertex indices correspond to each element in a block (code taken from sbaij2.c) */
5576d3df7717SStefano 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 */
55770e6343abSStefano Zampini       for (i = 0; i < n_vertices; i++) vary[pcbddc->local_primal_ref_node[i] / bs]++;
5578d3df7717SStefano Zampini       for (i = 0; i < pcis->n / bs; i++) {
55793a50541eSStefano Zampini         if (vary[i] != 0 && vary[i] != bs) {
55803a50541eSStefano Zampini           is_blocked = PETSC_FALSE;
55813a50541eSStefano Zampini           break;
55823a50541eSStefano Zampini         }
55833a50541eSStefano Zampini       }
55849566063dSJacob Faibussowitsch       PetscCall(PetscFree(vary));
5585d3df7717SStefano Zampini     } else {
5586d3df7717SStefano Zampini       /* Verify directly the R set */
5587d3df7717SStefano Zampini       for (i = 0; i < n_R / bs; i++) {
5588d3df7717SStefano Zampini         PetscInt j, node = idx_R_local[bs * i];
5589d3df7717SStefano Zampini         for (j = 1; j < bs; j++) {
5590d3df7717SStefano Zampini           if (node != idx_R_local[bs * i + j] - j) {
5591d3df7717SStefano Zampini             is_blocked = PETSC_FALSE;
5592d3df7717SStefano Zampini             break;
5593d3df7717SStefano Zampini           }
5594d3df7717SStefano Zampini         }
5595d3df7717SStefano Zampini       }
5596d3df7717SStefano Zampini     }
55973a50541eSStefano Zampini     if (is_blocked) { /* build compressed IS for R nodes (complement of vertices) */
55983a50541eSStefano Zampini       vbs = bs;
5599ad540459SPierre Jolivet       for (i = 0; i < n_R / vbs; i++) idx_R_local[i] = idx_R_local[vbs * i] / vbs;
56003a50541eSStefano Zampini     }
56013a50541eSStefano Zampini   }
56029566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, vbs, n_R / vbs, idx_R_local, PETSC_COPY_VALUES, &pcbddc->is_R_local));
5603b334f244SStefano Zampini   if (sub_schurs && sub_schurs->reuse_solver) {
5604df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
560553892102SStefano Zampini 
56069566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(reuse_solver->is_R, (const PetscInt **)&idx_R_local));
56079566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&reuse_solver->is_R));
56089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->is_R_local));
5609df4d28bfSStefano Zampini     reuse_solver->is_R = pcbddc->is_R_local;
561053892102SStefano Zampini   } else {
56119566063dSJacob Faibussowitsch     PetscCall(PetscFree(idx_R_local));
561253892102SStefano Zampini   }
5613a64d13efSStefano Zampini 
5614a64d13efSStefano Zampini   /* print some info if requested */
5615a64d13efSStefano Zampini   if (pcbddc->dbg_flag) {
56169566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
56179566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
56189566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
56199566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d local dimensions\n", PetscGlobalRank));
562063a3b9bcSJacob 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));
56219371c9d4SSatish 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,
56229371c9d4SSatish Balay                                                  pcbddc->local_primal_size - n_vertices - pcbddc->benign_n, pcbddc->local_primal_size));
56239566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
5624a64d13efSStefano Zampini   }
5625a64d13efSStefano Zampini 
5626a64d13efSStefano Zampini   /* VecScatters pcbddc->R_to_B and (optionally) pcbddc->R_to_D */
5627b334f244SStefano Zampini   if (!sub_schurs || !sub_schurs->reuse_solver) {
56286816873aSStefano Zampini     IS        is_aux1, is_aux2;
56296816873aSStefano Zampini     PetscInt *aux_array1, *aux_array2, *is_indices, *idx_R_local;
56306816873aSStefano Zampini 
56319566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
56329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array1));
56339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n_B - n_vertices, &aux_array2));
56349566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
563548a46eb9SPierre Jolivet     for (i = 0; i < n_D; i++) PetscCall(PetscBTSet(bitmask, is_indices[i]));
56369566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_I_local, (const PetscInt **)&is_indices));
5637a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_R; i++) {
5638ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5639a64d13efSStefano Zampini     }
56409566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
56419566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
5642a64d13efSStefano Zampini     for (i = 0, j = 0; i < n_B; i++) {
5643ad540459SPierre Jolivet       if (!PetscBTLookup(bitmask, is_indices[i])) aux_array2[j++] = i;
5644a64d13efSStefano Zampini     }
56459566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcis->is_B_local, (const PetscInt **)&is_indices));
56469566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array2, PETSC_OWN_POINTER, &is_aux2));
56479566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_B, is_aux2, &pcbddc->R_to_B));
56489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux1));
56499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_aux2));
5650a64d13efSStefano Zampini 
56518eeda7d8SStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
56529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_D, &aux_array1));
5653a64d13efSStefano Zampini       for (i = 0, j = 0; i < n_R; i++) {
5654ad540459SPierre Jolivet         if (PetscBTLookup(bitmask, idx_R_local[i])) aux_array1[j++] = i;
5655a64d13efSStefano Zampini       }
56569566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, aux_array1, PETSC_OWN_POINTER, &is_aux1));
56579566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, is_aux1, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
56589566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_aux1));
5659a64d13efSStefano Zampini     }
56609566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&bitmask));
56619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pcbddc->is_R_local, (const PetscInt **)&idx_R_local));
5662d62866d3SStefano Zampini   } else {
5663df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
56646816873aSStefano Zampini     IS                 tis;
56656816873aSStefano Zampini     PetscInt           schur_size;
56666816873aSStefano Zampini 
56679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(reuse_solver->is_B, &schur_size));
56689566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, schur_size, n_D, 1, &tis));
56699566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_B, reuse_solver->is_B, &pcbddc->R_to_B));
56709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&tis));
56716816873aSStefano Zampini     if (pcbddc->switch_static || pcbddc->dbg_flag) {
56729566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, n_D, 0, 1, &tis));
56739566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(pcbddc->vec1_R, tis, pcis->vec1_D, (IS)0, &pcbddc->R_to_D));
56749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&tis));
5675d62866d3SStefano Zampini     }
5676d62866d3SStefano Zampini   }
56773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5678a64d13efSStefano Zampini }
5679a64d13efSStefano Zampini 
5680d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNullSpacePropagateAny_Private(Mat A, IS is, Mat B)
5681d71ae5a4SJacob Faibussowitsch {
568292cccca0SStefano Zampini   MatNullSpace   NullSpace;
568392cccca0SStefano Zampini   Mat            dmat;
568492cccca0SStefano Zampini   const Vec     *nullvecs;
568592cccca0SStefano Zampini   Vec            v, v2, *nullvecs2;
56866d9e27e4SStefano Zampini   VecScatter     sct = NULL;
5687eb06acf8SStefano Zampini   PetscContainer c;
5688eb06acf8SStefano Zampini   PetscScalar   *ddata;
5689295df10fSStefano Zampini   PetscInt       k, nnsp_size, bsiz, bsiz2, n, N, bs;
569092cccca0SStefano Zampini   PetscBool      nnsp_has_cnst;
569192cccca0SStefano Zampini 
569292cccca0SStefano Zampini   PetscFunctionBegin;
56936d9e27e4SStefano Zampini   if (!is && !B) { /* MATIS */
56946d9e27e4SStefano Zampini     Mat_IS *matis = (Mat_IS *)A->data;
56956d9e27e4SStefano Zampini 
569648a46eb9SPierre Jolivet     if (!B) PetscCall(MatISGetLocalMat(A, &B));
56976d9e27e4SStefano Zampini     sct = matis->cctx;
56989566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sct));
56996d9e27e4SStefano Zampini   } else {
57009566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B, &NullSpace));
570148a46eb9SPierre Jolivet     if (!NullSpace) PetscCall(MatGetNearNullSpace(B, &NullSpace));
57023ba16761SJacob Faibussowitsch     if (NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
57036d9e27e4SStefano Zampini   }
57049566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(A, &NullSpace));
570548a46eb9SPierre Jolivet   if (!NullSpace) PetscCall(MatGetNearNullSpace(A, &NullSpace));
57063ba16761SJacob Faibussowitsch   if (!NullSpace) PetscFunctionReturn(PETSC_SUCCESS);
57076d9e27e4SStefano Zampini 
57089566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &v, NULL));
57099566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B, &v2, NULL));
571048a46eb9SPierre Jolivet   if (!sct) PetscCall(VecScatterCreate(v, is, v2, NULL, &sct));
57119566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(NullSpace, &nnsp_has_cnst, &nnsp_size, (const Vec **)&nullvecs));
5712295df10fSStefano Zampini   bsiz = bsiz2 = nnsp_size + !!nnsp_has_cnst;
57139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsiz, &nullvecs2));
57149566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v2, &bs));
57159566063dSJacob Faibussowitsch   PetscCall(VecGetSize(v2, &N));
57169566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v2, &n));
57179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * bsiz, &ddata));
571892cccca0SStefano Zampini   for (k = 0; k < nnsp_size; k++) {
57199566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * k, &nullvecs2[k]));
57209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
57219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, nullvecs[k], nullvecs2[k], INSERT_VALUES, SCATTER_FORWARD));
572292cccca0SStefano Zampini   }
572392cccca0SStefano Zampini   if (nnsp_has_cnst) {
57249566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)B), bs, n, N, ddata + n * nnsp_size, &nullvecs2[nnsp_size]));
57259566063dSJacob Faibussowitsch     PetscCall(VecSet(nullvecs2[nnsp_size], 1.0));
572692cccca0SStefano Zampini   }
57279566063dSJacob Faibussowitsch   PetscCall(PCBDDCOrthonormalizeVecs(&bsiz2, nullvecs2));
57289566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)B), PETSC_FALSE, bsiz2, nullvecs2, &NullSpace));
5729295df10fSStefano Zampini 
57309566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)B), n, PETSC_DECIDE, N, bsiz2, ddata, &dmat));
57319566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)B), &c));
57329566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ddata));
57339566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
57349566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)dmat, "_PBDDC_Null_dmat_arr", (PetscObject)c));
57359566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
57369566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)NullSpace, "_PBDDC_Null_dmat", (PetscObject)dmat));
57379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&dmat));
5738eb06acf8SStefano Zampini 
573948a46eb9SPierre Jolivet   for (k = 0; k < bsiz; k++) PetscCall(VecDestroy(&nullvecs2[k]));
57409566063dSJacob Faibussowitsch   PetscCall(PetscFree(nullvecs2));
57419566063dSJacob Faibussowitsch   PetscCall(MatSetNearNullSpace(B, NullSpace));
57429566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&NullSpace));
57439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
57449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v2));
57459566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sct));
57463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
574792cccca0SStefano Zampini }
5748304d26faSStefano Zampini 
5749d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpLocalSolvers(PC pc, PetscBool dirichlet, PetscBool neumann)
5750d71ae5a4SJacob Faibussowitsch {
5751304d26faSStefano Zampini   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
5752304d26faSStefano Zampini   PC_IS       *pcis   = (PC_IS *)pc->data;
5753304d26faSStefano Zampini   PC           pc_temp;
5754304d26faSStefano Zampini   Mat          A_RR;
575592cccca0SStefano Zampini   MatNullSpace nnsp;
5756f4ddd8eeSStefano Zampini   MatReuse     reuse;
5757304d26faSStefano Zampini   PetscScalar  m_one = -1.0;
5758304d26faSStefano Zampini   PetscReal    value;
575904708bb6SStefano Zampini   PetscInt     n_D, n_R;
5760b94d7dedSBarry Smith   PetscBool    issbaij, opts, isset, issym;
57610a545947SLisandro Dalcin   void (*f)(void) = NULL;
5762312be037SStefano Zampini   char   dir_prefix[256], neu_prefix[256], str_level[16];
5763e604994aSStefano Zampini   size_t len;
5764304d26faSStefano Zampini 
5765304d26faSStefano Zampini   PetscFunctionBegin;
57669566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
57676d9e27e4SStefano Zampini   /* approximate solver, propagate NearNullSpace if needed */
57686d9e27e4SStefano Zampini   if (!pc->setupcalled && (pcbddc->NullSpace_corr[0] || pcbddc->NullSpace_corr[2])) {
57696d9e27e4SStefano Zampini     MatNullSpace gnnsp1, gnnsp2;
57706d9e27e4SStefano Zampini     PetscBool    lhas, ghas;
57716d9e27e4SStefano Zampini 
57729566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcbddc->local_mat, &nnsp));
57739566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pc->pmat, &gnnsp1));
57749566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(pc->pmat, &gnnsp2));
57756d9e27e4SStefano Zampini     lhas = nnsp ? PETSC_TRUE : PETSC_FALSE;
57761c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lhas, &ghas, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
577748a46eb9SPierre Jolivet     if (!ghas && (gnnsp1 || gnnsp2)) PetscCall(MatNullSpacePropagateAny_Private(pc->pmat, NULL, NULL));
57786d9e27e4SStefano Zampini   }
57796d9e27e4SStefano Zampini 
5780e604994aSStefano Zampini   /* compute prefixes */
5781c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(dir_prefix, "", sizeof(dir_prefix)));
5782c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(neu_prefix, "", sizeof(neu_prefix)));
5783e604994aSStefano Zampini   if (!pcbddc->current_level) {
57849566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, sizeof(dir_prefix)));
57859566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, sizeof(neu_prefix)));
57869566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
57879566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
5788e604994aSStefano Zampini   } else {
5789f4f49eeaSPierre Jolivet     PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)pcbddc->current_level));
57909566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
5791e604994aSStefano Zampini     len -= 15;                                /* remove "pc_bddc_coarse_" */
5792312be037SStefano Zampini     if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
5793312be037SStefano Zampini     if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
5794a126751eSBarry Smith     /* Nonstandard use of PetscStrncpy() to only copy a portion of the input string */
57959566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(dir_prefix, ((PetscObject)pc)->prefix, len + 1));
57969566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(neu_prefix, ((PetscObject)pc)->prefix, len + 1));
57979566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, "pc_bddc_dirichlet_", sizeof(dir_prefix)));
57989566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, "pc_bddc_neumann_", sizeof(neu_prefix)));
57999566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(dir_prefix, str_level, sizeof(dir_prefix)));
58009566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(neu_prefix, str_level, sizeof(neu_prefix)));
5801e604994aSStefano Zampini   }
5802e604994aSStefano Zampini 
5803304d26faSStefano Zampini   /* DIRICHLET PROBLEM */
5804684f6988SStefano Zampini   if (dirichlet) {
5805d5574798SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
5806450f8f5eSStefano Zampini     if (pcbddc->benign_n && !pcbddc->benign_change_explicit) {
58077827d75bSBarry Smith       PetscCheck(sub_schurs && sub_schurs->reuse_solver, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not yet implemented");
5808450f8f5eSStefano Zampini       if (pcbddc->dbg_flag) {
5809a3df083aSStefano Zampini         Mat A_IIn;
5810a3df083aSStefano Zampini 
58119566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignProject(pc, pcis->is_I_local, pcis->is_I_local, &A_IIn));
58129566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcis->A_II));
5813a3df083aSStefano Zampini         pcis->A_II = A_IIn;
5814a3df083aSStefano Zampini       }
5815450f8f5eSStefano Zampini     }
5816b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5817b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(pcis->A_II, MAT_SYMMETRIC, issym));
5818b94d7dedSBarry Smith 
5819ac78edfcSStefano Zampini     /* Matrix for Dirichlet problem is pcis->A_II */
5820964fefecSStefano Zampini     n_D  = pcis->n - pcis->n_B;
582192cccca0SStefano Zampini     opts = PETSC_FALSE;
5822304d26faSStefano Zampini     if (!pcbddc->ksp_D) { /* create object if not yet build */
582392cccca0SStefano Zampini       opts = PETSC_TRUE;
58249566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_D));
58253821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_D, pc->kspnestlevel));
58269566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_D, (PetscObject)pc, 1));
5827304d26faSStefano Zampini       /* default */
58289566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_D, KSPPREONLY));
58299566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_D, dir_prefix));
58309566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pcis->pA_II, MATSEQSBAIJ, &issbaij));
58319566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
58329577ea80SStefano Zampini       if (issbaij) {
58339566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
58349577ea80SStefano Zampini       } else {
58359566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
58369577ea80SStefano Zampini       }
58379566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_D, pc->erroriffailure));
583892cccca0SStefano Zampini     }
58399566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pcis->pA_II, ((PetscObject)pcbddc->ksp_D)->prefix));
58409de2952eSStefano Zampini     PetscCall(MatViewFromOptions(pcis->pA_II, NULL, "-mat_view"));
58419566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->ksp_D, pcis->A_II, pcis->pA_II));
5842304d26faSStefano Zampini     /* Allow user's customization */
58431baa6e33SBarry Smith     if (opts) PetscCall(KSPSetFromOptions(pcbddc->ksp_D));
58449566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
58456d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[0] && !nnsp) { /* approximate solver, propagate NearNullSpace */
58469566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcis->is_I_local, pcis->pA_II));
584792cccca0SStefano Zampini     }
58489566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(pcis->pA_II, &nnsp));
58499566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
58509566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
585192cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
5852cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
5853cd18cfedSStefano Zampini       const PetscInt *idxs;
5854cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
5855cd18cfedSStefano Zampini 
58569566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcis->is_I_local, &nl));
58579566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcis->is_I_local, &idxs));
58589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
5859cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
5860ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
5861cd18cfedSStefano Zampini       }
58629566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcis->is_I_local, &idxs));
58639566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
58649566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
5865cd18cfedSStefano Zampini     }
5866b334f244SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
5867df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5868d62866d3SStefano Zampini 
58699566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_D, reuse_solver->interior_solver));
5870d5574798SStefano Zampini     }
587192cccca0SStefano Zampini 
5872304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
5873304d26faSStefano Zampini     if (!n_D) {
58749566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_D, &pc_temp));
58759566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
5876304d26faSStefano Zampini     }
58779566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_D));
5878304d26faSStefano Zampini     /* set ksp_D into pcis data */
58799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)pcbddc->ksp_D));
58809566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&pcis->ksp_D));
5881304d26faSStefano Zampini     pcis->ksp_D = pcbddc->ksp_D;
5882684f6988SStefano Zampini   }
5883304d26faSStefano Zampini 
5884304d26faSStefano Zampini   /* NEUMANN PROBLEM */
58850a545947SLisandro Dalcin   A_RR = NULL;
5886684f6988SStefano Zampini   if (neumann) {
5887d62866d3SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
588804708bb6SStefano Zampini     PetscInt        ibs, mbs;
5889b94d7dedSBarry Smith     PetscBool       issbaij, reuse_neumann_solver, isset, issym;
589004708bb6SStefano Zampini     Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
58910aa714b2SStefano Zampini 
58920aa714b2SStefano Zampini     reuse_neumann_solver = PETSC_FALSE;
58930aa714b2SStefano Zampini     if (sub_schurs && sub_schurs->reuse_solver) {
58940aa714b2SStefano Zampini       IS iP;
58950aa714b2SStefano Zampini 
58960aa714b2SStefano Zampini       reuse_neumann_solver = PETSC_TRUE;
58979566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)sub_schurs->A, "__KSPFETIDP_iP", (PetscObject *)&iP));
58980aa714b2SStefano Zampini       if (iP) reuse_neumann_solver = PETSC_FALSE;
58990aa714b2SStefano Zampini     }
5900f4ddd8eeSStefano Zampini     /* Matrix for Neumann problem is A_RR -> we need to create/reuse it at this point */
59019566063dSJacob Faibussowitsch     PetscCall(ISGetSize(pcbddc->is_R_local, &n_R));
5902f4ddd8eeSStefano Zampini     if (pcbddc->ksp_R) { /* already created ksp */
5903f4ddd8eeSStefano Zampini       PetscInt nn_R;
59049566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(pcbddc->ksp_R, NULL, &A_RR));
59059566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)A_RR));
59069566063dSJacob Faibussowitsch       PetscCall(MatGetSize(A_RR, &nn_R, NULL));
5907f4ddd8eeSStefano Zampini       if (nn_R != n_R) { /* old ksp is not reusable, so reset it */
59089566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->ksp_R));
59099566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5910f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5911f4ddd8eeSStefano Zampini       } else {                                /* same sizes, but nonzero pattern depend on primal vertices so it can be changed */
5912727cdba6SStefano Zampini         if (pcbddc->new_primal_space_local) { /* we are not sure the matrix will have the same nonzero pattern */
59139566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&A_RR));
5914f4ddd8eeSStefano Zampini           reuse = MAT_INITIAL_MATRIX;
5915f4ddd8eeSStefano Zampini         } else { /* safe to reuse the matrix */
5916f4ddd8eeSStefano Zampini           reuse = MAT_REUSE_MATRIX;
5917f4ddd8eeSStefano Zampini         }
5918f4ddd8eeSStefano Zampini       }
5919f4ddd8eeSStefano Zampini       /* last check */
5920d1e9a80fSBarry Smith       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
59219566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5922f4ddd8eeSStefano Zampini         reuse = MAT_INITIAL_MATRIX;
5923f4ddd8eeSStefano Zampini       }
5924f4ddd8eeSStefano Zampini     } else { /* first time, so we need to create the matrix */
5925f4ddd8eeSStefano Zampini       reuse = MAT_INITIAL_MATRIX;
5926f4ddd8eeSStefano Zampini     }
5927365a3a41SStefano Zampini     /* convert pcbddc->local_mat if needed later in PCBDDCSetUpCorrection
5928365a3a41SStefano Zampini        TODO: Get Rid of these conversions */
59299566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(pcbddc->local_mat, &mbs));
59309566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(pcbddc->is_R_local, &ibs));
59319566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->local_mat, MATSEQSBAIJ, &issbaij));
593204708bb6SStefano Zampini     if (ibs != mbs) { /* need to convert to SEQAIJ to extract any submatrix with is_R_local */
593304708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
59349566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
59359566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
5936af732b37SStefano Zampini       } else {
59379566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
59386816873aSStefano Zampini       }
59394cf0e950SBarry Smith     } else if (issbaij) { /* need to convert to BAIJ to get off-diagonal blocks */
594004708bb6SStefano Zampini       if (matis->A == pcbddc->local_mat) {
59419566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&pcbddc->local_mat));
59429566063dSJacob Faibussowitsch         PetscCall(MatConvert(matis->A, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INITIAL_MATRIX, &pcbddc->local_mat));
594304708bb6SStefano Zampini       } else {
59449566063dSJacob Faibussowitsch         PetscCall(MatConvert(pcbddc->local_mat, mbs > 1 ? MATSEQBAIJ : MATSEQAIJ, MAT_INPLACE_MATRIX, &pcbddc->local_mat));
594504708bb6SStefano Zampini       }
594604708bb6SStefano Zampini     }
5947a00504b5SStefano Zampini     /* extract A_RR */
59480aa714b2SStefano Zampini     if (reuse_neumann_solver) {
5949a00504b5SStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
5950a00504b5SStefano Zampini 
5951a00504b5SStefano Zampini       if (pcbddc->dbg_flag) { /* we need A_RR to test the solver later */
59529566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
5953a00504b5SStefano Zampini         if (reuse_solver->benign_n) { /* we are not using the explicit change of basis on the pressures */
59549566063dSJacob Faibussowitsch           PetscCall(PCBDDCBenignProject(pc, pcbddc->is_R_local, pcbddc->is_R_local, &A_RR));
595516e386b8SStefano Zampini         } else {
59569566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, MAT_INITIAL_MATRIX, &A_RR));
5957a00504b5SStefano Zampini         }
5958a00504b5SStefano Zampini       } else {
59599566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&A_RR));
59609566063dSJacob Faibussowitsch         PetscCall(PCGetOperators(reuse_solver->correction_solver, &A_RR, NULL));
59619566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A_RR));
5962a00504b5SStefano Zampini       }
5963a00504b5SStefano Zampini     } else { /* we have to build the neumann solver, so we need to extract the relevant matrix */
59649566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcbddc->is_R_local, pcbddc->is_R_local, reuse, &A_RR));
596516e386b8SStefano Zampini     }
5966b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pcbddc->local_mat, &isset, &issym));
5967b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(A_RR, MAT_SYMMETRIC, issym));
596892cccca0SStefano Zampini     opts = PETSC_FALSE;
5969f4ddd8eeSStefano Zampini     if (!pcbddc->ksp_R) { /* create object if not present */
597092cccca0SStefano Zampini       opts = PETSC_TRUE;
59719566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &pcbddc->ksp_R));
59723821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->ksp_R, pc->kspnestlevel));
59739566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->ksp_R, (PetscObject)pc, 1));
5974304d26faSStefano Zampini       /* default */
59759566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->ksp_R, KSPPREONLY));
59769566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->ksp_R, neu_prefix));
59779566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
59789566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)A_RR, MATSEQSBAIJ, &issbaij));
59799577ea80SStefano Zampini       if (issbaij) {
59809566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCCHOLESKY));
59819577ea80SStefano Zampini       } else {
59829566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCLU));
59839577ea80SStefano Zampini       }
59849566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->ksp_R, pc->erroriffailure));
598592cccca0SStefano Zampini     }
59869566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(A_RR, ((PetscObject)pcbddc->ksp_R)->prefix));
59879de2952eSStefano Zampini     PetscCall(MatViewFromOptions(A_RR, NULL, "-mat_view"));
59889de2952eSStefano Zampini     PetscCall(KSPSetOperators(pcbddc->ksp_R, A_RR, A_RR));
598992cccca0SStefano Zampini     if (opts) { /* Allow user's customization once */
59909566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->ksp_R));
599192cccca0SStefano Zampini     }
59929566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
59936d9e27e4SStefano Zampini     if (pcbddc->NullSpace_corr[2] && !nnsp) { /* approximate solver, propagate NearNullSpace */
59949566063dSJacob Faibussowitsch       PetscCall(MatNullSpacePropagateAny_Private(pcbddc->local_mat, pcbddc->is_R_local, A_RR));
599592cccca0SStefano Zampini     }
59969566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(A_RR, &nnsp));
59979566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
59989566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)pc_temp, "PCSetCoordinates_C", &f));
599992cccca0SStefano Zampini     if (f && pcbddc->mat_graph->cloc && !nnsp) {
6000cd18cfedSStefano Zampini       PetscReal      *coords = pcbddc->mat_graph->coords, *scoords;
6001cd18cfedSStefano Zampini       const PetscInt *idxs;
6002cd18cfedSStefano Zampini       PetscInt        cdim = pcbddc->mat_graph->cdim, nl, i, d;
6003cd18cfedSStefano Zampini 
60049566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->is_R_local, &nl));
60059566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->is_R_local, &idxs));
60069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl * cdim, &scoords));
6007cd18cfedSStefano Zampini       for (i = 0; i < nl; i++) {
6008ad540459SPierre Jolivet         for (d = 0; d < cdim; d++) scoords[i * cdim + d] = coords[idxs[i] * cdim + d];
6009cd18cfedSStefano Zampini       }
60109566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->is_R_local, &idxs));
60119566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_temp, cdim, nl, scoords));
60129566063dSJacob Faibussowitsch       PetscCall(PetscFree(scoords));
6013cd18cfedSStefano Zampini     }
601492cccca0SStefano Zampini 
6015304d26faSStefano Zampini     /* umfpack interface has a bug when matrix dimension is zero. TODO solve from umfpack interface */
6016304d26faSStefano Zampini     if (!n_R) {
60179566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->ksp_R, &pc_temp));
60189566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, PCNONE));
6019304d26faSStefano Zampini     }
6020df4d28bfSStefano Zampini     /* Reuse solver if it is present */
60210aa714b2SStefano Zampini     if (reuse_neumann_solver) {
6022df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6023d62866d3SStefano Zampini 
60249566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(pcbddc->ksp_R, reuse_solver->correction_solver));
6025d62866d3SStefano Zampini     }
60269566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->ksp_R));
6027684f6988SStefano Zampini   }
6028304d26faSStefano Zampini 
6029684f6988SStefano Zampini   if (pcbddc->dbg_flag) {
60309566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
60319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
60329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
6033684f6988SStefano Zampini   }
60349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_LocalSolvers[pcbddc->current_level], pc, 0, 0, 0));
6035c7017625SStefano Zampini 
6036c7017625SStefano Zampini   /* adapt Dirichlet and Neumann solvers if a nullspace correction has been requested */
603748a46eb9SPierre Jolivet   if (pcbddc->NullSpace_corr[0]) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
603848a46eb9SPierre Jolivet   if (dirichlet && pcbddc->NullSpace_corr[0] && !pcbddc->switch_static) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_TRUE, pcbddc->NullSpace_corr[1]));
603948a46eb9SPierre Jolivet   if (neumann && pcbddc->NullSpace_corr[2]) PetscCall(PCBDDCNullSpaceAssembleCorrection(pc, PETSC_FALSE, pcbddc->NullSpace_corr[3]));
6040c7017625SStefano Zampini   /* check Dirichlet and Neumann solvers */
6041c7017625SStefano Zampini   if (pcbddc->dbg_flag) {
6042684f6988SStefano Zampini     if (dirichlet) { /* Dirichlet */
60439566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcis->vec1_D, NULL));
60449566063dSJacob Faibussowitsch       PetscCall(MatMult(pcis->A_II, pcis->vec1_D, pcis->vec2_D));
60459566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec2_D, pcis->vec2_D));
60469566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
60479566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcis->vec1_D, m_one, pcis->vec2_D));
60489566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcis->vec1_D, NORM_INFINITY, &value));
6049f4f49eeaSPierre Jolivet       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Dirichlet solve (%s) = % 1.14e \n", PetscGlobalRank, ((PetscObject)pcbddc->ksp_D)->prefix, (double)value));
60509566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6051304d26faSStefano Zampini     }
6052684f6988SStefano Zampini     if (neumann) { /* Neumann */
60539566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(pcbddc->vec1_R, NULL));
60549566063dSJacob Faibussowitsch       PetscCall(MatMult(A_RR, pcbddc->vec1_R, pcbddc->vec2_R));
60559566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec2_R, pcbddc->vec2_R));
60569566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec2_R));
60579566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pcbddc->vec1_R, m_one, pcbddc->vec2_R));
60589566063dSJacob Faibussowitsch       PetscCall(VecNorm(pcbddc->vec1_R, NORM_INFINITY, &value));
6059f4f49eeaSPierre Jolivet       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d infinity error for Neumann solve (%s) = % 1.14e\n", PetscGlobalRank, ((PetscObject)pcbddc->ksp_R)->prefix, (double)value));
60609566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
6061304d26faSStefano Zampini     }
6062684f6988SStefano Zampini   }
60635cbda25cSStefano Zampini   /* free Neumann problem's matrix */
60649566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A_RR));
60653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6066304d26faSStefano Zampini }
6067304d26faSStefano Zampini 
6068d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBDDCSolveSubstructureCorrection(PC pc, Vec inout_B, Vec inout_D, PetscBool applytranspose)
6069d71ae5a4SJacob Faibussowitsch {
6070f4f49eeaSPierre Jolivet   PC_BDDC        *pcbddc       = (PC_BDDC *)pc->data;
6071be83ff47SStefano Zampini   PCBDDCSubSchurs sub_schurs   = pcbddc->sub_schurs;
6072b334f244SStefano Zampini   PetscBool       reuse_solver = sub_schurs ? (sub_schurs->reuse_solver ? PETSC_TRUE : PETSC_FALSE) : PETSC_FALSE;
6073674ae819SStefano Zampini 
6074674ae819SStefano Zampini   PetscFunctionBegin;
607548a46eb9SPierre Jolivet   if (!reuse_solver) PetscCall(VecSet(pcbddc->vec1_R, 0.));
607680677318SStefano Zampini   if (!pcbddc->switch_static) {
607780677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
60789566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, inout_B, pcbddc->vec1_C));
60799566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
608020c7b377SStefano Zampini     }
6081b334f244SStefano Zampini     if (!reuse_solver) {
60829566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
60839566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
608420c7b377SStefano Zampini     } else {
6085df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6086be83ff47SStefano Zampini 
60879566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
60889566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, inout_B, reuse_solver->rhs_B, INSERT_VALUES, SCATTER_FORWARD));
608920c7b377SStefano Zampini     }
6090be83ff47SStefano Zampini   } else {
60919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
60929566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
60939566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
60949566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, inout_D, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
609580677318SStefano Zampini     if (applytranspose && pcbddc->local_auxmat1) {
60969566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->local_auxmat2, pcbddc->vec1_R, pcbddc->vec1_C));
60979566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(pcbddc->local_auxmat1, pcbddc->vec1_C, inout_B, inout_B));
60989566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
60999566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, inout_B, pcbddc->vec1_R, INSERT_VALUES, SCATTER_REVERSE));
6100674ae819SStefano Zampini     }
6101674ae819SStefano Zampini   }
61029566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
6103b334f244SStefano Zampini   if (!reuse_solver || pcbddc->switch_static) {
610480677318SStefano Zampini     if (applytranspose) {
61059566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
610680677318SStefano Zampini     } else {
61079566063dSJacob Faibussowitsch       PetscCall(KSPSolve(pcbddc->ksp_R, pcbddc->vec1_R, pcbddc->vec1_R));
610880677318SStefano Zampini     }
61099566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(pcbddc->ksp_R, pc, pcbddc->vec1_R));
6110be83ff47SStefano Zampini   } else {
6111df4d28bfSStefano Zampini     PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6112be83ff47SStefano Zampini 
6113be83ff47SStefano Zampini     if (applytranspose) {
61149566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplementTranspose(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6115be83ff47SStefano Zampini     } else {
61169566063dSJacob Faibussowitsch       PetscCall(MatFactorSolveSchurComplement(reuse_solver->F, reuse_solver->rhs_B, reuse_solver->sol_B));
6117be83ff47SStefano Zampini     }
6118be83ff47SStefano Zampini   }
61199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][1], pc, 0, 0, 0));
61209566063dSJacob Faibussowitsch   PetscCall(VecSet(inout_B, 0.));
612180677318SStefano Zampini   if (!pcbddc->switch_static) {
6122b334f244SStefano Zampini     if (!reuse_solver) {
61239566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61249566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
6125be83ff47SStefano Zampini     } else {
6126df4d28bfSStefano Zampini       PCBDDCReuseSolvers reuse_solver = sub_schurs->reuse_solver;
6127be83ff47SStefano Zampini 
61289566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
61299566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(reuse_solver->correction_scatter_B, reuse_solver->sol_B, inout_B, INSERT_VALUES, SCATTER_REVERSE));
6130be83ff47SStefano Zampini     }
613180677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
61329566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
61339566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, inout_B, inout_B));
613480677318SStefano Zampini     }
613580677318SStefano Zampini   } else {
61369566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61379566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61389566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
61399566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
614080677318SStefano Zampini     if (!applytranspose && pcbddc->local_auxmat1) {
61419566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->local_auxmat1, inout_B, pcbddc->vec1_C));
61429566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->local_auxmat2, pcbddc->vec1_C, pcbddc->vec1_R, pcbddc->vec1_R));
614380677318SStefano Zampini     }
61449566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61459566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_B, pcbddc->vec1_R, inout_B, INSERT_VALUES, SCATTER_FORWARD));
61469566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
61479566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->R_to_D, pcbddc->vec1_R, inout_D, INSERT_VALUES, SCATTER_FORWARD));
6148674ae819SStefano Zampini   }
61493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6150674ae819SStefano Zampini }
6151674ae819SStefano Zampini 
6152dc359a40SStefano Zampini /* parameter apply transpose determines if the interface preconditioner should be applied transposed or not */
6153d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCApplyInterfacePreconditioner(PC pc, PetscBool applytranspose)
6154d71ae5a4SJacob Faibussowitsch {
6155f4f49eeaSPierre Jolivet   PC_BDDC          *pcbddc = (PC_BDDC *)pc->data;
6156f4f49eeaSPierre Jolivet   PC_IS            *pcis   = (PC_IS *)pc->data;
6157674ae819SStefano Zampini   const PetscScalar zero   = 0.0;
6158674ae819SStefano Zampini 
6159674ae819SStefano Zampini   PetscFunctionBegin;
6160dc359a40SStefano Zampini   /* Application of PSI^T or PHI^T (depending on applytranspose, see comment above) */
61614fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6162dc359a40SStefano Zampini     if (applytranspose) {
61639566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, pcis->vec1_B, pcbddc->vec1_P));
61649566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_phi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
6165dc359a40SStefano Zampini     } else {
61669566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(pcbddc->coarse_psi_B, pcis->vec1_B, pcbddc->vec1_P));
61679566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultTransposeAdd(pcbddc->coarse_psi_D, pcis->vec1_D, pcbddc->vec1_P, pcbddc->vec1_P));
616815aaf578SStefano Zampini     }
61694fee134fSStefano Zampini   } else {
61709566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, zero));
61714fee134fSStefano Zampini   }
6172efc2fbd9SStefano Zampini 
6173efc2fbd9SStefano Zampini   /* add p0 to the last value of vec1_P holding the coarse dof relative to p0 */
61744f1b2e48SStefano Zampini   if (pcbddc->benign_n) {
6175efc2fbd9SStefano Zampini     PetscScalar *array;
61764f1b2e48SStefano Zampini     PetscInt     j;
6177efc2fbd9SStefano Zampini 
61789566063dSJacob Faibussowitsch     PetscCall(VecGetArray(pcbddc->vec1_P, &array));
61794f1b2e48SStefano Zampini     for (j = 0; j < pcbddc->benign_n; j++) array[pcbddc->local_primal_size - pcbddc->benign_n + j] += pcbddc->benign_p0[j];
61809566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6181efc2fbd9SStefano Zampini   }
6182efc2fbd9SStefano Zampini 
618312edc857SStefano Zampini   /* start communications from local primal nodes to rhs of coarse solver */
61849566063dSJacob Faibussowitsch   PetscCall(VecSet(pcbddc->coarse_vec, zero));
61859566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, ADD_VALUES, SCATTER_FORWARD));
61869566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, ADD_VALUES, SCATTER_FORWARD));
618712edc857SStefano Zampini 
61889f00e9b4SStefano Zampini   /* Coarse solution -> rhs and sol updated inside PCBDDCScattarCoarseDataBegin/End */
6189a1cb837bSStefano Zampini   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
619012edc857SStefano Zampini   if (pcbddc->coarse_ksp) {
619151694757SStefano Zampini     Mat          coarse_mat;
6192964fefecSStefano Zampini     Vec          rhs, sol;
619351694757SStefano Zampini     MatNullSpace nullsp;
619427b6a85dSStefano Zampini     PetscBool    isbddc = PETSC_FALSE;
6195964fefecSStefano Zampini 
619627b6a85dSStefano Zampini     if (pcbddc->benign_have_null) {
619727b6a85dSStefano Zampini       PC coarse_pc;
619827b6a85dSStefano Zampini 
61999566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
62009566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
620127b6a85dSStefano Zampini       /* we need to propagate to coarser levels the need for a possible benign correction */
620227b6a85dSStefano Zampini       if (isbddc && pcbddc->benign_apply_coarse_only && !pcbddc->benign_skip_correction) {
6203f4f49eeaSPierre Jolivet         PC_BDDC *coarsepcbddc                  = (PC_BDDC *)coarse_pc->data;
620427b6a85dSStefano Zampini         coarsepcbddc->benign_skip_correction   = PETSC_FALSE;
62053bca92a6SStefano Zampini         coarsepcbddc->benign_apply_coarse_only = PETSC_TRUE;
620627b6a85dSStefano Zampini       }
620727b6a85dSStefano Zampini     }
62089566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &rhs));
62099566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &sol));
62109566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
621112edc857SStefano Zampini     if (applytranspose) {
621228b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->benign_apply_coarse_only, PetscObjectComm((PetscObject)pcbddc->coarse_ksp), PETSC_ERR_SUP, "Not yet implemented");
62139566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(pcbddc->coarse_ksp, rhs, sol));
62149566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
62159566063dSJacob Faibussowitsch       PetscCall(MatGetTransposeNullSpace(coarse_mat, &nullsp));
62161baa6e33SBarry Smith       if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
62172701bc32SStefano Zampini     } else {
62189566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(coarse_mat, &nullsp));
62191f4df5f7SStefano Zampini       if (pcbddc->benign_apply_coarse_only && isbddc) { /* need just to apply the coarse preconditioner during presolve */
62202701bc32SStefano Zampini         PC coarse_pc;
62212701bc32SStefano Zampini 
62221baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, rhs));
62239566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
62249566063dSJacob Faibussowitsch         PetscCall(PCPreSolve(coarse_pc, pcbddc->coarse_ksp));
62259566063dSJacob Faibussowitsch         PetscCall(PCBDDCBenignRemoveInterior(coarse_pc, rhs, sol));
62269566063dSJacob Faibussowitsch         PetscCall(PCPostSolve(coarse_pc, pcbddc->coarse_ksp));
622712edc857SStefano Zampini       } else {
62289566063dSJacob Faibussowitsch         PetscCall(KSPSolve(pcbddc->coarse_ksp, rhs, sol));
62299566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(pcbddc->coarse_ksp, pc, sol));
62301baa6e33SBarry Smith         if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, sol));
623112edc857SStefano Zampini       }
62322701bc32SStefano Zampini     }
62331d82a3b6SStefano Zampini     /* we don't need the benign correction at coarser levels anymore */
623427b6a85dSStefano Zampini     if (pcbddc->benign_have_null && isbddc) {
623527b6a85dSStefano Zampini       PC       coarse_pc;
623627b6a85dSStefano Zampini       PC_BDDC *coarsepcbddc;
623727b6a85dSStefano Zampini 
62389566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
6239f4f49eeaSPierre Jolivet       coarsepcbddc                           = (PC_BDDC *)coarse_pc->data;
624027b6a85dSStefano Zampini       coarsepcbddc->benign_skip_correction   = PETSC_TRUE;
62413bca92a6SStefano Zampini       coarsepcbddc->benign_apply_coarse_only = PETSC_FALSE;
624227b6a85dSStefano Zampini     }
624312edc857SStefano Zampini   }
6244a1cb837bSStefano Zampini   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][2], pc, 0, 0, 0));
6245674ae819SStefano Zampini 
6246674ae819SStefano Zampini   /* Local solution on R nodes */
6247a1cb837bSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCSolveSubstructureCorrection(pc, pcis->vec1_B, pcis->vec1_D, applytranspose));
62489f00e9b4SStefano Zampini   /* communications from coarse sol to local primal nodes */
62499566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataBegin(pc, INSERT_VALUES, SCATTER_REVERSE));
62509566063dSJacob Faibussowitsch   PetscCall(PCBDDCScatterCoarseDataEnd(pc, INSERT_VALUES, SCATTER_REVERSE));
6251674ae819SStefano Zampini 
62524fee134fSStefano Zampini   /* Sum contributions from the two levels */
62534fee134fSStefano Zampini   if (!pcbddc->benign_apply_coarse_only) {
6254dc359a40SStefano Zampini     if (applytranspose) {
62559566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
62569566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_psi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6257dc359a40SStefano Zampini     } else {
62589566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B, pcis->vec1_B));
62599566063dSJacob Faibussowitsch       if (pcbddc->switch_static) PetscCall(MatMultAdd(pcbddc->coarse_phi_D, pcbddc->vec1_P, pcis->vec1_D, pcis->vec1_D));
6260dc359a40SStefano Zampini     }
6261efc2fbd9SStefano Zampini     /* store p0 */
62624f1b2e48SStefano Zampini     if (pcbddc->benign_n) {
6263efc2fbd9SStefano Zampini       PetscScalar *array;
62644f1b2e48SStefano Zampini       PetscInt     j;
6265efc2fbd9SStefano Zampini 
62669566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pcbddc->vec1_P, &array));
62674f1b2e48SStefano Zampini       for (j = 0; j < pcbddc->benign_n; j++) pcbddc->benign_p0[j] = array[pcbddc->local_primal_size - pcbddc->benign_n + j];
62689566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pcbddc->vec1_P, &array));
6269efc2fbd9SStefano Zampini     }
62704fee134fSStefano Zampini   } else { /* expand the coarse solution */
62714fee134fSStefano Zampini     if (applytranspose) {
62729566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_psi_B, pcbddc->vec1_P, pcis->vec1_B));
62734fee134fSStefano Zampini     } else {
62749566063dSJacob Faibussowitsch       PetscCall(MatMult(pcbddc->coarse_phi_B, pcbddc->vec1_P, pcis->vec1_B));
62754fee134fSStefano Zampini     }
62764fee134fSStefano Zampini   }
62773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6278674ae819SStefano Zampini }
6279674ae819SStefano Zampini 
6280d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataBegin(PC pc, InsertMode imode, ScatterMode smode)
6281d71ae5a4SJacob Faibussowitsch {
6282f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
628312edc857SStefano Zampini   Vec                from, to;
62847ebab0bbSStefano Zampini   const PetscScalar *array;
6285674ae819SStefano Zampini 
6286674ae819SStefano Zampini   PetscFunctionBegin;
628712edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
628812edc857SStefano Zampini     from = pcbddc->coarse_vec;
628912edc857SStefano Zampini     to   = pcbddc->vec1_P;
629012edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
629112edc857SStefano Zampini       Vec tvec;
629258da7f69SStefano Zampini 
62939566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
62949566063dSJacob Faibussowitsch       PetscCall(VecResetArray(tvec));
62959566063dSJacob Faibussowitsch       PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &tvec));
62969566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(tvec, &array));
62979566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(from, array));
62989566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(tvec, &array));
629912edc857SStefano Zampini     }
6300dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
630112edc857SStefano Zampini     from = pcbddc->vec1_P;
630212edc857SStefano Zampini     to   = pcbddc->coarse_vec;
630312edc857SStefano Zampini   }
63049566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
63053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6306674ae819SStefano Zampini }
6307674ae819SStefano Zampini 
6308d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCScatterCoarseDataEnd(PC pc, InsertMode imode, ScatterMode smode)
6309d71ae5a4SJacob Faibussowitsch {
6310f4f49eeaSPierre Jolivet   PC_BDDC           *pcbddc = (PC_BDDC *)pc->data;
631112edc857SStefano Zampini   Vec                from, to;
63127ebab0bbSStefano Zampini   const PetscScalar *array;
6313674ae819SStefano Zampini 
6314674ae819SStefano Zampini   PetscFunctionBegin;
631512edc857SStefano Zampini   if (smode == SCATTER_REVERSE) { /* from global to local -> get data from coarse solution */
631612edc857SStefano Zampini     from = pcbddc->coarse_vec;
631712edc857SStefano Zampini     to   = pcbddc->vec1_P;
6318dd8e379bSPierre Jolivet   } else { /* from local to global -> put data in coarse right-hand side */
631912edc857SStefano Zampini     from = pcbddc->vec1_P;
632012edc857SStefano Zampini     to   = pcbddc->coarse_vec;
632112edc857SStefano Zampini   }
63229566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, from, to, imode, smode));
632312edc857SStefano Zampini   if (smode == SCATTER_FORWARD) {
632412edc857SStefano Zampini     if (pcbddc->coarse_ksp) { /* get array from coarse processes */
632512edc857SStefano Zampini       Vec tvec;
632658da7f69SStefano Zampini 
63279566063dSJacob Faibussowitsch       PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &tvec));
63289566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(to, &array));
63299566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(tvec, array));
63309566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(to, &array));
633158da7f69SStefano Zampini     }
633258da7f69SStefano Zampini   } else {
633358da7f69SStefano Zampini     if (pcbddc->coarse_ksp) { /* restore array of pcbddc->coarse_vec */
63349566063dSJacob Faibussowitsch       PetscCall(VecResetArray(from));
633512edc857SStefano Zampini     }
633612edc857SStefano Zampini   }
63373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6338674ae819SStefano Zampini }
6339674ae819SStefano Zampini 
6340d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCConstraintsSetUp(PC pc)
6341d71ae5a4SJacob Faibussowitsch {
6342f4f49eeaSPierre Jolivet   PC_IS   *pcis   = (PC_IS *)pc->data;
6343674ae819SStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
6344674ae819SStefano Zampini   Mat_IS  *matis  = (Mat_IS *)pc->pmat->data;
6345984c4197SStefano Zampini   /* one and zero */
6346984c4197SStefano Zampini   PetscScalar one = 1.0, zero = 0.0;
6347984c4197SStefano Zampini   /* space to store constraints and their local indices */
63489162d606SStefano Zampini   PetscScalar *constraints_data;
63499162d606SStefano Zampini   PetscInt    *constraints_idxs, *constraints_idxs_B;
63509162d606SStefano Zampini   PetscInt    *constraints_idxs_ptr, *constraints_data_ptr;
63519162d606SStefano Zampini   PetscInt    *constraints_n;
6352984c4197SStefano Zampini   /* iterators */
6353b3d85658SStefano Zampini   PetscInt i, j, k, total_counts, total_counts_cc, cum;
6354984c4197SStefano Zampini   /* BLAS integers */
6355e310c8b4SStefano Zampini   PetscBLASInt lwork, lierr;
6356e310c8b4SStefano Zampini   PetscBLASInt Blas_N, Blas_M, Blas_K, Blas_one = 1;
6357c4303822SStefano Zampini   PetscBLASInt Blas_LDA, Blas_LDB, Blas_LDC;
6358727cdba6SStefano Zampini   /* reuse */
63590e6343abSStefano Zampini   PetscInt  olocal_primal_size, olocal_primal_size_cc;
63600e6343abSStefano Zampini   PetscInt *olocal_primal_ref_node, *olocal_primal_ref_mult;
6361984c4197SStefano Zampini   /* change of basis */
6362b3d85658SStefano Zampini   PetscBool qr_needed;
63639162d606SStefano Zampini   PetscBT   change_basis, qr_needed_idx;
6364984c4197SStefano Zampini   /* auxiliary stuff */
636564efe560SStefano Zampini   PetscInt *nnz, *is_indices;
63668a0068c3SStefano Zampini   PetscInt  ncc;
6367984c4197SStefano Zampini   /* some quantities */
636845a1bb75SStefano Zampini   PetscInt  n_vertices, total_primal_vertices, valid_constraints;
6369a58a30b4SStefano Zampini   PetscInt  size_of_constraint, max_size_of_constraint = 0, max_constraints, temp_constraints;
637057715f18SStefano Zampini   PetscReal tol; /* tolerance for retaining eigenmodes */
6371984c4197SStefano Zampini 
6372674ae819SStefano Zampini   PetscFunctionBegin;
637357715f18SStefano Zampini   tol = PetscSqrtReal(PETSC_SMALL);
63748e61c736SStefano Zampini   /* Destroy Mat objects computed previously */
63759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ChangeOfBasisMatrix));
63769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
63779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pcbddc->switch_static_change));
6378088faed8SStefano Zampini   /* save info on constraints from previous setup (if any) */
6379088faed8SStefano Zampini   olocal_primal_size    = pcbddc->local_primal_size;
63800e6343abSStefano Zampini   olocal_primal_size_cc = pcbddc->local_primal_size_cc;
63819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(olocal_primal_size_cc, &olocal_primal_ref_node, olocal_primal_size_cc, &olocal_primal_ref_mult));
63829566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_node, pcbddc->local_primal_ref_node, olocal_primal_size_cc));
63839566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(olocal_primal_ref_mult, pcbddc->local_primal_ref_mult, olocal_primal_size_cc));
63849566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pcbddc->local_primal_ref_node, pcbddc->local_primal_ref_mult));
63859566063dSJacob Faibussowitsch   PetscCall(PetscFree(pcbddc->primal_indices_local_idxs));
6386cf5a6209SStefano Zampini 
6387cf5a6209SStefano Zampini   if (!pcbddc->adaptive_selection) {
63889162d606SStefano Zampini     IS           ISForVertices, *ISForFaces, *ISForEdges;
6389cf5a6209SStefano Zampini     MatNullSpace nearnullsp;
6390cf5a6209SStefano Zampini     const Vec   *nearnullvecs;
6391cf5a6209SStefano Zampini     Vec         *localnearnullsp;
6392cf5a6209SStefano Zampini     PetscScalar *array;
639332fe681dSStefano Zampini     PetscInt     n_ISForFaces, n_ISForEdges, nnsp_size, o_nf, o_ne;
6394cf5a6209SStefano Zampini     PetscBool    nnsp_has_cnst;
6395674ae819SStefano Zampini     /* LAPACK working arrays for SVD or POD */
6396b3d85658SStefano Zampini     PetscBool    skip_lapack, boolforchange;
6397674ae819SStefano Zampini     PetscScalar *work;
6398674ae819SStefano Zampini     PetscReal   *singular_vals;
6399674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
6400674ae819SStefano Zampini     PetscReal *rwork;
6401674ae819SStefano Zampini #endif
640255080a34SStefano Zampini     PetscScalar *temp_basis = NULL, *correlation_mat = NULL;
6403964fefecSStefano Zampini     PetscBLASInt dummy_int    = 1;
6404964fefecSStefano Zampini     PetscScalar  dummy_scalar = 1.;
640555080a34SStefano Zampini     PetscBool    use_pod      = PETSC_FALSE;
6406674ae819SStefano Zampini 
640755080a34SStefano Zampini     /* MKL SVD with same input gives different results on different processes! */
6408b88df2e7SBarry Smith #if defined(PETSC_MISSING_LAPACK_GESVD) || defined(PETSC_HAVE_MKL_LIBS)
640955080a34SStefano Zampini     use_pod = PETSC_TRUE;
641055080a34SStefano Zampini #endif
6411674ae819SStefano Zampini     /* Get index sets for faces, edges and vertices from graph */
64129566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, &n_ISForFaces, &ISForFaces, &n_ISForEdges, &ISForEdges, &ISForVertices));
641332fe681dSStefano Zampini     o_nf       = n_ISForFaces;
641432fe681dSStefano Zampini     o_ne       = n_ISForEdges;
641532fe681dSStefano Zampini     n_vertices = 0;
641632fe681dSStefano Zampini     if (ISForVertices) PetscCall(ISGetSize(ISForVertices, &n_vertices));
6417e4d548c7SStefano Zampini     /* print some info */
64185c643e28SStefano Zampini     if (pcbddc->dbg_flag && (!pcbddc->sub_schurs || pcbddc->sub_schurs_rebuild)) {
641932fe681dSStefano Zampini       if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
64209566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphASCIIView(pcbddc->mat_graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
64219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
64229566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
642332fe681dSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, n_vertices, pcbddc->use_vertices));
642463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, n_ISForEdges, pcbddc->use_edges));
642563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, n_ISForFaces, pcbddc->use_faces));
64269566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
64279566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
6428e4d548c7SStefano Zampini     }
6429e4d548c7SStefano Zampini 
643032fe681dSStefano Zampini     if (!pcbddc->use_vertices) n_vertices = 0;
643132fe681dSStefano Zampini     if (!pcbddc->use_edges) n_ISForEdges = 0;
643232fe681dSStefano Zampini     if (!pcbddc->use_faces) n_ISForFaces = 0;
643370022509SStefano Zampini 
6434674ae819SStefano Zampini     /* check if near null space is attached to global mat */
64356d9e27e4SStefano Zampini     if (pcbddc->use_nnsp) {
64369566063dSJacob Faibussowitsch       PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullsp));
64376d9e27e4SStefano Zampini     } else nearnullsp = NULL;
64386d9e27e4SStefano Zampini 
6439674ae819SStefano Zampini     if (nearnullsp) {
64409566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceGetVecs(nearnullsp, &nnsp_has_cnst, &nnsp_size, &nearnullvecs));
6441f4ddd8eeSStefano Zampini       /* remove any stored info */
64429566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&pcbddc->onearnullspace));
64439566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->onearnullvecs_state));
6444f4ddd8eeSStefano Zampini       /* store information for BDDC solver reuse */
64459566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)nearnullsp));
6446f4ddd8eeSStefano Zampini       pcbddc->onearnullspace = nearnullsp;
64479566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nnsp_size, &pcbddc->onearnullvecs_state));
644848a46eb9SPierre Jolivet       for (i = 0; i < nnsp_size; i++) PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &pcbddc->onearnullvecs_state[i]));
6449984c4197SStefano Zampini     } else { /* if near null space is not provided BDDC uses constants by default */
6450984c4197SStefano Zampini       nnsp_size     = 0;
6451674ae819SStefano Zampini       nnsp_has_cnst = PETSC_TRUE;
6452674ae819SStefano Zampini     }
6453984c4197SStefano Zampini     /* get max number of constraints on a single cc */
6454984c4197SStefano Zampini     max_constraints = nnsp_size;
6455984c4197SStefano Zampini     if (nnsp_has_cnst) max_constraints++;
6456984c4197SStefano Zampini 
6457674ae819SStefano Zampini     /*
6458674ae819SStefano Zampini          Evaluate maximum storage size needed by the procedure
64599162d606SStefano Zampini          - Indices for connected component i stored at "constraints_idxs + constraints_idxs_ptr[i]"
64609162d606SStefano Zampini          - Values for constraints on connected component i stored at "constraints_data + constraints_data_ptr[i]"
64619162d606SStefano Zampini          There can be multiple constraints per connected component
6462674ae819SStefano Zampini                                                                                                                                                            */
64639162d606SStefano Zampini     ncc = n_vertices + n_ISForFaces + n_ISForEdges;
64649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(ncc + 1, &constraints_idxs_ptr, ncc + 1, &constraints_data_ptr, ncc, &constraints_n));
64659162d606SStefano Zampini 
64669162d606SStefano Zampini     total_counts = n_ISForFaces + n_ISForEdges;
64679162d606SStefano Zampini     total_counts *= max_constraints;
6468674ae819SStefano Zampini     total_counts += n_vertices;
64699566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts, &change_basis));
64709162d606SStefano Zampini 
6471674ae819SStefano Zampini     total_counts           = 0;
6472674ae819SStefano Zampini     max_size_of_constraint = 0;
6473674ae819SStefano Zampini     for (i = 0; i < n_ISForEdges + n_ISForFaces; i++) {
64749162d606SStefano Zampini       IS used_is;
6475674ae819SStefano Zampini       if (i < n_ISForEdges) {
64769162d606SStefano Zampini         used_is = ISForEdges[i];
6477674ae819SStefano Zampini       } else {
64789162d606SStefano Zampini         used_is = ISForFaces[i - n_ISForEdges];
6479674ae819SStefano Zampini       }
64809566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &j));
6481674ae819SStefano Zampini       total_counts += j;
6482674ae819SStefano Zampini       max_size_of_constraint = PetscMax(j, max_size_of_constraint);
6483674ae819SStefano Zampini     }
64849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(total_counts * max_constraints + n_vertices, &constraints_data, total_counts + n_vertices, &constraints_idxs, total_counts + n_vertices, &constraints_idxs_B));
64859162d606SStefano Zampini 
6486984c4197SStefano Zampini     /* get local part of global near null space vectors */
64879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnsp_size, &localnearnullsp));
6488984c4197SStefano Zampini     for (k = 0; k < nnsp_size; k++) {
64899566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(pcis->vec1_N, &localnearnullsp[k]));
64909566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
64919566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, nearnullvecs[k], localnearnullsp[k], INSERT_VALUES, SCATTER_FORWARD));
6492984c4197SStefano Zampini     }
6493674ae819SStefano Zampini 
6494242a89d7SStefano Zampini     /* whether or not to skip lapack calls */
6495242a89d7SStefano Zampini     skip_lapack = PETSC_TRUE;
6496a773dcb8SStefano Zampini     if (n_ISForFaces + n_ISForEdges && max_constraints > 1 && !pcbddc->use_nnsp_true) skip_lapack = PETSC_FALSE;
6497242a89d7SStefano Zampini 
6498984c4197SStefano Zampini     /* First we issue queries to allocate optimal workspace for LAPACKgesvd (or LAPACKsyev if SVD is missing) */
6499a773dcb8SStefano Zampini     if (!skip_lapack) {
6500674ae819SStefano Zampini       PetscScalar temp_work;
6501911cabfeSStefano Zampini 
650255080a34SStefano Zampini       if (use_pod) {
6503984c4197SStefano Zampini         /* Proper Orthogonal Decomposition (POD) using the snapshot method */
65049566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints * max_constraints, &correlation_mat));
65059566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_constraints, &singular_vals));
65069566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(max_size_of_constraint * max_constraints, &temp_basis));
6507674ae819SStefano Zampini #if defined(PETSC_USE_COMPLEX)
65089566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(3 * max_constraints, &rwork));
6509674ae819SStefano Zampini #endif
6510674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
65119566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
65129566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_constraints, &Blas_LDA));
6513674ae819SStefano Zampini         lwork = -1;
65149566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6515674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6516792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, &lierr));
6517674ae819SStefano Zampini #else
6518792fecdfSBarry Smith         PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, &temp_work, &lwork, rwork, &lierr));
6519674ae819SStefano Zampini #endif
65209566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
652128b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to SYEV Lapack routine %d", (int)lierr);
652255080a34SStefano Zampini       } else {
652355080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
6524674ae819SStefano Zampini         /* SVD */
6525674ae819SStefano Zampini         PetscInt max_n, min_n;
6526674ae819SStefano Zampini         max_n = max_size_of_constraint;
6527984c4197SStefano Zampini         min_n = max_constraints;
6528984c4197SStefano Zampini         if (max_size_of_constraint < max_constraints) {
6529674ae819SStefano Zampini           min_n = max_size_of_constraint;
6530984c4197SStefano Zampini           max_n = max_constraints;
6531674ae819SStefano Zampini         }
65329566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(min_n, &singular_vals));
6533674ae819SStefano Zampini   #if defined(PETSC_USE_COMPLEX)
65349566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(5 * min_n, &rwork));
6535674ae819SStefano Zampini   #endif
6536674ae819SStefano Zampini         /* now we evaluate the optimal workspace using query with lwork=-1 */
6537674ae819SStefano Zampini         lwork = -1;
65389566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_M));
65399566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(min_n, &Blas_N));
65409566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(max_n, &Blas_LDA));
65419566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6542674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6543792fecdfSBarry 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));
6544674ae819SStefano Zampini   #else
6545792fecdfSBarry 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));
6546674ae819SStefano Zampini   #endif
65479566063dSJacob Faibussowitsch         PetscCall(PetscFPTrapPop());
654828b400f6SJacob Faibussowitsch         PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GESVD Lapack routine %d", (int)lierr);
654955080a34SStefano Zampini #else
655055080a34SStefano Zampini         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6551984c4197SStefano Zampini #endif /* on missing GESVD */
655255080a34SStefano Zampini       }
6553674ae819SStefano Zampini       /* Allocate optimal workspace */
65549566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(temp_work), &lwork));
65559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lwork, &work));
6556674ae819SStefano Zampini     }
6557674ae819SStefano Zampini     /* Now we can loop on constraining sets */
6558674ae819SStefano Zampini     total_counts            = 0;
65599162d606SStefano Zampini     constraints_idxs_ptr[0] = 0;
65609162d606SStefano Zampini     constraints_data_ptr[0] = 0;
6561674ae819SStefano Zampini     /* vertices */
65629162d606SStefano Zampini     if (n_vertices) {
65639566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(ISForVertices, (const PetscInt **)&is_indices));
65649566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(constraints_idxs, is_indices, n_vertices));
6565674ae819SStefano Zampini       for (i = 0; i < n_vertices; i++) {
65669162d606SStefano Zampini         constraints_n[total_counts]            = 1;
65679162d606SStefano Zampini         constraints_data[total_counts]         = 1.0;
65689162d606SStefano Zampini         constraints_idxs_ptr[total_counts + 1] = constraints_idxs_ptr[total_counts] + 1;
65699162d606SStefano Zampini         constraints_data_ptr[total_counts + 1] = constraints_data_ptr[total_counts] + 1;
6570674ae819SStefano Zampini         total_counts++;
6571674ae819SStefano Zampini       }
65729566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(ISForVertices, (const PetscInt **)&is_indices));
6573674ae819SStefano Zampini     }
6574984c4197SStefano Zampini 
6575674ae819SStefano Zampini     /* edges and faces */
65769162d606SStefano Zampini     total_counts_cc = total_counts;
6577911cabfeSStefano Zampini     for (ncc = 0; ncc < n_ISForEdges + n_ISForFaces; ncc++) {
65789162d606SStefano Zampini       IS        used_is;
65799162d606SStefano Zampini       PetscBool idxs_copied = PETSC_FALSE;
65809162d606SStefano Zampini 
6581911cabfeSStefano Zampini       if (ncc < n_ISForEdges) {
65829162d606SStefano Zampini         used_is       = ISForEdges[ncc];
6583984c4197SStefano Zampini         boolforchange = pcbddc->use_change_of_basis; /* change or not the basis on the edge */
6584674ae819SStefano Zampini       } else {
65859162d606SStefano Zampini         used_is       = ISForFaces[ncc - n_ISForEdges];
6586984c4197SStefano Zampini         boolforchange = (PetscBool)(pcbddc->use_change_of_basis && pcbddc->use_change_on_faces); /* change or not the basis on the face */
6587674ae819SStefano Zampini       }
6588674ae819SStefano Zampini       temp_constraints = 0; /* zero the number of constraints I have on this conn comp */
65899162d606SStefano Zampini 
65909566063dSJacob Faibussowitsch       PetscCall(ISGetSize(used_is, &size_of_constraint));
659132fe681dSStefano Zampini       if (!size_of_constraint) continue;
65929566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(used_is, (const PetscInt **)&is_indices));
6593674ae819SStefano Zampini       if (nnsp_has_cnst) {
65945b08dc53SStefano Zampini         PetscScalar quad_value;
65959162d606SStefano Zampini 
65969566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
65979162d606SStefano Zampini         idxs_copied = PETSC_TRUE;
65989162d606SStefano Zampini 
6599a773dcb8SStefano Zampini         if (!pcbddc->use_nnsp_true) {
6600674ae819SStefano Zampini           quad_value = (PetscScalar)(1.0 / PetscSqrtReal((PetscReal)size_of_constraint));
6601a773dcb8SStefano Zampini         } else {
6602a773dcb8SStefano Zampini           quad_value = 1.0;
6603a773dcb8SStefano Zampini         }
6604ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) constraints_data[constraints_data_ptr[total_counts_cc] + j] = quad_value;
66059162d606SStefano Zampini         temp_constraints++;
6606674ae819SStefano Zampini         total_counts++;
6607674ae819SStefano Zampini       }
6608674ae819SStefano Zampini       for (k = 0; k < nnsp_size; k++) {
6609984c4197SStefano Zampini         PetscReal    real_value;
66109162d606SStefano Zampini         PetscScalar *ptr_to_data;
66119162d606SStefano Zampini 
66129566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
66139162d606SStefano Zampini         ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc] + temp_constraints * size_of_constraint];
6614ad540459SPierre Jolivet         for (j = 0; j < size_of_constraint; j++) ptr_to_data[j] = array[is_indices[j]];
66159566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(localnearnullsp[k], (const PetscScalar **)&array));
6616984c4197SStefano Zampini         /* check if array is null on the connected component */
66179566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6618792fecdfSBarry Smith         PetscCallBLAS("BLASasum", real_value = BLASasum_(&Blas_N, ptr_to_data, &Blas_one));
661957715f18SStefano Zampini         if (real_value > tol * size_of_constraint) { /* keep indices and values */
6620674ae819SStefano Zampini           temp_constraints++;
6621674ae819SStefano Zampini           total_counts++;
66229162d606SStefano Zampini           if (!idxs_copied) {
66239566063dSJacob Faibussowitsch             PetscCall(PetscArraycpy(constraints_idxs + constraints_idxs_ptr[total_counts_cc], is_indices, size_of_constraint));
66249162d606SStefano Zampini             idxs_copied = PETSC_TRUE;
6625674ae819SStefano Zampini           }
6626674ae819SStefano Zampini         }
66279162d606SStefano Zampini       }
66289566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(used_is, (const PetscInt **)&is_indices));
662945a1bb75SStefano Zampini       valid_constraints = temp_constraints;
6630eb97c9d2SStefano Zampini       if (!pcbddc->use_nnsp_true && temp_constraints) {
6631a773dcb8SStefano Zampini         if (temp_constraints == 1) { /* just normalize the constraint */
66329162d606SStefano Zampini           PetscScalar norm, *ptr_to_data;
66339162d606SStefano Zampini 
66349162d606SStefano Zampini           ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
66359566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
6636792fecdfSBarry Smith           PetscCallBLAS("BLASdot", norm = BLASdot_(&Blas_N, ptr_to_data, &Blas_one, ptr_to_data, &Blas_one));
6637a773dcb8SStefano Zampini           norm = 1.0 / PetscSqrtReal(PetscRealPart(norm));
6638792fecdfSBarry Smith           PetscCallBLAS("BLASscal", BLASscal_(&Blas_N, &norm, ptr_to_data, &Blas_one));
6639a773dcb8SStefano Zampini         } else { /* perform SVD */
66409162d606SStefano Zampini           PetscScalar *ptr_to_data = &constraints_data[constraints_data_ptr[total_counts_cc]];
6641674ae819SStefano Zampini 
664255080a34SStefano Zampini           if (use_pod) {
6643984c4197SStefano Zampini             /* SVD: Y = U*S*V^H                -> U (eigenvectors of Y*Y^H) = Y*V*(S)^\dag
6644984c4197SStefano Zampini                POD: Y^H*Y = V*D*V^H, D = S^H*S -> U = Y*V*D^(-1/2)
6645984c4197SStefano Zampini                -> When PETSC_USE_COMPLEX and PETSC_MISSING_LAPACK_GESVD are defined
6646984c4197SStefano Zampini                   the constraints basis will differ (by a complex factor with absolute value equal to 1)
6647984c4197SStefano Zampini                   from that computed using LAPACKgesvd
6648984c4197SStefano Zampini                -> This is due to a different computation of eigenvectors in LAPACKheev
6649984c4197SStefano Zampini                -> The quality of the POD-computed basis will be the same */
66509566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(correlation_mat, temp_constraints * temp_constraints));
6651674ae819SStefano Zampini             /* Store upper triangular part of correlation matrix */
66529566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
66539566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6654674ae819SStefano Zampini             for (j = 0; j < temp_constraints; j++) {
665548a46eb9SPierre 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));
6656674ae819SStefano Zampini             }
6657e310c8b4SStefano Zampini             /* compute eigenvalues and eigenvectors of correlation matrix */
66589566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
66599566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDA));
6660674ae819SStefano Zampini #if !defined(PETSC_USE_COMPLEX)
6661792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, &lierr));
6662674ae819SStefano Zampini #else
6663792fecdfSBarry Smith             PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &Blas_N, correlation_mat, &Blas_LDA, singular_vals, work, &lwork, rwork, &lierr));
6664674ae819SStefano Zampini #endif
66659566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
666628b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SYEV Lapack routine %d", (int)lierr);
6667984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKsyev gives eigs in ascending order */
6668674ae819SStefano Zampini             j = 0;
666987b3baaaSStefano Zampini             while (j < temp_constraints && singular_vals[j] / singular_vals[temp_constraints - 1] < tol) j++;
6670674ae819SStefano Zampini             total_counts      = total_counts - j;
667145a1bb75SStefano Zampini             valid_constraints = temp_constraints - j;
6672e310c8b4SStefano Zampini             /* scale and copy POD basis into used quadrature memory */
66739566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
66749566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
66759566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_K));
66769566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
66779566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_LDB));
66789566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
6679674ae819SStefano Zampini             if (j < temp_constraints) {
6680984c4197SStefano Zampini               PetscInt ii;
6681984c4197SStefano Zampini               for (k = j; k < temp_constraints; k++) singular_vals[k] = 1.0 / PetscSqrtReal(singular_vals[k]);
66829566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6683792fecdfSBarry 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));
66849566063dSJacob Faibussowitsch               PetscCall(PetscFPTrapPop());
6685984c4197SStefano Zampini               for (k = 0; k < temp_constraints - j; k++) {
6686ad540459SPierre 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];
6687674ae819SStefano Zampini               }
6688674ae819SStefano Zampini             }
668955080a34SStefano Zampini           } else {
669055080a34SStefano Zampini #if !defined(PETSC_MISSING_LAPACK_GESVD)
66919566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
66929566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(temp_constraints, &Blas_N));
66939566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
66949566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6695674ae819SStefano Zampini   #if !defined(PETSC_USE_COMPLEX)
6696792fecdfSBarry 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));
6697674ae819SStefano Zampini   #else
6698792fecdfSBarry 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));
6699674ae819SStefano Zampini   #endif
670028b400f6SJacob Faibussowitsch             PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GESVD Lapack routine %d", (int)lierr);
67019566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
6702984c4197SStefano Zampini             /* retain eigenvalues greater than tol: note that LAPACKgesvd gives eigs in descending order */
6703e310c8b4SStefano Zampini             k = temp_constraints;
6704e310c8b4SStefano Zampini             if (k > size_of_constraint) k = size_of_constraint;
6705674ae819SStefano Zampini             j = 0;
670687b3baaaSStefano Zampini             while (j < k && singular_vals[k - j - 1] / singular_vals[0] < tol) j++;
670745a1bb75SStefano Zampini             valid_constraints = k - j;
6708911cabfeSStefano Zampini             total_counts      = total_counts - temp_constraints + valid_constraints;
670955080a34SStefano Zampini #else
671055080a34SStefano Zampini             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "This should not happen");
6711984c4197SStefano Zampini #endif /* on missing GESVD */
6712674ae819SStefano Zampini           }
6713a773dcb8SStefano Zampini         }
671455080a34SStefano Zampini       }
67159162d606SStefano Zampini       /* update pointers information */
67169162d606SStefano Zampini       if (valid_constraints) {
67179162d606SStefano Zampini         constraints_n[total_counts_cc]            = valid_constraints;
67189162d606SStefano Zampini         constraints_idxs_ptr[total_counts_cc + 1] = constraints_idxs_ptr[total_counts_cc] + size_of_constraint;
67199162d606SStefano Zampini         constraints_data_ptr[total_counts_cc + 1] = constraints_data_ptr[total_counts_cc] + size_of_constraint * valid_constraints;
67209162d606SStefano Zampini         /* set change_of_basis flag */
67213ba16761SJacob Faibussowitsch         if (boolforchange) PetscCall(PetscBTSet(change_basis, total_counts_cc));
6722b3d85658SStefano Zampini         total_counts_cc++;
672345a1bb75SStefano Zampini       }
672445a1bb75SStefano Zampini     }
6725984c4197SStefano Zampini     /* free workspace */
67268f1c130eSStefano Zampini     if (!skip_lapack) {
67279566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
6728984c4197SStefano Zampini #if defined(PETSC_USE_COMPLEX)
67299566063dSJacob Faibussowitsch       PetscCall(PetscFree(rwork));
6730984c4197SStefano Zampini #endif
67319566063dSJacob Faibussowitsch       PetscCall(PetscFree(singular_vals));
67329566063dSJacob Faibussowitsch       PetscCall(PetscFree(correlation_mat));
67339566063dSJacob Faibussowitsch       PetscCall(PetscFree(temp_basis));
6734984c4197SStefano Zampini     }
673548a46eb9SPierre Jolivet     for (k = 0; k < nnsp_size; k++) PetscCall(VecDestroy(&localnearnullsp[k]));
67369566063dSJacob Faibussowitsch     PetscCall(PetscFree(localnearnullsp));
6737cf5a6209SStefano Zampini     /* free index sets of faces, edges and vertices */
673832fe681dSStefano Zampini     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, &o_nf, &ISForFaces, &o_ne, &ISForEdges, &ISForVertices));
673908122e43SStefano Zampini   } else {
674008122e43SStefano Zampini     PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
6741984c4197SStefano Zampini 
674208122e43SStefano Zampini     total_counts = 0;
674308122e43SStefano Zampini     n_vertices   = 0;
674448a46eb9SPierre Jolivet     if (sub_schurs->is_vertices && pcbddc->use_vertices) PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
674508122e43SStefano Zampini     max_constraints = 0;
67469162d606SStefano Zampini     total_counts_cc = 0;
674708122e43SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
674808122e43SStefano Zampini       total_counts += pcbddc->adaptive_constraints_n[i];
67499162d606SStefano Zampini       if (pcbddc->adaptive_constraints_n[i]) total_counts_cc++;
675008122e43SStefano Zampini       max_constraints = PetscMax(max_constraints, pcbddc->adaptive_constraints_n[i]);
675108122e43SStefano Zampini     }
67529162d606SStefano Zampini     constraints_idxs_ptr = pcbddc->adaptive_constraints_idxs_ptr;
67539162d606SStefano Zampini     constraints_data_ptr = pcbddc->adaptive_constraints_data_ptr;
67549162d606SStefano Zampini     constraints_idxs     = pcbddc->adaptive_constraints_idxs;
67559162d606SStefano Zampini     constraints_data     = pcbddc->adaptive_constraints_data;
675674d5cdf7SStefano Zampini     /* constraints_n differs from pcbddc->adaptive_constraints_n */
67579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_counts_cc, &constraints_n));
67589162d606SStefano Zampini     total_counts_cc = 0;
67599162d606SStefano Zampini     for (i = 0; i < sub_schurs->n_subs + n_vertices; i++) {
6760ad540459SPierre Jolivet       if (pcbddc->adaptive_constraints_n[i]) constraints_n[total_counts_cc++] = pcbddc->adaptive_constraints_n[i];
676108122e43SStefano Zampini     }
676208122e43SStefano Zampini 
67638bec7fa6SStefano Zampini     max_size_of_constraint = 0;
67649162d606SStefano 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]);
67659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(constraints_idxs_ptr[total_counts_cc], &constraints_idxs_B));
676608122e43SStefano Zampini     /* Change of basis */
67679566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(total_counts_cc, &change_basis));
676808122e43SStefano Zampini     if (pcbddc->use_change_of_basis) {
676908122e43SStefano Zampini       for (i = 0; i < sub_schurs->n_subs; i++) {
677048a46eb9SPierre Jolivet         if (PetscBTLookup(sub_schurs->is_edge, i) || pcbddc->use_change_on_faces) PetscCall(PetscBTSet(change_basis, i + n_vertices));
677108122e43SStefano Zampini       }
677208122e43SStefano Zampini     }
677308122e43SStefano Zampini   }
6774984c4197SStefano Zampini   pcbddc->local_primal_size = total_counts;
67759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size + pcbddc->benign_n, &pcbddc->primal_indices_local_idxs));
677608122e43SStefano Zampini 
67779162d606SStefano Zampini   /* map constraints_idxs in boundary numbering */
677832fe681dSStefano Zampini   if (pcbddc->use_change_of_basis) {
67799566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, constraints_idxs_ptr[total_counts_cc], constraints_idxs, &i, constraints_idxs_B));
678063a3b9bcSJacob 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);
678132fe681dSStefano Zampini   }
6782674ae819SStefano Zampini 
6783674ae819SStefano Zampini   /* Create constraint matrix */
67849566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &pcbddc->ConstraintMatrix));
67859566063dSJacob Faibussowitsch   PetscCall(MatSetType(pcbddc->ConstraintMatrix, MATAIJ));
67869566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(pcbddc->ConstraintMatrix, pcbddc->local_primal_size, pcis->n, pcbddc->local_primal_size, pcis->n));
6787984c4197SStefano Zampini 
6788984c4197SStefano Zampini   /* find primal_dofs: subdomain corners plus dofs selected as primal after change of basis */
6789a717540cSStefano Zampini   /* determine if a QR strategy is needed for change of basis */
67905a52fde0SStefano Zampini   qr_needed = pcbddc->use_qr_single;
67919566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(total_counts_cc, &qr_needed_idx));
6792984c4197SStefano Zampini   total_primal_vertices        = 0;
6793b3d85658SStefano Zampini   pcbddc->local_primal_size_cc = 0;
67949162d606SStefano Zampini   for (i = 0; i < total_counts_cc; i++) {
67959162d606SStefano Zampini     size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
679672b8c272SStefano Zampini     if (size_of_constraint == 1 && pcbddc->mat_graph->custom_minimal_size) {
67979162d606SStefano Zampini       pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i]];
6798b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
679964efe560SStefano Zampini     } else if (PetscBTLookup(change_basis, i)) {
6800ad540459SPierre Jolivet       for (k = 0; k < constraints_n[i]; k++) pcbddc->primal_indices_local_idxs[total_primal_vertices++] = constraints_idxs[constraints_idxs_ptr[i] + k];
6801b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += constraints_n[i];
680291af6908SStefano Zampini       if (constraints_n[i] > 1 || pcbddc->use_qr_single) {
68033ba16761SJacob Faibussowitsch         PetscCall(PetscBTSet(qr_needed_idx, i));
6804a717540cSStefano Zampini         qr_needed = PETSC_TRUE;
6805a717540cSStefano Zampini       }
6806fa434743SStefano Zampini     } else {
6807b3d85658SStefano Zampini       pcbddc->local_primal_size_cc += 1;
6808fa434743SStefano Zampini     }
6809a717540cSStefano Zampini   }
6810b371cd4fSStefano Zampini   /* note that the local variable n_vertices used below stores the number of pointwise constraints */
6811b371cd4fSStefano Zampini   pcbddc->n_vertices = total_primal_vertices;
6812674ae819SStefano Zampini   /* permute indices in order to have a sorted set of vertices */
68139566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(total_primal_vertices, pcbddc->primal_indices_local_idxs));
68149566063dSJacob 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));
68159566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(pcbddc->local_primal_ref_node, pcbddc->primal_indices_local_idxs, total_primal_vertices));
68160e6343abSStefano Zampini   for (i = 0; i < total_primal_vertices; i++) pcbddc->local_primal_ref_mult[i] = 1;
6817984c4197SStefano Zampini 
6818984c4197SStefano Zampini   /* nonzero structure of constraint matrix */
681974d5cdf7SStefano Zampini   /* and get reference dof for local constraints */
68209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pcbddc->local_primal_size, &nnz));
6821984c4197SStefano Zampini   for (i = 0; i < total_primal_vertices; i++) nnz[i] = 1;
682274d5cdf7SStefano Zampini 
6823984c4197SStefano Zampini   j            = total_primal_vertices;
682474d5cdf7SStefano Zampini   total_counts = total_primal_vertices;
6825b3d85658SStefano Zampini   cum          = total_primal_vertices;
68269162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
68274641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
6828b3d85658SStefano Zampini       pcbddc->local_primal_ref_node[cum] = constraints_idxs[constraints_idxs_ptr[i]];
6829b3d85658SStefano Zampini       pcbddc->local_primal_ref_mult[cum] = constraints_n[i];
6830b3d85658SStefano Zampini       cum++;
68319162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
683274d5cdf7SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
683374d5cdf7SStefano Zampini         pcbddc->primal_indices_local_idxs[total_counts++] = constraints_idxs[constraints_idxs_ptr[i] + k];
683474d5cdf7SStefano Zampini         nnz[j + k]                                        = size_of_constraint;
683574d5cdf7SStefano Zampini       }
68369162d606SStefano Zampini       j += constraints_n[i];
6837674ae819SStefano Zampini     }
6838674ae819SStefano Zampini   }
68399566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(pcbddc->ConstraintMatrix, 0, nnz));
68409566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pcbddc->ConstraintMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
68419566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
6842088faed8SStefano Zampini 
6843674ae819SStefano Zampini   /* set values in constraint matrix */
684448a46eb9SPierre Jolivet   for (i = 0; i < total_primal_vertices; i++) PetscCall(MatSetValue(pcbddc->ConstraintMatrix, i, pcbddc->local_primal_ref_node[i], 1.0, INSERT_VALUES));
6845984c4197SStefano Zampini   total_counts = total_primal_vertices;
68469162d606SStefano Zampini   for (i = n_vertices; i < total_counts_cc; i++) {
68474641a718SStefano Zampini     if (!PetscBTLookup(change_basis, i)) {
68489162d606SStefano Zampini       PetscInt *cols;
68499162d606SStefano Zampini 
68509162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
68519162d606SStefano Zampini       cols               = constraints_idxs + constraints_idxs_ptr[i];
68529162d606SStefano Zampini       for (k = 0; k < constraints_n[i]; k++) {
68539162d606SStefano Zampini         PetscInt     row = total_counts + k;
68549162d606SStefano Zampini         PetscScalar *vals;
68559162d606SStefano Zampini 
68569162d606SStefano Zampini         vals = constraints_data + constraints_data_ptr[i] + k * size_of_constraint;
68579566063dSJacob Faibussowitsch         PetscCall(MatSetValues(pcbddc->ConstraintMatrix, 1, &row, size_of_constraint, cols, vals, INSERT_VALUES));
68589162d606SStefano Zampini       }
68599162d606SStefano Zampini       total_counts += constraints_n[i];
6860674ae819SStefano Zampini     }
6861674ae819SStefano Zampini   }
6862674ae819SStefano Zampini   /* assembling */
68639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
68649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(pcbddc->ConstraintMatrix, MAT_FINAL_ASSEMBLY));
68659566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(pcbddc->ConstraintMatrix, (PetscObject)pc, "-pc_bddc_constraint_mat_view"));
6866088faed8SStefano Zampini 
6867674ae819SStefano Zampini   /* Create matrix for change of basis. We don't need it in case pcbddc->use_change_of_basis is FALSE */
6868674ae819SStefano Zampini   if (pcbddc->use_change_of_basis) {
6869026de310SStefano Zampini     /* dual and primal dofs on a single cc */
6870984c4197SStefano Zampini     PetscInt dual_dofs, primal_dofs;
6871984c4197SStefano Zampini     /* working stuff for GEQRF */
68725a52fde0SStefano Zampini     PetscScalar *qr_basis = NULL, *qr_tau = NULL, *qr_work = NULL, lqr_work_t;
6873984c4197SStefano Zampini     PetscBLASInt lqr_work;
6874984c4197SStefano Zampini     /* working stuff for UNGQR */
68753c377650SSatish Balay     PetscScalar *gqr_work = NULL, lgqr_work_t = 0.0;
6876984c4197SStefano Zampini     PetscBLASInt lgqr_work;
6877984c4197SStefano Zampini     /* working stuff for TRTRS */
68785a52fde0SStefano Zampini     PetscScalar *trs_rhs = NULL;
68793f08241aSStefano Zampini     PetscBLASInt Blas_NRHS;
6880984c4197SStefano Zampini     /* pointers for values insertion into change of basis matrix */
6881984c4197SStefano Zampini     PetscInt    *start_rows, *start_cols;
6882984c4197SStefano Zampini     PetscScalar *start_vals;
6883984c4197SStefano Zampini     /* working stuff for values insertion */
68844641a718SStefano Zampini     PetscBT   is_primal;
688564efe560SStefano Zampini     PetscInt *aux_primal_numbering_B;
6886906d46d4SStefano Zampini     /* matrix sizes */
6887906d46d4SStefano Zampini     PetscInt global_size, local_size;
6888906d46d4SStefano Zampini     /* temporary change of basis */
6889906d46d4SStefano Zampini     Mat localChangeOfBasisMatrix;
6890cf5a6209SStefano Zampini     /* extra space for debugging */
68915a52fde0SStefano Zampini     PetscScalar *dbg_work = NULL;
6892984c4197SStefano Zampini 
68939566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &localChangeOfBasisMatrix));
68949566063dSJacob Faibussowitsch     PetscCall(MatSetType(localChangeOfBasisMatrix, MATAIJ));
68959566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(localChangeOfBasisMatrix, pcis->n, pcis->n, pcis->n, pcis->n));
6896906d46d4SStefano Zampini     /* nonzeros for local mat */
68979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcis->n, &nnz));
68981dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
6899bbb9e6c6SStefano Zampini       for (i = 0; i < pcis->n; i++) nnz[i] = 1;
69001dd7afcfSStefano Zampini     } else {
69011dd7afcfSStefano Zampini       const PetscInt *ii;
69021dd7afcfSStefano Zampini       PetscInt        n;
69031dd7afcfSStefano Zampini       PetscBool       flg_row;
69049566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
69051dd7afcfSStefano Zampini       for (i = 0; i < n; i++) nnz[i] = ii[i + 1] - ii[i];
69069566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, NULL, &flg_row));
69071dd7afcfSStefano Zampini     }
69089162d606SStefano Zampini     for (i = n_vertices; i < total_counts_cc; i++) {
6909a717540cSStefano Zampini       if (PetscBTLookup(change_basis, i)) {
69109162d606SStefano Zampini         size_of_constraint = constraints_idxs_ptr[i + 1] - constraints_idxs_ptr[i];
6911a717540cSStefano Zampini         if (PetscBTLookup(qr_needed_idx, i)) {
69129162d606SStefano Zampini           for (j = 0; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = size_of_constraint;
6913a717540cSStefano Zampini         } else {
69149162d606SStefano Zampini           nnz[constraints_idxs[constraints_idxs_ptr[i]]] = size_of_constraint;
69159162d606SStefano Zampini           for (j = 1; j < size_of_constraint; j++) nnz[constraints_idxs[constraints_idxs_ptr[i] + j]] = 2;
6916a717540cSStefano Zampini         }
6917a717540cSStefano Zampini       }
6918a717540cSStefano Zampini     }
69199566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(localChangeOfBasisMatrix, 0, nnz));
69209566063dSJacob Faibussowitsch     PetscCall(MatSetOption(localChangeOfBasisMatrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
69219566063dSJacob Faibussowitsch     PetscCall(PetscFree(nnz));
69221dd7afcfSStefano Zampini     /* Set interior change in the matrix */
69231dd7afcfSStefano Zampini     if (!pcbddc->benign_change || pcbddc->fake_change) {
692448a46eb9SPierre Jolivet       for (i = 0; i < pcis->n; i++) PetscCall(MatSetValue(localChangeOfBasisMatrix, i, i, 1.0, INSERT_VALUES));
69251dd7afcfSStefano Zampini     } else {
69261dd7afcfSStefano Zampini       const PetscInt *ii, *jj;
69271dd7afcfSStefano Zampini       PetscScalar    *aa;
69281dd7afcfSStefano Zampini       PetscInt        n;
69291dd7afcfSStefano Zampini       PetscBool       flg_row;
69309566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
69319566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJGetArray(pcbddc->benign_change, &aa));
693248a46eb9SPierre 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));
69339566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJRestoreArray(pcbddc->benign_change, &aa));
69349566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->benign_change, 0, PETSC_FALSE, PETSC_FALSE, &n, &ii, &jj, &flg_row));
69351dd7afcfSStefano Zampini     }
6936a717540cSStefano Zampini 
6937a717540cSStefano Zampini     if (pcbddc->dbg_flag) {
69389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
69399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Checking change of basis computation for subdomain %04d\n", PetscGlobalRank));
6940a717540cSStefano Zampini     }
6941a717540cSStefano Zampini 
6942a717540cSStefano Zampini     /* Now we loop on the constraints which need a change of basis */
6943a717540cSStefano Zampini     /*
6944a717540cSStefano Zampini        Change of basis matrix is evaluated similarly to the FIRST APPROACH in
6945a717540cSStefano Zampini        Klawonn and Widlund, Dual-primal FETI-DP methods for linear elasticity, (see Sect 6.2.1)
6946a717540cSStefano Zampini 
69477c625d9fSStefano Zampini        Basic blocks of change of basis matrix T computed:
6948a717540cSStefano Zampini 
69497c625d9fSStefano 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)
6950a6b551f4SStefano Zampini 
6951a6b551f4SStefano Zampini             | 1        0   ...        0         s_1/S |
6952a6b551f4SStefano Zampini             | 0        1   ...        0         s_2/S |
6953a717540cSStefano Zampini             |              ...                        |
6954a6b551f4SStefano Zampini             | 0        ...            1     s_{n-1}/S |
6955a6b551f4SStefano Zampini             | -s_1/s_n ...    -s_{n-1}/s_n      s_n/S |
6956a717540cSStefano Zampini 
6957a6b551f4SStefano Zampini             with S = \sum_{i=1}^n s_i^2
6958a6b551f4SStefano Zampini             NOTE: in the above example, the primal dof is the last one of the edge in LOCAL ordering
6959a6b551f4SStefano Zampini                   in the current implementation, the primal dof is the first one of the edge in GLOBAL ordering
6960a6b551f4SStefano Zampini 
6961a6b551f4SStefano Zampini           - QR decomposition of constraints otherwise
6962a717540cSStefano Zampini     */
69635a52fde0SStefano Zampini     if (qr_needed && max_size_of_constraint) {
6964984c4197SStefano Zampini       /* space to store Q */
69659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_size_of_constraint * max_size_of_constraint, &qr_basis));
69664e64d54eSstefano_zampini       /* array to store scaling factors for reflectors */
69679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints, &qr_tau));
6968984c4197SStefano Zampini       /* first we issue queries for optimal work */
69699566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
69709566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_N));
69719566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
6972984c4197SStefano Zampini       lqr_work = -1;
6973792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, &lqr_work_t, &lqr_work, &lierr));
697428b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to GEQRF Lapack routine %d", (int)lierr);
69759566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lqr_work_t), &lqr_work));
697659b05608SBarry Smith       PetscCall(PetscMalloc1(lqr_work, &qr_work));
6977984c4197SStefano Zampini       lgqr_work = -1;
69789566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_M));
69799566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_N));
69809566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_constraints, &Blas_K));
69819566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast(max_size_of_constraint, &Blas_LDA));
69823f08241aSStefano Zampini       if (Blas_K > Blas_M) Blas_K = Blas_M; /* adjust just for computing optimal work */
6983792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, &lgqr_work_t, &lgqr_work, &lierr));
698428b400f6SJacob Faibussowitsch       PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in query to ORGQR/UNGQR Lapack routine %d", (int)lierr);
69859566063dSJacob Faibussowitsch       PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(lgqr_work_t), &lgqr_work));
698659b05608SBarry Smith       PetscCall(PetscMalloc1(lgqr_work, &gqr_work));
6987984c4197SStefano Zampini       /* array to store rhs and solution of triangular solver */
69889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(max_constraints * max_constraints, &trs_rhs));
6989a717540cSStefano Zampini       /* allocating workspace for check */
699048a46eb9SPierre Jolivet       if (pcbddc->dbg_flag) PetscCall(PetscMalloc1(max_size_of_constraint * (max_constraints + max_size_of_constraint), &dbg_work));
6991a717540cSStefano Zampini     }
6992984c4197SStefano Zampini     /* array to store whether a node is primal or not */
69939566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(pcis->n_B, &is_primal));
69949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(total_primal_vertices, &aux_primal_numbering_B));
69959566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(pcis->BtoNmap, IS_GTOLM_DROP, total_primal_vertices, pcbddc->local_primal_ref_node, &i, aux_primal_numbering_B));
699663a3b9bcSJacob 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);
699748a46eb9SPierre Jolivet     for (i = 0; i < total_primal_vertices; i++) PetscCall(PetscBTSet(is_primal, aux_primal_numbering_B[i]));
69989566063dSJacob Faibussowitsch     PetscCall(PetscFree(aux_primal_numbering_B));
6999984c4197SStefano Zampini 
7000a717540cSStefano Zampini     /* loop on constraints and see whether or not they need a change of basis and compute it */
70019162d606SStefano Zampini     for (total_counts = n_vertices; total_counts < total_counts_cc; total_counts++) {
70029162d606SStefano Zampini       size_of_constraint = constraints_idxs_ptr[total_counts + 1] - constraints_idxs_ptr[total_counts];
70034641a718SStefano Zampini       if (PetscBTLookup(change_basis, total_counts)) {
7004984c4197SStefano Zampini         /* get constraint info */
70059162d606SStefano Zampini         primal_dofs = constraints_n[total_counts];
7006984c4197SStefano Zampini         dual_dofs   = size_of_constraint - primal_dofs;
7007984c4197SStefano Zampini 
700848a46eb9SPierre 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));
7009984c4197SStefano Zampini 
7010fa434743SStefano Zampini         if (PetscBTLookup(qr_needed_idx, total_counts)) { /* QR */
7011a717540cSStefano Zampini 
7012a717540cSStefano Zampini           /* copy quadrature constraints for change of basis check */
701348a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscArraycpy(dbg_work, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7014984c4197SStefano Zampini           /* copy temporary constraints into larger work vector (in order to store all columns of Q) */
70159566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7016984c4197SStefano Zampini 
7017984c4197SStefano Zampini           /* compute QR decomposition of constraints */
70189566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
70199566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
70209566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70219566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7022792fecdfSBarry Smith           PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Blas_M, &Blas_N, qr_basis, &Blas_LDA, qr_tau, qr_work, &lqr_work, &lierr));
702328b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in GEQRF Lapack routine %d", (int)lierr);
70249566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7025984c4197SStefano Zampini 
7026a5b23f4aSJose E. Roman           /* explicitly compute R^-T */
70279566063dSJacob Faibussowitsch           PetscCall(PetscArrayzero(trs_rhs, primal_dofs * primal_dofs));
7028984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) trs_rhs[j * (primal_dofs + 1)] = 1.0;
70299566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
70309566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_NRHS));
70319566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70329566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
70339566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7034792fecdfSBarry Smith           PetscCallBLAS("LAPACKtrtrs", LAPACKtrtrs_("U", "T", "N", &Blas_N, &Blas_NRHS, qr_basis, &Blas_LDA, trs_rhs, &Blas_LDB, &lierr));
703528b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in TRTRS Lapack routine %d", (int)lierr);
70369566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7037984c4197SStefano Zampini 
7038a717540cSStefano Zampini           /* explicitly compute all columns of Q (Q = [Q1 | Q2]) overwriting QR factorization in qr_basis */
70399566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
70409566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
70419566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
70429566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70439566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7044792fecdfSBarry Smith           PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Blas_M, &Blas_N, &Blas_K, qr_basis, &Blas_LDA, qr_tau, gqr_work, &lgqr_work, &lierr));
704528b400f6SJacob Faibussowitsch           PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ORGQR/UNGQR Lapack routine %d", (int)lierr);
70469566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
7047984c4197SStefano Zampini 
7048984c4197SStefano Zampini           /* first primal_dofs columns of Q need to be re-scaled in order to be unitary w.r.t constraints
7049984c4197SStefano Zampini              i.e. C_{pxn}*Q_{nxn} should be equal to [I_pxp | 0_pxd] (see check below)
7050984c4197SStefano Zampini              where n=size_of_constraint, p=primal_dofs, d=dual_dofs (n=p+d), I and 0 identity and null matrix resp. */
70519566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_M));
70529566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_N));
70539566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_K));
70549566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70559566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDB));
70569566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDC));
70579566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7058792fecdfSBarry 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));
70599566063dSJacob Faibussowitsch           PetscCall(PetscFPTrapPop());
70609566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(qr_basis, &constraints_data[constraints_data_ptr[total_counts]], size_of_constraint * primal_dofs));
7061984c4197SStefano Zampini 
7062984c4197SStefano Zampini           /* insert values in change of basis matrix respecting global ordering of new primal dofs */
70639162d606SStefano Zampini           start_rows = &constraints_idxs[constraints_idxs_ptr[total_counts]];
7064984c4197SStefano Zampini           /* insert cols for primal dofs */
7065984c4197SStefano Zampini           for (j = 0; j < primal_dofs; j++) {
7066984c4197SStefano Zampini             start_vals = &qr_basis[j * size_of_constraint];
70679162d606SStefano Zampini             start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + j];
70689566063dSJacob Faibussowitsch             PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7069984c4197SStefano Zampini           }
7070984c4197SStefano Zampini           /* insert cols for dual dofs */
7071984c4197SStefano Zampini           for (j = 0, k = 0; j < dual_dofs; k++) {
70729162d606SStefano Zampini             if (!PetscBTLookup(is_primal, constraints_idxs_B[constraints_idxs_ptr[total_counts] + k])) {
7073984c4197SStefano Zampini               start_vals = &qr_basis[(primal_dofs + j) * size_of_constraint];
70749162d606SStefano Zampini               start_cols = &constraints_idxs[constraints_idxs_ptr[total_counts] + k];
70759566063dSJacob Faibussowitsch               PetscCall(MatSetValues(localChangeOfBasisMatrix, size_of_constraint, start_rows, 1, start_cols, start_vals, INSERT_VALUES));
7076984c4197SStefano Zampini               j++;
7077674ae819SStefano Zampini             }
7078674ae819SStefano Zampini           }
7079984c4197SStefano Zampini 
7080984c4197SStefano Zampini           /* check change of basis */
7081984c4197SStefano Zampini           if (pcbddc->dbg_flag) {
7082984c4197SStefano Zampini             PetscInt  ii, jj;
7083984c4197SStefano Zampini             PetscBool valid_qr = PETSC_TRUE;
70849566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_M));
70859566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
70869566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_K));
70879566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDA));
70889566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_LDB));
70899566063dSJacob Faibussowitsch             PetscCall(PetscBLASIntCast(primal_dofs, &Blas_LDC));
70909566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
7091792fecdfSBarry 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));
70929566063dSJacob Faibussowitsch             PetscCall(PetscFPTrapPop());
7093984c4197SStefano Zampini             for (jj = 0; jj < size_of_constraint; jj++) {
7094984c4197SStefano Zampini               for (ii = 0; ii < primal_dofs; ii++) {
7095cf5a6209SStefano Zampini                 if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) valid_qr = PETSC_FALSE;
7096c068d9bbSLisandro 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;
7097674ae819SStefano Zampini               }
7098674ae819SStefano Zampini             }
7099984c4197SStefano Zampini             if (!valid_qr) {
71009566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> wrong change of basis!\n"));
7101984c4197SStefano Zampini               for (jj = 0; jj < size_of_constraint; jj++) {
7102984c4197SStefano Zampini                 for (ii = 0; ii < primal_dofs; ii++) {
7103cf5a6209SStefano Zampini                   if (ii != jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii]) > 1.e-12) {
710463a3b9bcSJacob 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])));
7105674ae819SStefano Zampini                   }
7106c068d9bbSLisandro Dalcin                   if (ii == jj && PetscAbsScalar(dbg_work[size_of_constraint * primal_dofs + jj * primal_dofs + ii] - (PetscReal)1) > 1.e-12) {
710763a3b9bcSJacob 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])));
7108984c4197SStefano Zampini                   }
7109984c4197SStefano Zampini                 }
7110984c4197SStefano Zampini               }
7111674ae819SStefano Zampini             } else {
71129566063dSJacob Faibussowitsch               PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> right change of basis!\n"));
7113674ae819SStefano Zampini             }
7114674ae819SStefano Zampini           }
7115a717540cSStefano Zampini         } else { /* simple transformation block */
7116a717540cSStefano Zampini           PetscInt    row, col;
7117a6b551f4SStefano Zampini           PetscScalar val, norm;
7118a6b551f4SStefano Zampini 
71199566063dSJacob Faibussowitsch           PetscCall(PetscBLASIntCast(size_of_constraint, &Blas_N));
7120792fecdfSBarry 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));
7121a717540cSStefano Zampini           for (j = 0; j < size_of_constraint; j++) {
71229162d606SStefano Zampini             PetscInt row_B = constraints_idxs_B[constraints_idxs_ptr[total_counts] + j];
71239162d606SStefano Zampini             row            = constraints_idxs[constraints_idxs_ptr[total_counts] + j];
7124bbb9e6c6SStefano Zampini             if (!PetscBTLookup(is_primal, row_B)) {
71259162d606SStefano Zampini               col = constraints_idxs[constraints_idxs_ptr[total_counts]];
71269566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, row, 1.0, INSERT_VALUES));
71279566063dSJacob Faibussowitsch               PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, constraints_data[constraints_data_ptr[total_counts] + j] / norm, INSERT_VALUES));
7128a717540cSStefano Zampini             } else {
7129a717540cSStefano Zampini               for (k = 0; k < size_of_constraint; k++) {
71309162d606SStefano Zampini                 col = constraints_idxs[constraints_idxs_ptr[total_counts] + k];
7131a717540cSStefano Zampini                 if (row != col) {
71329162d606SStefano Zampini                   val = -constraints_data[constraints_data_ptr[total_counts] + k] / constraints_data[constraints_data_ptr[total_counts]];
7133a717540cSStefano Zampini                 } else {
71349162d606SStefano Zampini                   val = constraints_data[constraints_data_ptr[total_counts]] / norm;
7135a717540cSStefano Zampini                 }
71369566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(localChangeOfBasisMatrix, row, col, val, INSERT_VALUES));
7137a717540cSStefano Zampini               }
7138a717540cSStefano Zampini             }
7139a717540cSStefano Zampini           }
714048a46eb9SPierre Jolivet           if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "\t-> using standard change of basis\n"));
7141a717540cSStefano Zampini         }
7142984c4197SStefano Zampini       } else {
714348a46eb9SPierre 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));
7144674ae819SStefano Zampini       }
7145674ae819SStefano Zampini     }
7146a717540cSStefano Zampini 
7147a717540cSStefano Zampini     /* free workspace */
7148a717540cSStefano Zampini     if (qr_needed) {
71491baa6e33SBarry Smith       if (pcbddc->dbg_flag) PetscCall(PetscFree(dbg_work));
71509566063dSJacob Faibussowitsch       PetscCall(PetscFree(trs_rhs));
71519566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_tau));
71529566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_work));
71539566063dSJacob Faibussowitsch       PetscCall(PetscFree(gqr_work));
71549566063dSJacob Faibussowitsch       PetscCall(PetscFree(qr_basis));
7155674ae819SStefano Zampini     }
71569566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&is_primal));
71579566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
71589566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(localChangeOfBasisMatrix, MAT_FINAL_ASSEMBLY));
7159906d46d4SStefano Zampini 
7160906d46d4SStefano Zampini     /* assembling of global change of variable */
716188c03ad3SStefano Zampini     if (!pcbddc->fake_change) {
7162bbb9e6c6SStefano Zampini       Mat      tmat;
716316f15bc4SStefano Zampini       PetscInt bs;
716416f15bc4SStefano Zampini 
71659566063dSJacob Faibussowitsch       PetscCall(VecGetSize(pcis->vec1_global, &global_size));
71669566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(pcis->vec1_global, &local_size));
71679566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &tmat));
71689566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(tmat, localChangeOfBasisMatrix));
71699566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tmat, MAT_FINAL_ASSEMBLY));
71709566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tmat, MAT_FINAL_ASSEMBLY));
71719566063dSJacob Faibussowitsch       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &pcbddc->ChangeOfBasisMatrix));
71729566063dSJacob Faibussowitsch       PetscCall(MatSetType(pcbddc->ChangeOfBasisMatrix, MATAIJ));
71739566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(pc->pmat, &bs));
71749566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(pcbddc->ChangeOfBasisMatrix, bs));
71759566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(pcbddc->ChangeOfBasisMatrix, local_size, local_size, global_size, global_size));
71769566063dSJacob Faibussowitsch       PetscCall(MatISSetMPIXAIJPreallocation_Private(tmat, pcbddc->ChangeOfBasisMatrix, PETSC_TRUE));
71779566063dSJacob Faibussowitsch       PetscCall(MatConvert(tmat, MATAIJ, MAT_REUSE_MATRIX, &pcbddc->ChangeOfBasisMatrix));
71789566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&tmat));
71799566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_global, 0.0));
71809566063dSJacob Faibussowitsch       PetscCall(VecSet(pcis->vec1_N, 1.0));
71819566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
71829566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, pcis->vec1_global, ADD_VALUES, SCATTER_REVERSE));
71839566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(pcis->vec1_global));
71849566063dSJacob Faibussowitsch       PetscCall(MatDiagonalScale(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, NULL));
718588c03ad3SStefano Zampini 
7186906d46d4SStefano Zampini       /* check */
7187906d46d4SStefano Zampini       if (pcbddc->dbg_flag) {
7188906d46d4SStefano Zampini         PetscReal error;
7189906d46d4SStefano Zampini         Vec       x, x_change;
7190906d46d4SStefano Zampini 
71919566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x));
71929566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(pcis->vec1_global, &x_change));
71939566063dSJacob Faibussowitsch         PetscCall(VecSetRandom(x, NULL));
71949566063dSJacob Faibussowitsch         PetscCall(VecCopy(x, pcis->vec1_global));
71959566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
71969566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, x, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
71979566063dSJacob Faibussowitsch         PetscCall(MatMult(localChangeOfBasisMatrix, pcis->vec1_N, pcis->vec2_N));
71989566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
71999566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(matis->rctx, pcis->vec2_N, x, INSERT_VALUES, SCATTER_REVERSE));
72009566063dSJacob Faibussowitsch         PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x_change));
72019566063dSJacob Faibussowitsch         PetscCall(VecAXPY(x, -1.0, x_change));
72029566063dSJacob Faibussowitsch         PetscCall(VecNorm(x, NORM_INFINITY, &error));
7203049d1499SBarry Smith         PetscCheck(error <= PETSC_SMALL, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Error global vs local change on N: %1.6e", (double)error);
72049566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
72059566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x_change));
7206906d46d4SStefano Zampini       }
7207b96c3477SStefano Zampini       /* adapt sub_schurs computed (if any) */
7208b96c3477SStefano Zampini       if (pcbddc->use_deluxe_scaling) {
7209b96c3477SStefano Zampini         PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
7210bf3a8328SStefano Zampini 
721108401ef6SPierre 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");
7212b334f244SStefano Zampini         if (sub_schurs && sub_schurs->S_Ej_all) {
7213ac632422SStefano Zampini           Mat S_new, tmat;
7214bf3a8328SStefano Zampini           IS  is_all_N, is_V_Sall = NULL;
7215bbb9e6c6SStefano Zampini 
72169566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingApplyIS(pcis->BtoNmap, sub_schurs->is_Ej_all, &is_all_N));
72179566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(localChangeOfBasisMatrix, is_all_N, is_all_N, MAT_INITIAL_MATRIX, &tmat));
7218bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7219bf3a8328SStefano Zampini             ISLocalToGlobalMapping NtoSall;
7220bf3a8328SStefano Zampini             IS                     is_V;
72219566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pcbddc->n_vertices, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &is_V));
72229566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingCreateIS(is_all_N, &NtoSall));
72239566063dSJacob Faibussowitsch             PetscCall(ISGlobalToLocalMappingApplyIS(NtoSall, IS_GTOLM_DROP, is_V, &is_V_Sall));
72249566063dSJacob Faibussowitsch             PetscCall(ISLocalToGlobalMappingDestroy(&NtoSall));
72259566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&is_V));
7226bf3a8328SStefano Zampini           }
72279566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_all_N));
72289566063dSJacob Faibussowitsch           PetscCall(MatPtAP(sub_schurs->S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
72299566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&sub_schurs->S_Ej_all));
72309566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)S_new));
7231bf3a8328SStefano Zampini           if (pcbddc->deluxe_zerorows) {
7232bf3a8328SStefano Zampini             const PetscScalar *array;
7233bf3a8328SStefano Zampini             const PetscInt    *idxs_V, *idxs_all;
7234bf3a8328SStefano Zampini             PetscInt           i, n_V;
7235bf3a8328SStefano Zampini 
72369566063dSJacob Faibussowitsch             PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
72379566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(is_V_Sall, &n_V));
72389566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(is_V_Sall, &idxs_V));
72399566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(sub_schurs->is_Ej_all, &idxs_all));
72409566063dSJacob Faibussowitsch             PetscCall(VecGetArrayRead(pcis->D, &array));
7241b087196eSStefano Zampini             for (i = 0; i < n_V; i++) {
7242b087196eSStefano Zampini               PetscScalar val;
7243b087196eSStefano Zampini               PetscInt    idx;
7244b087196eSStefano Zampini 
7245b087196eSStefano Zampini               idx = idxs_V[i];
7246b087196eSStefano Zampini               val = array[idxs_all[idxs_V[i]]];
72479566063dSJacob Faibussowitsch               PetscCall(MatSetValue(S_new, idx, idx, val, INSERT_VALUES));
7248b087196eSStefano Zampini             }
72499566063dSJacob Faibussowitsch             PetscCall(MatAssemblyBegin(S_new, MAT_FINAL_ASSEMBLY));
72509566063dSJacob Faibussowitsch             PetscCall(MatAssemblyEnd(S_new, MAT_FINAL_ASSEMBLY));
72519566063dSJacob Faibussowitsch             PetscCall(VecRestoreArrayRead(pcis->D, &array));
72529566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(sub_schurs->is_Ej_all, &idxs_all));
72539566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(is_V_Sall, &idxs_V));
7254bf3a8328SStefano Zampini           }
7255ac632422SStefano Zampini           sub_schurs->S_Ej_all = S_new;
72569566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&S_new));
7257ac632422SStefano Zampini           if (sub_schurs->sum_S_Ej_all) {
72589566063dSJacob Faibussowitsch             PetscCall(MatPtAP(sub_schurs->sum_S_Ej_all, tmat, MAT_INITIAL_MATRIX, 1.0, &S_new));
72599566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&sub_schurs->sum_S_Ej_all));
72609566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)S_new));
72611baa6e33SBarry Smith             if (pcbddc->deluxe_zerorows) PetscCall(MatZeroRowsColumnsIS(S_new, is_V_Sall, 1., NULL, NULL));
7262ac632422SStefano Zampini             sub_schurs->sum_S_Ej_all = S_new;
72639566063dSJacob Faibussowitsch             PetscCall(MatDestroy(&S_new));
7264ac632422SStefano Zampini           }
72659566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is_V_Sall));
72669566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&tmat));
7267b96c3477SStefano Zampini         }
7268c9db6a07SStefano Zampini         /* destroy any change of basis context in sub_schurs */
7269b334f244SStefano Zampini         if (sub_schurs && sub_schurs->change) {
7270c9db6a07SStefano Zampini           PetscInt i;
7271c9db6a07SStefano Zampini 
727248a46eb9SPierre Jolivet           for (i = 0; i < sub_schurs->n_subs; i++) PetscCall(KSPDestroy(&sub_schurs->change[i]));
72739566063dSJacob Faibussowitsch           PetscCall(PetscFree(sub_schurs->change));
7274c9db6a07SStefano Zampini         }
7275b96c3477SStefano Zampini       }
727616909a7fSStefano Zampini       if (pcbddc->switch_static) { /* need to save the local change */
727716909a7fSStefano Zampini         pcbddc->switch_static_change = localChangeOfBasisMatrix;
727816909a7fSStefano Zampini       } else {
72799566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&localChangeOfBasisMatrix));
728016909a7fSStefano Zampini       }
72811dd7afcfSStefano Zampini       /* determine if any process has changed the pressures locally */
728227b6a85dSStefano Zampini       pcbddc->change_interior = pcbddc->benign_have_null;
728372b8c272SStefano Zampini     } else { /* fake change (get back change of basis into ConstraintMatrix and info on qr) */
72849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pcbddc->ConstraintMatrix));
728572b8c272SStefano Zampini       pcbddc->ConstraintMatrix = localChangeOfBasisMatrix;
728672b8c272SStefano Zampini       pcbddc->use_qr_single    = qr_needed;
728772b8c272SStefano Zampini     }
72881dd7afcfSStefano Zampini   } else if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->benign_saddle_point) {
728927b6a85dSStefano Zampini     if (!pcbddc->benign_have_null && pcbddc->user_ChangeOfBasisMatrix) {
72909566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)pcbddc->user_ChangeOfBasisMatrix));
7291b9b85e73SStefano Zampini       pcbddc->ChangeOfBasisMatrix = pcbddc->user_ChangeOfBasisMatrix;
7292906d46d4SStefano Zampini     } else {
72931dd7afcfSStefano Zampini       Mat benign_global = NULL;
729427b6a85dSStefano Zampini       if (pcbddc->benign_have_null) {
72951dd7afcfSStefano Zampini         Mat M;
72961dd7afcfSStefano Zampini 
72979e9b7b1fSStefano Zampini         pcbddc->change_interior = PETSC_TRUE;
72989566063dSJacob Faibussowitsch         PetscCall(VecCopy(matis->counter, pcis->vec1_N));
72999566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(pcis->vec1_N));
73009566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(pc->pmat, MAT_DO_NOT_COPY_VALUES, &benign_global));
73019e9b7b1fSStefano Zampini         if (pcbddc->benign_change) {
73029566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(pcbddc->benign_change, MAT_COPY_VALUES, &M));
73039566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(M, pcis->vec1_N, NULL));
7304906d46d4SStefano Zampini         } else {
73059566063dSJacob Faibussowitsch           PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, pcis->n, pcis->n, 1, NULL, &M));
73069566063dSJacob Faibussowitsch           PetscCall(MatDiagonalSet(M, pcis->vec1_N, INSERT_VALUES));
7307906d46d4SStefano Zampini         }
73089566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(benign_global, M));
73099566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
73109566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(benign_global, MAT_FINAL_ASSEMBLY));
73119566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(benign_global, MAT_FINAL_ASSEMBLY));
73121dd7afcfSStefano Zampini       }
73131dd7afcfSStefano Zampini       if (pcbddc->user_ChangeOfBasisMatrix) {
73149566063dSJacob Faibussowitsch         PetscCall(MatMatMult(pcbddc->user_ChangeOfBasisMatrix, benign_global, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &pcbddc->ChangeOfBasisMatrix));
73159566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&benign_global));
731627b6a85dSStefano Zampini       } else if (pcbddc->benign_have_null) {
73171dd7afcfSStefano Zampini         pcbddc->ChangeOfBasisMatrix = benign_global;
73181dd7afcfSStefano Zampini       }
73191dd7afcfSStefano Zampini     }
732016909a7fSStefano Zampini     if (pcbddc->switch_static && pcbddc->ChangeOfBasisMatrix) { /* need to save the local change */
732116909a7fSStefano Zampini       IS              is_global;
732216909a7fSStefano Zampini       const PetscInt *gidxs;
732316909a7fSStefano Zampini 
73249566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
73259566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcis->n, gidxs, PETSC_COPY_VALUES, &is_global));
73269566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
73279566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrixUnsorted(pcbddc->ChangeOfBasisMatrix, is_global, is_global, &pcbddc->switch_static_change));
73289566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_global));
732916909a7fSStefano Zampini     }
73301dd7afcfSStefano Zampini   }
733148a46eb9SPierre Jolivet   if (!pcbddc->fake_change && pcbddc->ChangeOfBasisMatrix && !pcbddc->work_change) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->work_change));
7332a717540cSStefano Zampini 
733372b8c272SStefano Zampini   if (!pcbddc->fake_change) {
73344f1b2e48SStefano Zampini     /* add pressure dofs to set of primal nodes for numbering purposes */
73354f1b2e48SStefano Zampini     for (i = 0; i < pcbddc->benign_n; i++) {
73364f1b2e48SStefano Zampini       pcbddc->local_primal_ref_node[pcbddc->local_primal_size_cc]  = pcbddc->benign_p0_lidx[i];
73374f1b2e48SStefano Zampini       pcbddc->primal_indices_local_idxs[pcbddc->local_primal_size] = pcbddc->benign_p0_lidx[i];
7338019a44ceSStefano Zampini       pcbddc->local_primal_ref_mult[pcbddc->local_primal_size_cc]  = 1;
7339019a44ceSStefano Zampini       pcbddc->local_primal_size_cc++;
7340019a44ceSStefano Zampini       pcbddc->local_primal_size++;
7341019a44ceSStefano Zampini     }
7342019a44ceSStefano Zampini 
7343019a44ceSStefano Zampini     /* check if a new primal space has been introduced (also take into account benign trick) */
7344727cdba6SStefano Zampini     pcbddc->new_primal_space_local = PETSC_TRUE;
7345727cdba6SStefano Zampini     if (olocal_primal_size == pcbddc->local_primal_size) {
73469566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(pcbddc->local_primal_ref_node, olocal_primal_ref_node, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7347c1c8e736SStefano Zampini       pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
73480e6343abSStefano Zampini       if (!pcbddc->new_primal_space_local) {
73499566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(pcbddc->local_primal_ref_mult, olocal_primal_ref_mult, olocal_primal_size_cc, &pcbddc->new_primal_space_local));
7350727cdba6SStefano Zampini         pcbddc->new_primal_space_local = (PetscBool)(!pcbddc->new_primal_space_local);
7351727cdba6SStefano Zampini       }
73520e6343abSStefano Zampini     }
7353727cdba6SStefano Zampini     /* new_primal_space will be used for numbering of coarse dofs, so it should be the same across all subdomains */
73541c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&pcbddc->new_primal_space_local, &pcbddc->new_primal_space, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
735572b8c272SStefano Zampini   }
73569566063dSJacob Faibussowitsch   PetscCall(PetscFree2(olocal_primal_ref_node, olocal_primal_ref_mult));
7357727cdba6SStefano Zampini 
7358a717540cSStefano Zampini   /* flush dbg viewer */
73591baa6e33SBarry Smith   if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7360a717540cSStefano Zampini 
7361e310c8b4SStefano Zampini   /* free workspace */
73629566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&qr_needed_idx));
73639566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&change_basis));
736408122e43SStefano Zampini   if (!pcbddc->adaptive_selection) {
73659566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_idxs_ptr, constraints_data_ptr, constraints_n));
73669566063dSJacob Faibussowitsch     PetscCall(PetscFree3(constraints_data, constraints_idxs, constraints_idxs_B));
736708122e43SStefano Zampini   } else {
7368d0609cedSBarry 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));
73699566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_n));
73709566063dSJacob Faibussowitsch     PetscCall(PetscFree(constraints_idxs_B));
737108122e43SStefano Zampini   }
73723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7373674ae819SStefano Zampini }
7374674ae819SStefano Zampini 
7375d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCAnalyzeInterface(PC pc)
7376d71ae5a4SJacob Faibussowitsch {
737771582508SStefano Zampini   ISLocalToGlobalMapping map;
7378674ae819SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
7379674ae819SStefano Zampini   Mat_IS                *matis  = (Mat_IS *)pc->pmat->data;
738066da6bd7Sstefano_zampini   PetscInt               i, N;
738166da6bd7Sstefano_zampini   PetscBool              rcsr = PETSC_FALSE;
7382674ae819SStefano Zampini 
7383674ae819SStefano Zampini   PetscFunctionBegin;
73848af8fcf9SStefano Zampini   if (pcbddc->recompute_topography) {
7385b03ebc13SStefano Zampini     pcbddc->graphanalyzed = PETSC_FALSE;
73868e61c736SStefano Zampini     /* Reset previously computed graph */
73879566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphReset(pcbddc->mat_graph));
7388674ae819SStefano Zampini     /* Init local Graph struct */
73899566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->pmat, &N, NULL));
73909566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(pc->pmat, &map, NULL));
73919566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(pcbddc->mat_graph, map, N, pcbddc->graphmaxcount));
7392674ae819SStefano Zampini 
739348a46eb9SPierre Jolivet     if (pcbddc->user_primal_vertices_local && !pcbddc->user_primal_vertices) PetscCall(PCBDDCConsistencyCheckIS(pc, MPI_LOR, &pcbddc->user_primal_vertices_local));
7394575ad6abSStefano Zampini     /* Check validity of the csr graph passed in by the user */
73959371c9d4SSatish 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,
73969371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
73979577ea80SStefano Zampini 
7398674ae819SStefano Zampini     /* Set default CSR adjacency of local dofs if not provided by the user with PCBDDCSetLocalAdjacencyGraph */
739966da6bd7Sstefano_zampini     if (!pcbddc->mat_graph->xadj && pcbddc->use_local_adj) {
74004d379d7bSStefano Zampini       PetscInt *xadj, *adjncy;
74014d379d7bSStefano Zampini       PetscInt  nvtxs;
74029de2952eSStefano Zampini       PetscBool flg_row;
74039de2952eSStefano Zampini       Mat       A;
7404674ae819SStefano Zampini 
74059de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
74069de2952eSStefano Zampini       A = matis->A;
74079de2952eSStefano Zampini       for (PetscInt i = 0; i < pcbddc->local_adj_square; i++) {
74089de2952eSStefano Zampini         Mat AtA;
74099de2952eSStefano Zampini 
74109de2952eSStefano Zampini         PetscCall(MatProductCreate(A, A, NULL, &AtA));
74119de2952eSStefano Zampini         PetscCall(MatSetOptionsPrefix(AtA, "pc_bddc_graph_"));
74129de2952eSStefano Zampini         PetscCall(MatProductSetType(AtA, MATPRODUCT_AtB));
74139de2952eSStefano Zampini         PetscCall(MatProductSetFromOptions(AtA));
74149de2952eSStefano Zampini         PetscCall(MatProductSymbolic(AtA));
74159de2952eSStefano Zampini         PetscCall(MatProductClear(AtA));
74169de2952eSStefano Zampini         /* we only need the sparsity, cheat and tell PETSc the matrix has been assembled */
74179de2952eSStefano Zampini         AtA->assembled = PETSC_TRUE;
74189de2952eSStefano Zampini         PetscCall(MatDestroy(&A));
74199de2952eSStefano Zampini         A = AtA;
74209de2952eSStefano Zampini       }
74219de2952eSStefano Zampini       PetscCall(MatGetRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
74222fffb893SStefano Zampini       if (flg_row) {
74239566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLocalAdjacencyGraph(pc, nvtxs, xadj, adjncy, PETSC_COPY_VALUES));
7424b96c3477SStefano Zampini         pcbddc->computed_rowadj = PETSC_TRUE;
74259de2952eSStefano Zampini         PetscCall(MatRestoreRowIJ(A, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &flg_row));
742666da6bd7Sstefano_zampini         rcsr = PETSC_TRUE;
7427674ae819SStefano Zampini       }
74289de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
74299de2952eSStefano Zampini     }
74301baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
7431674ae819SStefano Zampini 
7432ab8c8b98SStefano Zampini     if (pcbddc->mat_graph->cdim && !pcbddc->mat_graph->cloc) {
7433ab8c8b98SStefano Zampini       PetscReal   *lcoords;
7434ab8c8b98SStefano Zampini       PetscInt     n;
7435ab8c8b98SStefano Zampini       MPI_Datatype dimrealtype;
7436ab8c8b98SStefano Zampini 
74374f819b78SStefano Zampini       /* TODO: support for blocked */
743863a3b9bcSJacob 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);
74399566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
74409566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pcbddc->mat_graph->cdim * n, &lcoords));
74419566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_contiguous(pcbddc->mat_graph->cdim, MPIU_REAL, &dimrealtype));
74429566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&dimrealtype));
74439566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
74449566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->sf, dimrealtype, pcbddc->mat_graph->coords, lcoords, MPI_REPLACE));
74459566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&dimrealtype));
74469566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcbddc->mat_graph->coords));
7447ab8c8b98SStefano Zampini 
7448ab8c8b98SStefano Zampini       pcbddc->mat_graph->coords = lcoords;
7449ab8c8b98SStefano Zampini       pcbddc->mat_graph->cloc   = PETSC_TRUE;
7450ab8c8b98SStefano Zampini       pcbddc->mat_graph->cnloc  = n;
7451ab8c8b98SStefano Zampini     }
74529371c9d4SSatish 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,
74539371c9d4SSatish Balay                pcbddc->mat_graph->nvtxs);
7454625961bdSStefano Zampini     pcbddc->mat_graph->active_coords = (PetscBool)(pcbddc->corner_selection && pcbddc->mat_graph->cdim && !pcbddc->corner_selected);
7455ab8c8b98SStefano Zampini 
74564f1b2e48SStefano Zampini     /* attach info on disconnected subdomains if present */
74574f1b2e48SStefano Zampini     if (pcbddc->n_local_subs) {
745820c3699dSStefano Zampini       PetscInt *local_subs, n, totn;
74594f1b2e48SStefano Zampini 
74609566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(matis->A, &n, NULL));
74619566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &local_subs));
746220c3699dSStefano Zampini       for (i = 0; i < n; i++) local_subs[i] = pcbddc->n_local_subs;
74634f1b2e48SStefano Zampini       for (i = 0; i < pcbddc->n_local_subs; i++) {
74644f1b2e48SStefano Zampini         const PetscInt *idxs;
74654f1b2e48SStefano Zampini         PetscInt        nl, j;
74664f1b2e48SStefano Zampini 
74679566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->local_subs[i], &nl));
74689566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->local_subs[i], &idxs));
746971582508SStefano Zampini         for (j = 0; j < nl; j++) local_subs[idxs[j]] = i;
74709566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->local_subs[i], &idxs));
74714f1b2e48SStefano Zampini       }
747220c3699dSStefano Zampini       for (i = 0, totn = 0; i < n; i++) totn = PetscMax(totn, local_subs[i]);
747320c3699dSStefano Zampini       pcbddc->mat_graph->n_local_subs = totn + 1;
74744f1b2e48SStefano Zampini       pcbddc->mat_graph->local_subs   = local_subs;
74754f1b2e48SStefano Zampini     }
74769de2952eSStefano Zampini 
74779de2952eSStefano Zampini     /* Setup of Graph */
74789de2952eSStefano Zampini     PetscCall(PCBDDCGraphSetUp(pcbddc->mat_graph, pcbddc->vertex_size, pcbddc->NeumannBoundariesLocal, pcbddc->DirichletBoundariesLocal, pcbddc->n_ISForDofsLocal, pcbddc->ISForDofsLocal, pcbddc->user_primal_vertices_local));
74798af8fcf9SStefano Zampini   }
74804f1b2e48SStefano Zampini 
7481cac5312eSStefano Zampini   if (!pcbddc->graphanalyzed) {
7482674ae819SStefano Zampini     /* Graph's connected components analysis */
74839566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(pcbddc->mat_graph));
748471582508SStefano Zampini     pcbddc->graphanalyzed   = PETSC_TRUE;
74854f819b78SStefano Zampini     pcbddc->corner_selected = pcbddc->corner_selection;
74868af8fcf9SStefano Zampini   }
748766da6bd7Sstefano_zampini   if (rcsr) pcbddc->mat_graph->nvtxs_csr = 0;
74883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7489674ae819SStefano Zampini }
7490674ae819SStefano Zampini 
7491d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCOrthonormalizeVecs(PetscInt *nio, Vec vecs[])
7492d71ae5a4SJacob Faibussowitsch {
7493295df10fSStefano Zampini   PetscInt     i, j, n;
74949a7d3425SStefano Zampini   PetscScalar *alphas;
7495295df10fSStefano Zampini   PetscReal    norm, *onorms;
74969a7d3425SStefano Zampini 
74979a7d3425SStefano Zampini   PetscFunctionBegin;
7498295df10fSStefano Zampini   n = *nio;
74993ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
75009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n, &alphas, n, &onorms));
75019566063dSJacob Faibussowitsch   PetscCall(VecNormalize(vecs[0], &norm));
750292cccca0SStefano Zampini   if (norm < PETSC_SMALL) {
7503295df10fSStefano Zampini     onorms[0] = 0.0;
75049566063dSJacob Faibussowitsch     PetscCall(VecSet(vecs[0], 0.0));
7505295df10fSStefano Zampini   } else {
7506295df10fSStefano Zampini     onorms[0] = norm;
750792cccca0SStefano Zampini   }
7508295df10fSStefano Zampini 
75098c0031efSStefano Zampini   for (i = 1; i < n; i++) {
75109566063dSJacob Faibussowitsch     PetscCall(VecMDot(vecs[i], i, vecs, alphas));
75118c0031efSStefano Zampini     for (j = 0; j < i; j++) alphas[j] = PetscConj(-alphas[j]);
75129566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(vecs[i], i, alphas, vecs));
75139566063dSJacob Faibussowitsch     PetscCall(VecNormalize(vecs[i], &norm));
751492cccca0SStefano Zampini     if (norm < PETSC_SMALL) {
7515295df10fSStefano Zampini       onorms[i] = 0.0;
75169566063dSJacob Faibussowitsch       PetscCall(VecSet(vecs[i], 0.0));
7517295df10fSStefano Zampini     } else {
7518295df10fSStefano Zampini       onorms[i] = norm;
751992cccca0SStefano Zampini     }
75209a7d3425SStefano Zampini   }
7521295df10fSStefano Zampini   /* push nonzero vectors at the beginning */
7522295df10fSStefano Zampini   for (i = 0; i < n; i++) {
7523295df10fSStefano Zampini     if (onorms[i] == 0.0) {
7524295df10fSStefano Zampini       for (j = i + 1; j < n; j++) {
7525295df10fSStefano Zampini         if (onorms[j] != 0.0) {
75269566063dSJacob Faibussowitsch           PetscCall(VecCopy(vecs[j], vecs[i]));
7527295df10fSStefano Zampini           onorms[j] = 0.0;
7528295df10fSStefano Zampini         }
7529295df10fSStefano Zampini       }
7530295df10fSStefano Zampini     }
7531295df10fSStefano Zampini   }
7532295df10fSStefano Zampini   for (i = 0, *nio = 0; i < n; i++) *nio += onorms[i] != 0.0 ? 1 : 0;
75339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(alphas, onorms));
75343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75359a7d3425SStefano Zampini }
75369a7d3425SStefano Zampini 
7537ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCMatISGetSubassemblingPattern(Mat mat, PetscInt *n_subdomains, PetscInt redprocs, IS *is_sends, PetscBool *have_void)
7538d71ae5a4SJacob Faibussowitsch {
7539e432b41dSStefano Zampini   ISLocalToGlobalMapping mapping;
754057de7509SStefano Zampini   Mat                    A;
7541e7931f94SStefano Zampini   PetscInt               n_neighs, *neighs, *n_shared, **shared;
7542e7931f94SStefano Zampini   PetscMPIInt            size, rank, color;
754352e5ac9dSStefano Zampini   PetscInt              *xadj, *adjncy;
754452e5ac9dSStefano Zampini   PetscInt              *adjncy_wgt, *v_wgt, *ranks_send_to_idx;
7545bb360cb4SStefano Zampini   PetscInt               im_active, active_procs, N, n, i, j, threshold = 2;
754657de7509SStefano Zampini   PetscInt               void_procs, *procs_candidates = NULL;
754727b6a85dSStefano Zampini   PetscInt               xadj_count, *count;
754827b6a85dSStefano Zampini   PetscBool              ismatis, use_vwgt = PETSC_FALSE;
754927b6a85dSStefano Zampini   PetscSubcomm           psubcomm;
755027b6a85dSStefano Zampini   MPI_Comm               subcomm;
7551a57a6d2fSStefano Zampini 
7552e7931f94SStefano Zampini   PetscFunctionBegin;
755357de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
75549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
755528b400f6SJacob 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);
755657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, *n_subdomains, 2);
755757de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, redprocs, 3);
755863a3b9bcSJacob Faibussowitsch   PetscCheck(*n_subdomains > 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Invalid number of subdomains requested %" PetscInt_FMT, *n_subdomains);
755957de7509SStefano Zampini 
756057de7509SStefano Zampini   if (have_void) *have_void = PETSC_FALSE;
75619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
75629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
75639566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &A));
75649566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &n, NULL));
7565bb360cb4SStefano Zampini   im_active = !!n;
75661c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
756757de7509SStefano Zampini   void_procs = size - active_procs;
756815229ffcSPierre Jolivet   /* get ranks of non-active processes in mat communicator */
756957de7509SStefano Zampini   if (void_procs) {
757057de7509SStefano Zampini     PetscInt ncand;
757157de7509SStefano Zampini 
757257de7509SStefano Zampini     if (have_void) *have_void = PETSC_TRUE;
75739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &procs_candidates));
75749566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(&im_active, 1, MPIU_INT, procs_candidates, 1, MPIU_INT, PetscObjectComm((PetscObject)mat)));
757557de7509SStefano Zampini     for (i = 0, ncand = 0; i < size; i++) {
7576ad540459SPierre Jolivet       if (!procs_candidates[i]) procs_candidates[ncand++] = i;
757757de7509SStefano Zampini     }
757857de7509SStefano Zampini     /* force n_subdomains to be not greater that the number of non-active processes */
757957de7509SStefano Zampini     *n_subdomains = PetscMin(void_procs, *n_subdomains);
758057de7509SStefano Zampini   }
758157de7509SStefano Zampini 
7582bb360cb4SStefano Zampini   /* number of subdomains requested greater than active processes or matrix size -> just shift the matrix
75839dddd249SSatish Balay      number of subdomains requested 1 -> send to rank-0 or first candidate in voids  */
75849566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &N, NULL));
7585bb360cb4SStefano Zampini   if (active_procs < *n_subdomains || *n_subdomains == 1 || N <= *n_subdomains) {
758614f0bfb9SStefano Zampini     PetscInt issize, isidx, dest;
758714f0bfb9SStefano Zampini     if (*n_subdomains == 1) dest = 0;
758814f0bfb9SStefano Zampini     else dest = rank;
758957de7509SStefano Zampini     if (im_active) {
759057de7509SStefano Zampini       issize = 1;
759157de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
759214f0bfb9SStefano Zampini         isidx = procs_candidates[dest];
759357de7509SStefano Zampini       } else {
759414f0bfb9SStefano Zampini         isidx = dest;
759557de7509SStefano Zampini       }
759657de7509SStefano Zampini     } else {
759757de7509SStefano Zampini       issize = 0;
759857de7509SStefano Zampini       isidx  = -1;
759957de7509SStefano Zampini     }
7600bb360cb4SStefano Zampini     if (*n_subdomains != 1) *n_subdomains = active_procs;
76019566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), issize, &isidx, PETSC_COPY_VALUES, is_sends));
76029566063dSJacob Faibussowitsch     PetscCall(PetscFree(procs_candidates));
76033ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
760457de7509SStefano Zampini   }
76059de2952eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_use_vwgt", &use_vwgt, NULL));
76069de2952eSStefano Zampini   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)A)->prefix, "-mat_is_partitioning_threshold", &threshold, NULL));
760727b6a85dSStefano Zampini   threshold = PetscMax(threshold, 2);
7608e7931f94SStefano Zampini 
7609e7931f94SStefano Zampini   /* Get info on mapping */
76109566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
76119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
7612e7931f94SStefano Zampini 
7613e7931f94SStefano Zampini   /* build local CSR graph of subdomains' connectivity */
76149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2, &xadj));
7615e7931f94SStefano Zampini   xadj[0] = 0;
7616e7931f94SStefano Zampini   xadj[1] = PetscMax(n_neighs - 1, 0);
76179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy));
76189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xadj[1], &adjncy_wgt));
76199566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(n, &count));
762027b6a85dSStefano Zampini   for (i = 1; i < n_neighs; i++)
76219371c9d4SSatish Balay     for (j = 0; j < n_shared[i]; j++) count[shared[i][j]] += 1;
7622e7931f94SStefano Zampini 
762327b6a85dSStefano Zampini   xadj_count = 0;
76242b510759SStefano Zampini   for (i = 1; i < n_neighs; i++) {
762527b6a85dSStefano Zampini     for (j = 0; j < n_shared[i]; j++) {
762627b6a85dSStefano Zampini       if (count[shared[i][j]] < threshold) {
7627d023bfaeSStefano Zampini         adjncy[xadj_count]     = neighs[i];
7628d023bfaeSStefano Zampini         adjncy_wgt[xadj_count] = n_shared[i];
7629d023bfaeSStefano Zampini         xadj_count++;
763027b6a85dSStefano Zampini         break;
763127b6a85dSStefano Zampini       }
7632e7931f94SStefano Zampini     }
7633e7931f94SStefano Zampini   }
7634d023bfaeSStefano Zampini   xadj[1] = xadj_count;
76359566063dSJacob Faibussowitsch   PetscCall(PetscFree(count));
76369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neighs, &neighs, &n_shared, &shared));
76379566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
7638e7931f94SStefano Zampini 
76399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ranks_send_to_idx));
7640e7931f94SStefano Zampini 
764127b6a85dSStefano Zampini   /* Restrict work on active processes only */
76429566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(im_active, &color));
764327b6a85dSStefano Zampini   if (void_procs) {
76449566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)mat), &psubcomm));
76459566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(psubcomm, 2)); /* 2 groups, active process and not active processes */
76469566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetTypeGeneral(psubcomm, color, rank));
764727b6a85dSStefano Zampini     subcomm = PetscSubcommChild(psubcomm);
764827b6a85dSStefano Zampini   } else {
764927b6a85dSStefano Zampini     psubcomm = NULL;
765027b6a85dSStefano Zampini     subcomm  = PetscObjectComm((PetscObject)mat);
765127b6a85dSStefano Zampini   }
765227b6a85dSStefano Zampini 
765327b6a85dSStefano Zampini   v_wgt = NULL;
765427b6a85dSStefano Zampini   if (!color) {
76559566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
76569566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
76579566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy_wgt));
7658c8587f34SStefano Zampini   } else {
765952e5ac9dSStefano Zampini     Mat             subdomain_adj;
766052e5ac9dSStefano Zampini     IS              new_ranks, new_ranks_contig;
766152e5ac9dSStefano Zampini     MatPartitioning partitioner;
766227b6a85dSStefano Zampini     PetscInt        rstart = 0, rend = 0;
766352e5ac9dSStefano Zampini     PetscInt       *is_indices, *oldranks;
766457de7509SStefano Zampini     PetscMPIInt     size;
7665b0c7d250SStefano Zampini     PetscBool       aggregate;
7666b0c7d250SStefano Zampini 
76679566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(subcomm, &size));
766827b6a85dSStefano Zampini     if (void_procs) {
766927b6a85dSStefano Zampini       PetscInt prank = rank;
76709566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &oldranks));
76719566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allgather(&prank, 1, MPIU_INT, oldranks, 1, MPIU_INT, subcomm));
767248a46eb9SPierre Jolivet       for (i = 0; i < xadj[1]; i++) PetscCall(PetscFindInt(adjncy[i], size, oldranks, &adjncy[i]));
76739566063dSJacob Faibussowitsch       PetscCall(PetscSortIntWithArray(xadj[1], adjncy, adjncy_wgt));
767427b6a85dSStefano Zampini     } else {
767527b6a85dSStefano Zampini       oldranks = NULL;
767627b6a85dSStefano Zampini     }
7677b0c7d250SStefano Zampini     aggregate = ((redprocs > 0 && redprocs < size) ? PETSC_TRUE : PETSC_FALSE);
767827b6a85dSStefano Zampini     if (aggregate) { /* TODO: all this part could be made more efficient */
7679b0c7d250SStefano Zampini       PetscInt     lrows, row, ncols, *cols;
7680b0c7d250SStefano Zampini       PetscMPIInt  nrank;
7681b0c7d250SStefano Zampini       PetscScalar *vals;
7682b0c7d250SStefano Zampini 
76839566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(subcomm, &nrank));
7684b0c7d250SStefano Zampini       lrows = 0;
7685b0c7d250SStefano Zampini       if (nrank < redprocs) {
7686b0c7d250SStefano Zampini         lrows = size / redprocs;
7687b0c7d250SStefano Zampini         if (nrank < size % redprocs) lrows++;
7688b0c7d250SStefano Zampini       }
76899566063dSJacob Faibussowitsch       PetscCall(MatCreateAIJ(subcomm, lrows, lrows, size, size, 50, NULL, 50, NULL, &subdomain_adj));
76909566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(subdomain_adj, &rstart, &rend));
76919566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
76929566063dSJacob Faibussowitsch       PetscCall(MatSetOption(subdomain_adj, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
7693b0c7d250SStefano Zampini       row   = nrank;
7694b0c7d250SStefano Zampini       ncols = xadj[1] - xadj[0];
7695b0c7d250SStefano Zampini       cols  = adjncy;
76969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncols, &vals));
7697b0c7d250SStefano Zampini       for (i = 0; i < ncols; i++) vals[i] = adjncy_wgt[i];
76989566063dSJacob Faibussowitsch       PetscCall(MatSetValues(subdomain_adj, 1, &row, ncols, cols, vals, INSERT_VALUES));
76999566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(subdomain_adj, MAT_FINAL_ASSEMBLY));
77009566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(subdomain_adj, MAT_FINAL_ASSEMBLY));
77019566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj));
77029566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy));
77039566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_wgt));
77049566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
770527b6a85dSStefano Zampini       if (use_vwgt) {
770627b6a85dSStefano Zampini         Vec                v;
770727b6a85dSStefano Zampini         const PetscScalar *array;
770827b6a85dSStefano Zampini         PetscInt           nl;
770927b6a85dSStefano Zampini 
77109566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(subdomain_adj, &v, NULL));
77119566063dSJacob Faibussowitsch         PetscCall(VecSetValue(v, row, (PetscScalar)n, INSERT_VALUES));
77129566063dSJacob Faibussowitsch         PetscCall(VecAssemblyBegin(v));
77139566063dSJacob Faibussowitsch         PetscCall(VecAssemblyEnd(v));
77149566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(v, &nl));
77159566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(v, &array));
77169566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nl, &v_wgt));
771722db5ddcSStefano Zampini         for (i = 0; i < nl; i++) v_wgt[i] = (PetscInt)PetscRealPart(array[i]);
77189566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(v, &array));
77199566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
772027b6a85dSStefano Zampini       }
7721b0c7d250SStefano Zampini     } else {
77229566063dSJacob Faibussowitsch       PetscCall(MatCreateMPIAdj(subcomm, 1, (PetscInt)size, xadj, adjncy, adjncy_wgt, &subdomain_adj));
772327b6a85dSStefano Zampini       if (use_vwgt) {
77249566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(1, &v_wgt));
7725bb360cb4SStefano Zampini         v_wgt[0] = n;
772627b6a85dSStefano Zampini       }
7727b0c7d250SStefano Zampini     }
77289566063dSJacob Faibussowitsch     /* PetscCall(MatView(subdomain_adj,0)); */
7729e7931f94SStefano Zampini 
7730e7931f94SStefano Zampini     /* Partition */
77319566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(subcomm, &partitioner));
7732ce64c636SStefano Zampini #if defined(PETSC_HAVE_PTSCOTCH)
77339566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPTSCOTCH));
7734ce64c636SStefano Zampini #elif defined(PETSC_HAVE_PARMETIS)
77359566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGPARMETIS));
7736ce64c636SStefano Zampini #else
77379566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetType(partitioner, MATPARTITIONINGAVERAGE));
7738ce64c636SStefano Zampini #endif
77399566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(partitioner, subdomain_adj));
77401baa6e33SBarry Smith     if (v_wgt) PetscCall(MatPartitioningSetVertexWeights(partitioner, v_wgt));
774157de7509SStefano Zampini     *n_subdomains = PetscMin((PetscInt)size, *n_subdomains);
77429566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetNParts(partitioner, *n_subdomains));
77439566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(partitioner));
77449566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApply(partitioner, &new_ranks));
77459566063dSJacob Faibussowitsch     /* PetscCall(MatPartitioningView(partitioner,0)); */
7746e7931f94SStefano Zampini 
774752e5ac9dSStefano Zampini     /* renumber new_ranks to avoid "holes" in new set of processors */
77489566063dSJacob Faibussowitsch     PetscCall(ISRenumber(new_ranks, NULL, NULL, &new_ranks_contig));
77499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks));
77509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(new_ranks_contig, (const PetscInt **)&is_indices));
775157de7509SStefano Zampini     if (!aggregate) {
775257de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
77536bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
775457de7509SStefano Zampini         ranks_send_to_idx[0] = procs_candidates[oldranks[is_indices[0]]];
775527b6a85dSStefano Zampini       } else if (oldranks) {
7756b0c7d250SStefano Zampini         ranks_send_to_idx[0] = oldranks[is_indices[0]];
775727b6a85dSStefano Zampini       } else {
775827b6a85dSStefano Zampini         ranks_send_to_idx[0] = is_indices[0];
775957de7509SStefano Zampini       }
776028143c3dSStefano Zampini     } else {
77617fb8a5e4SKarl Rupp       PetscInt     idx = 0;
7762b0c7d250SStefano Zampini       PetscMPIInt  tag;
7763b0c7d250SStefano Zampini       MPI_Request *reqs;
7764b0c7d250SStefano Zampini 
77659566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetNewTag((PetscObject)subdomain_adj, &tag));
77669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(rend - rstart, &reqs));
776748a46eb9SPierre Jolivet       for (i = rstart; i < rend; i++) PetscCallMPI(MPI_Isend(is_indices + i - rstart, 1, MPIU_INT, i, tag, subcomm, &reqs[i - rstart]));
77689566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Recv(&idx, 1, MPIU_INT, MPI_ANY_SOURCE, tag, subcomm, MPI_STATUS_IGNORE));
77699566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Waitall(rend - rstart, reqs, MPI_STATUSES_IGNORE));
77709566063dSJacob Faibussowitsch       PetscCall(PetscFree(reqs));
777157de7509SStefano Zampini       if (procs_candidates) { /* shift the pattern on non-active candidates (if any) */
77726bdcaf15SBarry Smith         PetscAssert(oldranks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This should not happen");
77737fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = procs_candidates[oldranks[idx]];
777427b6a85dSStefano Zampini       } else if (oldranks) {
77757fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = oldranks[idx];
777627b6a85dSStefano Zampini       } else {
77777fb8a5e4SKarl Rupp         ranks_send_to_idx[0] = idx;
777828143c3dSStefano Zampini       }
777957de7509SStefano Zampini     }
77809566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(new_ranks_contig, (const PetscInt **)&is_indices));
7781e7931f94SStefano Zampini     /* clean up */
77829566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldranks));
77839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_ranks_contig));
77849566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&subdomain_adj));
77859566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&partitioner));
7786e7931f94SStefano Zampini   }
77879566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&psubcomm));
77889566063dSJacob Faibussowitsch   PetscCall(PetscFree(procs_candidates));
7789e7931f94SStefano Zampini 
7790e7931f94SStefano Zampini   /* assemble parallel IS for sends */
7791e7931f94SStefano Zampini   i = 1;
779227b6a85dSStefano Zampini   if (!color) i = 0;
77939566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), i, ranks_send_to_idx, PETSC_OWN_POINTER, is_sends));
77943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7795e7931f94SStefano Zampini }
7796e7931f94SStefano Zampini 
77979371c9d4SSatish Balay typedef enum {
77989371c9d4SSatish Balay   MATDENSE_PRIVATE = 0,
77999371c9d4SSatish Balay   MATAIJ_PRIVATE,
78009371c9d4SSatish Balay   MATBAIJ_PRIVATE,
78019371c9d4SSatish Balay   MATSBAIJ_PRIVATE
78029371c9d4SSatish Balay } MatTypePrivate;
7803e7931f94SStefano Zampini 
7804ba38deedSJacob Faibussowitsch static PetscErrorCode PCBDDCMatISSubassemble(Mat mat, IS is_sends, PetscInt n_subdomains, PetscBool restrict_comm, PetscBool restrict_full, PetscBool reuse, Mat *mat_n, PetscInt nis, IS isarray[], PetscInt nvecs, Vec nnsp_vec[])
7805d71ae5a4SJacob Faibussowitsch {
780670cf5478SStefano Zampini   Mat                    local_mat;
7807e7931f94SStefano Zampini   IS                     is_sends_internal;
78089d30be91SStefano Zampini   PetscInt               rows, cols, new_local_rows;
78091ae86dd6SStefano Zampini   PetscInt               i, bs, buf_size_idxs, buf_size_idxs_is, buf_size_vals, buf_size_vecs;
78109d30be91SStefano Zampini   PetscBool              ismatis, isdense, newisdense, destroy_mat;
7811e7931f94SStefano Zampini   ISLocalToGlobalMapping l2gmap;
7812e7931f94SStefano Zampini   PetscInt              *l2gmap_indices;
7813e7931f94SStefano Zampini   const PetscInt        *is_indices;
7814e7931f94SStefano Zampini   MatType                new_local_type;
7815e7931f94SStefano Zampini   /* buffers */
7816e7931f94SStefano Zampini   PetscInt          *ptr_idxs, *send_buffer_idxs, *recv_buffer_idxs;
781728143c3dSStefano Zampini   PetscInt          *ptr_idxs_is, *send_buffer_idxs_is, *recv_buffer_idxs_is;
78189d30be91SStefano Zampini   PetscInt          *recv_buffer_idxs_local;
78191683a169SBarry Smith   PetscScalar       *ptr_vals, *recv_buffer_vals;
78201683a169SBarry Smith   const PetscScalar *send_buffer_vals;
78211ae86dd6SStefano Zampini   PetscScalar       *ptr_vecs, *send_buffer_vecs, *recv_buffer_vecs;
7822e7931f94SStefano Zampini   /* MPI */
782328143c3dSStefano Zampini   MPI_Comm     comm, comm_n;
782428143c3dSStefano Zampini   PetscSubcomm subcomm;
7825e569e4e1SStefano Zampini   PetscMPIInt  n_sends, n_recvs, size;
782628143c3dSStefano Zampini   PetscMPIInt *iflags, *ilengths_idxs, *ilengths_vals, *ilengths_idxs_is;
782728143c3dSStefano Zampini   PetscMPIInt *onodes, *onodes_is, *olengths_idxs, *olengths_idxs_is, *olengths_vals;
78281ae86dd6SStefano Zampini   PetscMPIInt  len, tag_idxs, tag_idxs_is, tag_vals, tag_vecs, source_dest;
78291ae86dd6SStefano Zampini   MPI_Request *send_req_idxs, *send_req_idxs_is, *send_req_vals, *send_req_vecs;
78301ae86dd6SStefano Zampini   MPI_Request *recv_req_idxs, *recv_req_idxs_is, *recv_req_vals, *recv_req_vecs;
7831e7931f94SStefano Zampini 
7832e7931f94SStefano Zampini   PetscFunctionBegin;
783357de7509SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
78349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATIS, &ismatis));
78355f80ce2aSJacob 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);
783657de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, n_subdomains, 3);
783757de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_comm, 4);
783857de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, restrict_full, 5);
783957de7509SStefano Zampini   PetscValidLogicalCollectiveBool(mat, reuse, 6);
784057de7509SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nis, 8);
78411ae86dd6SStefano Zampini   PetscValidLogicalCollectiveInt(mat, nvecs, 10);
78421ae86dd6SStefano Zampini   if (nvecs) {
784308401ef6SPierre Jolivet     PetscCheck(nvecs <= 1, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Just 1 vector supported");
78441ae86dd6SStefano Zampini     PetscValidHeaderSpecific(nnsp_vec[0], VEC_CLASSID, 11);
78451ae86dd6SStefano Zampini   }
784657de7509SStefano Zampini   /* further checks */
78479566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &local_mat));
78489566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
78499de2952eSStefano Zampini   /* XXX hack for multi_element */
78509de2952eSStefano Zampini   if (!isdense) PetscCall(MatConvert(local_mat, MATDENSE, MAT_INPLACE_MATRIX, &local_mat));
78519de2952eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &isdense));
78525f80ce2aSJacob Faibussowitsch   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Currently cannot subassemble MATIS when local matrix type is not of type SEQDENSE");
78539de2952eSStefano Zampini 
78549566063dSJacob Faibussowitsch   PetscCall(MatGetSize(local_mat, &rows, &cols));
78555f80ce2aSJacob Faibussowitsch   PetscCheck(rows == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Local MATIS matrices should be square");
785657de7509SStefano Zampini   if (reuse && *mat_n) {
785770cf5478SStefano Zampini     PetscInt mrows, mcols, mnrows, mncols;
785857de7509SStefano Zampini     PetscValidHeaderSpecific(*mat_n, MAT_CLASSID, 7);
78599566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*mat_n, MATIS, &ismatis));
78605f80ce2aSJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_SUP, "Cannot reuse a matrix which is not of type MATIS");
78619566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &mrows, &mcols));
78629566063dSJacob Faibussowitsch     PetscCall(MatGetSize(*mat_n, &mnrows, &mncols));
786363a3b9bcSJacob Faibussowitsch     PetscCheck(mrows == mnrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of rows %" PetscInt_FMT " != %" PetscInt_FMT, mrows, mnrows);
786463a3b9bcSJacob Faibussowitsch     PetscCheck(mcols == mncols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix! Wrong number of cols %" PetscInt_FMT " != %" PetscInt_FMT, mcols, mncols);
786570cf5478SStefano Zampini   }
78669566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(local_mat, &bs));
7867064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(mat, bs, 1);
786857de7509SStefano Zampini 
7869e7931f94SStefano Zampini   /* prepare IS for sending if not provided */
7870e7931f94SStefano Zampini   if (!is_sends) {
78715f80ce2aSJacob Faibussowitsch     PetscCheck(n_subdomains, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "You should specify either an IS or a target number of subdomains");
78729566063dSJacob Faibussowitsch     PetscCall(PCBDDCMatISGetSubassemblingPattern(mat, &n_subdomains, 0, &is_sends_internal, NULL));
7873c8587f34SStefano Zampini   } else {
78749566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is_sends));
7875e7931f94SStefano Zampini     is_sends_internal = is_sends;
7876c8587f34SStefano Zampini   }
7877e7931f94SStefano Zampini 
7878e7931f94SStefano Zampini   /* get comm */
78799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7880e7931f94SStefano Zampini 
7881e7931f94SStefano Zampini   /* compute number of sends */
78829566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is_sends_internal, &i));
78839566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(i, &n_sends));
7884e7931f94SStefano Zampini 
7885e7931f94SStefano Zampini   /* compute number of receives */
78869566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
78879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &iflags));
78889566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(iflags, size));
78899566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is_sends_internal, &is_indices));
7890e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) iflags[is_indices[i]] = 1;
78919566063dSJacob Faibussowitsch   PetscCall(PetscGatherNumberOfMessages(comm, iflags, NULL, &n_recvs));
78929566063dSJacob Faibussowitsch   PetscCall(PetscFree(iflags));
7893e7931f94SStefano Zampini 
789428143c3dSStefano Zampini   /* restrict comm if requested */
78950a545947SLisandro Dalcin   subcomm     = NULL;
789628143c3dSStefano Zampini   destroy_mat = PETSC_FALSE;
789728143c3dSStefano Zampini   if (restrict_comm) {
7898779c1cceSStefano Zampini     PetscMPIInt color, subcommsize;
7899779c1cceSStefano Zampini 
790028143c3dSStefano Zampini     color = 0;
790153a05cb3SStefano Zampini     if (restrict_full) {
79026aad120cSJose E. Roman       if (!n_recvs) color = 1; /* processes not receiving anything will not participate in new comm (full restriction) */
790353a05cb3SStefano Zampini     } else {
79046aad120cSJose 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 */
790553a05cb3SStefano Zampini     }
79061c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&color, &subcommsize, 1, MPI_INT, MPI_SUM, comm));
7907e569e4e1SStefano Zampini     subcommsize = size - subcommsize;
790828143c3dSStefano Zampini     /* check if reuse has been requested */
790957de7509SStefano Zampini     if (reuse) {
791028143c3dSStefano Zampini       if (*mat_n) {
791128143c3dSStefano Zampini         PetscMPIInt subcommsize2;
79129566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)*mat_n), &subcommsize2));
79135f80ce2aSJacob Faibussowitsch         PetscCheck(subcommsize == subcommsize2, PetscObjectComm((PetscObject)*mat_n), PETSC_ERR_PLIB, "Cannot reuse matrix! wrong subcomm size %d != %d", subcommsize, subcommsize2);
791428143c3dSStefano Zampini         comm_n = PetscObjectComm((PetscObject)*mat_n);
791528143c3dSStefano Zampini       } else {
791628143c3dSStefano Zampini         comm_n = PETSC_COMM_SELF;
791728143c3dSStefano Zampini       }
791828143c3dSStefano Zampini     } else { /* MAT_INITIAL_MATRIX */
7919779c1cceSStefano Zampini       PetscMPIInt rank;
7920779c1cceSStefano Zampini 
79219566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
79229566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &subcomm));
79239566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(subcomm, 2));
79249566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
7925306c2d5bSBarry Smith       comm_n = PetscSubcommChild(subcomm);
792628143c3dSStefano Zampini     }
792728143c3dSStefano Zampini     /* flag to destroy *mat_n if not significative */
792828143c3dSStefano Zampini     if (color) destroy_mat = PETSC_TRUE;
792928143c3dSStefano Zampini   } else {
793028143c3dSStefano Zampini     comm_n = comm;
793128143c3dSStefano Zampini   }
793228143c3dSStefano Zampini 
7933e7931f94SStefano Zampini   /* prepare send/receive buffers */
79349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_idxs));
79359566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_idxs, size));
79369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &ilengths_vals));
79379566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ilengths_vals, size));
793848a46eb9SPierre Jolivet   if (nis) PetscCall(PetscCalloc1(size, &ilengths_idxs_is));
7939e7931f94SStefano Zampini 
794028143c3dSStefano Zampini   /* Get data from local matrices */
7941e432b41dSStefano Zampini   PetscCheck(isdense, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Subassembling of AIJ local matrices not yet implemented");
7942e7931f94SStefano Zampini   /* TODO: See below some guidelines on how to prepare the local buffers */
7943e7931f94SStefano Zampini   /*
7944e7931f94SStefano Zampini        send_buffer_vals should contain the raw values of the local matrix
7945e7931f94SStefano Zampini        send_buffer_idxs should contain:
7946e7931f94SStefano Zampini        - MatType_PRIVATE type
7947e7931f94SStefano Zampini        - PetscInt        size_of_l2gmap
7948e7931f94SStefano Zampini        - PetscInt        global_row_indices[size_of_l2gmap]
7949e7931f94SStefano Zampini        - PetscInt        all_other_info_which_is_needed_to_compute_preallocation_and_set_values
7950e7931f94SStefano Zampini     */
7951e432b41dSStefano Zampini   {
7952e432b41dSStefano Zampini     ISLocalToGlobalMapping mapping;
7953e432b41dSStefano Zampini 
79549566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(mat, &mapping, NULL));
79559566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &send_buffer_vals));
79569566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(mapping, &i));
79579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(i + 2, &send_buffer_idxs));
7958e7931f94SStefano Zampini     send_buffer_idxs[0] = (PetscInt)MATDENSE_PRIVATE;
7959e7931f94SStefano Zampini     send_buffer_idxs[1] = i;
79609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(mapping, (const PetscInt **)&ptr_idxs));
79619566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&send_buffer_idxs[2], ptr_idxs, i));
79629566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, (const PetscInt **)&ptr_idxs));
79639566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(i, &len));
7964e7931f94SStefano Zampini     for (i = 0; i < n_sends; i++) {
7965e7931f94SStefano Zampini       ilengths_vals[is_indices[i]] = len * len;
7966e7931f94SStefano Zampini       ilengths_idxs[is_indices[i]] = len + 2;
7967c8587f34SStefano Zampini     }
7968c8587f34SStefano Zampini   }
79699566063dSJacob Faibussowitsch   PetscCall(PetscGatherMessageLengths2(comm, n_sends, n_recvs, ilengths_idxs, ilengths_vals, &onodes, &olengths_idxs, &olengths_vals));
797028143c3dSStefano Zampini   /* additional is (if any) */
797128143c3dSStefano Zampini   if (nis) {
797228143c3dSStefano Zampini     PetscMPIInt psum;
797328143c3dSStefano Zampini     PetscInt    j;
797428143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
797528143c3dSStefano Zampini       PetscInt plen;
79769566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
79779566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(plen, &len));
79786aad120cSJose E. Roman       psum += len + 1; /* indices + length */
797928143c3dSStefano Zampini     }
79809566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &send_buffer_idxs_is));
798128143c3dSStefano Zampini     for (j = 0, psum = 0; j < nis; j++) {
798228143c3dSStefano Zampini       PetscInt        plen;
798328143c3dSStefano Zampini       const PetscInt *is_array_idxs;
79849566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isarray[j], &plen));
798528143c3dSStefano Zampini       send_buffer_idxs_is[psum] = plen;
79869566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isarray[j], &is_array_idxs));
79879566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(&send_buffer_idxs_is[psum + 1], is_array_idxs, plen));
79889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isarray[j], &is_array_idxs));
79896aad120cSJose E. Roman       psum += plen + 1; /* indices + length */
799028143c3dSStefano Zampini     }
7991ad540459SPierre Jolivet     for (i = 0; i < n_sends; i++) ilengths_idxs_is[is_indices[i]] = psum;
79929566063dSJacob Faibussowitsch     PetscCall(PetscGatherMessageLengths(comm, n_sends, n_recvs, ilengths_idxs_is, &onodes_is, &olengths_idxs_is));
799328143c3dSStefano Zampini   }
79949566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(mat, &local_mat));
799528143c3dSStefano Zampini 
7996e7931f94SStefano Zampini   buf_size_idxs    = 0;
7997e7931f94SStefano Zampini   buf_size_vals    = 0;
799828143c3dSStefano Zampini   buf_size_idxs_is = 0;
79991ae86dd6SStefano Zampini   buf_size_vecs    = 0;
8000e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8001e7931f94SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
8002e7931f94SStefano Zampini     buf_size_vals += (PetscInt)olengths_vals[i];
800328143c3dSStefano Zampini     if (nis) buf_size_idxs_is += (PetscInt)olengths_idxs_is[i];
80041ae86dd6SStefano Zampini     if (nvecs) buf_size_vecs += (PetscInt)olengths_idxs[i];
8005e7931f94SStefano Zampini   }
80069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs));
80079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vals, &recv_buffer_vals));
80089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs_is, &recv_buffer_idxs_is));
80099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_vecs, &recv_buffer_vecs));
8010e7931f94SStefano Zampini 
8011e7931f94SStefano Zampini   /* get new tags for clean communications */
80129566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs));
80139566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vals));
80149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_idxs_is));
80159566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag_vecs));
8016e7931f94SStefano Zampini 
8017e7931f94SStefano Zampini   /* allocate for requests */
80189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs));
80199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vals));
80209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_idxs_is));
80219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_sends, &send_req_vecs));
80229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs));
80239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vals));
80249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_idxs_is));
80259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_recvs, &recv_req_vecs));
8026e7931f94SStefano Zampini 
8027e7931f94SStefano Zampini   /* communications */
8028e7931f94SStefano Zampini   ptr_idxs    = recv_buffer_idxs;
8029e7931f94SStefano Zampini   ptr_vals    = recv_buffer_vals;
803028143c3dSStefano Zampini   ptr_idxs_is = recv_buffer_idxs_is;
80311ae86dd6SStefano Zampini   ptr_vecs    = recv_buffer_vecs;
8032e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8033e7931f94SStefano Zampini     source_dest = onodes[i];
80349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_idxs, olengths_idxs[i], MPIU_INT, source_dest, tag_idxs, comm, &recv_req_idxs[i]));
80359566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(ptr_vals, olengths_vals[i], MPIU_SCALAR, source_dest, tag_vals, comm, &recv_req_vals[i]));
8036e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8037e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
803828143c3dSStefano Zampini     if (nis) {
803957de7509SStefano Zampini       source_dest = onodes_is[i];
80409566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_idxs_is, olengths_idxs_is[i], MPIU_INT, source_dest, tag_idxs_is, comm, &recv_req_idxs_is[i]));
804128143c3dSStefano Zampini       ptr_idxs_is += olengths_idxs_is[i];
804228143c3dSStefano Zampini     }
80431ae86dd6SStefano Zampini     if (nvecs) {
80441ae86dd6SStefano Zampini       source_dest = onodes[i];
80459566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Irecv(ptr_vecs, olengths_idxs[i] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &recv_req_vecs[i]));
80461ae86dd6SStefano Zampini       ptr_vecs += olengths_idxs[i] - 2;
80471ae86dd6SStefano Zampini     }
8048e7931f94SStefano Zampini   }
8049e7931f94SStefano Zampini   for (i = 0; i < n_sends; i++) {
80509566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(is_indices[i], &source_dest));
80519566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(send_buffer_idxs, ilengths_idxs[source_dest], MPIU_INT, source_dest, tag_idxs, comm, &send_req_idxs[i]));
80529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend((PetscScalar *)send_buffer_vals, ilengths_vals[source_dest], MPIU_SCALAR, source_dest, tag_vals, comm, &send_req_vals[i]));
805348a46eb9SPierre 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]));
80541ae86dd6SStefano Zampini     if (nvecs) {
80559566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
80569566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Isend(send_buffer_vecs, ilengths_idxs[source_dest] - 2, MPIU_SCALAR, source_dest, tag_vecs, comm, &send_req_vecs[i]));
80571ae86dd6SStefano Zampini     }
8058e7931f94SStefano Zampini   }
80599566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is_sends_internal, &is_indices));
80609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_sends_internal));
8061e7931f94SStefano Zampini 
8062e7931f94SStefano Zampini   /* assemble new l2g map */
80639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs, MPI_STATUSES_IGNORE));
8064e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
80659d30be91SStefano Zampini   new_local_rows = 0;
8066e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
80679d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8068e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8069e7931f94SStefano Zampini   }
80709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(new_local_rows, &l2gmap_indices));
8071e7931f94SStefano Zampini   ptr_idxs       = recv_buffer_idxs;
80729d30be91SStefano Zampini   new_local_rows = 0;
8073e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
80749566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&l2gmap_indices[new_local_rows], ptr_idxs + 2, *(ptr_idxs + 1)));
80759d30be91SStefano Zampini     new_local_rows += *(ptr_idxs + 1); /* second element is the local size of the l2gmap */
8076e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8077e7931f94SStefano Zampini   }
80789566063dSJacob Faibussowitsch   PetscCall(PetscSortRemoveDupsInt(&new_local_rows, l2gmap_indices));
80799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(comm_n, 1, new_local_rows, l2gmap_indices, PETSC_COPY_VALUES, &l2gmap));
80809566063dSJacob Faibussowitsch   PetscCall(PetscFree(l2gmap_indices));
8081e7931f94SStefano Zampini 
8082e7931f94SStefano Zampini   /* infer new local matrix type from received local matrices type */
8083e7931f94SStefano Zampini   /* currently if all local matrices are of type X, then the resulting matrix will be of type X, except for the dense case */
8084e7931f94SStefano 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) */
8085e7931f94SStefano Zampini   if (n_recvs) {
808628143c3dSStefano Zampini     MatTypePrivate new_local_type_private = (MatTypePrivate)send_buffer_idxs[0];
8087e7931f94SStefano Zampini     ptr_idxs                              = recv_buffer_idxs;
8088e7931f94SStefano Zampini     for (i = 0; i < n_recvs; i++) {
8089e7931f94SStefano Zampini       if ((PetscInt)new_local_type_private != *ptr_idxs) {
8090e7931f94SStefano Zampini         new_local_type_private = MATAIJ_PRIVATE;
8091e7931f94SStefano Zampini         break;
8092e7931f94SStefano Zampini       }
8093e7931f94SStefano Zampini       ptr_idxs += olengths_idxs[i];
8094e7931f94SStefano Zampini     }
8095e7931f94SStefano Zampini     switch (new_local_type_private) {
809628143c3dSStefano Zampini     case MATDENSE_PRIVATE:
8097e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8098e7931f94SStefano Zampini       bs             = 1;
8099e7931f94SStefano Zampini       break;
8100e7931f94SStefano Zampini     case MATAIJ_PRIVATE:
8101e7931f94SStefano Zampini       new_local_type = MATSEQAIJ;
8102e7931f94SStefano Zampini       bs             = 1;
8103e7931f94SStefano Zampini       break;
8104d71ae5a4SJacob Faibussowitsch     case MATBAIJ_PRIVATE:
8105d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQBAIJ;
8106d71ae5a4SJacob Faibussowitsch       break;
8107d71ae5a4SJacob Faibussowitsch     case MATSBAIJ_PRIVATE:
8108d71ae5a4SJacob Faibussowitsch       new_local_type = MATSEQSBAIJ;
8109d71ae5a4SJacob Faibussowitsch       break;
8110d71ae5a4SJacob Faibussowitsch     default:
8111d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Unsupported private type %d in %s", new_local_type_private, PETSC_FUNCTION_NAME);
8112e7931f94SStefano Zampini     }
8113ed8ed4edSstefano_zampini   } else { /* by default, new_local_type is seqaij */
8114ed8ed4edSstefano_zampini     new_local_type = MATSEQAIJ;
811528143c3dSStefano Zampini     bs             = 1;
8116e7931f94SStefano Zampini   }
8117e7931f94SStefano Zampini 
811870cf5478SStefano Zampini   /* create MATIS object if needed */
811957de7509SStefano Zampini   if (!reuse) {
81209566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &rows, &cols));
81219566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
812270cf5478SStefano Zampini   } else {
812370cf5478SStefano Zampini     /* it also destroys the local matrices */
812457de7509SStefano Zampini     if (*mat_n) {
81259566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*mat_n, l2gmap, l2gmap));
812657de7509SStefano Zampini     } else { /* this is a fake object */
81279566063dSJacob Faibussowitsch       PetscCall(MatCreateIS(comm_n, bs, PETSC_DECIDE, PETSC_DECIDE, rows, cols, l2gmap, l2gmap, mat_n));
812857de7509SStefano Zampini     }
812970cf5478SStefano Zampini   }
81309566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(*mat_n, &local_mat));
81319566063dSJacob Faibussowitsch   PetscCall(MatSetType(local_mat, new_local_type));
81329d30be91SStefano Zampini 
81339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vals, MPI_STATUSES_IGNORE));
81349d30be91SStefano Zampini 
81359d30be91SStefano Zampini   /* Global to local map of received indices */
81369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(buf_size_idxs, &recv_buffer_idxs_local)); /* needed for values insertion */
81379566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(l2gmap, IS_GTOLM_MASK, buf_size_idxs, recv_buffer_idxs, &i, recv_buffer_idxs_local));
81389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&l2gmap));
81399d30be91SStefano Zampini 
81409d30be91SStefano Zampini   /* restore attributes -> type of incoming data and its size */
81419d30be91SStefano Zampini   buf_size_idxs = 0;
81429d30be91SStefano Zampini   for (i = 0; i < n_recvs; i++) {
81439d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs]     = recv_buffer_idxs[buf_size_idxs];
81449d30be91SStefano Zampini     recv_buffer_idxs_local[buf_size_idxs + 1] = recv_buffer_idxs[buf_size_idxs + 1];
81459d30be91SStefano Zampini     buf_size_idxs += (PetscInt)olengths_idxs[i];
81469d30be91SStefano Zampini   }
81479566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs));
81489d30be91SStefano Zampini 
81499d30be91SStefano Zampini   /* set preallocation */
81509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)local_mat, MATSEQDENSE, &newisdense));
81519d30be91SStefano Zampini   if (!newisdense) {
81520a545947SLisandro Dalcin     PetscInt *new_local_nnz = NULL;
81539d30be91SStefano Zampini 
81549d30be91SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
815548a46eb9SPierre Jolivet     if (n_recvs) PetscCall(PetscCalloc1(new_local_rows, &new_local_nnz));
81569d30be91SStefano Zampini     for (i = 0; i < n_recvs; i++) {
81579d30be91SStefano Zampini       PetscInt j;
81589d30be91SStefano Zampini       if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* preallocation provided for dense case only */
8159ad540459SPierre Jolivet         for (j = 0; j < *(ptr_idxs + 1); j++) new_local_nnz[*(ptr_idxs + 2 + j)] += *(ptr_idxs + 1);
81609d30be91SStefano Zampini       } else {
81619d30be91SStefano Zampini         /* TODO */
81629d30be91SStefano Zampini       }
81639d30be91SStefano Zampini       ptr_idxs += olengths_idxs[i];
81649d30be91SStefano Zampini     }
81659d30be91SStefano Zampini     if (new_local_nnz) {
81669d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMin(new_local_nnz[i], new_local_rows);
81679566063dSJacob Faibussowitsch       PetscCall(MatSeqAIJSetPreallocation(local_mat, 0, new_local_nnz));
81689d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] /= bs;
81699566063dSJacob Faibussowitsch       PetscCall(MatSeqBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
81709d30be91SStefano Zampini       for (i = 0; i < new_local_rows; i++) new_local_nnz[i] = PetscMax(new_local_nnz[i] - i, 0);
81719566063dSJacob Faibussowitsch       PetscCall(MatSeqSBAIJSetPreallocation(local_mat, bs, 0, new_local_nnz));
81729d30be91SStefano Zampini     } else {
81739566063dSJacob Faibussowitsch       PetscCall(MatSetUp(local_mat));
81749d30be91SStefano Zampini     }
81759566063dSJacob Faibussowitsch     PetscCall(PetscFree(new_local_nnz));
81769d30be91SStefano Zampini   } else {
81779566063dSJacob Faibussowitsch     PetscCall(MatSetUp(local_mat));
81789d30be91SStefano Zampini   }
8179e7931f94SStefano Zampini 
8180e7931f94SStefano Zampini   /* set values */
8181e7931f94SStefano Zampini   ptr_vals = recv_buffer_vals;
81829d30be91SStefano Zampini   ptr_idxs = recv_buffer_idxs_local;
8183e7931f94SStefano Zampini   for (i = 0; i < n_recvs; i++) {
8184e7931f94SStefano Zampini     if (*ptr_idxs == (PetscInt)MATDENSE_PRIVATE) { /* values insertion provided for dense case only */
81859566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_FALSE));
81869566063dSJacob Faibussowitsch       PetscCall(MatSetValues(local_mat, *(ptr_idxs + 1), ptr_idxs + 2, *(ptr_idxs + 1), ptr_idxs + 2, ptr_vals, ADD_VALUES));
81879566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(local_mat, MAT_FLUSH_ASSEMBLY));
81889566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(local_mat, MAT_FLUSH_ASSEMBLY));
81899566063dSJacob Faibussowitsch       PetscCall(MatSetOption(local_mat, MAT_ROW_ORIENTED, PETSC_TRUE));
819028143c3dSStefano Zampini     } else {
819128143c3dSStefano Zampini       /* TODO */
8192e7931f94SStefano Zampini     }
8193e7931f94SStefano Zampini     ptr_idxs += olengths_idxs[i];
8194e7931f94SStefano Zampini     ptr_vals += olengths_vals[i];
8195e7931f94SStefano Zampini   }
81969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(local_mat, MAT_FINAL_ASSEMBLY));
81979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(local_mat, MAT_FINAL_ASSEMBLY));
81989566063dSJacob Faibussowitsch   PetscCall(MatISRestoreLocalMat(*mat_n, &local_mat));
81999566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat_n, MAT_FINAL_ASSEMBLY));
82009566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat_n, MAT_FINAL_ASSEMBLY));
82019566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vals));
8202e7931f94SStefano Zampini 
8203dfd14d43SStefano Zampini #if 0
820428143c3dSStefano Zampini   if (!restrict_comm) { /* check */
8205e7931f94SStefano Zampini     Vec       lvec,rvec;
8206e7931f94SStefano Zampini     PetscReal infty_error;
8207e7931f94SStefano Zampini 
82089566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&rvec,&lvec));
82099566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(rvec,NULL));
82109566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,rvec,lvec));
82119566063dSJacob Faibussowitsch     PetscCall(VecScale(lvec,-1.0));
82129566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(*mat_n,rvec,lvec,lvec));
82139566063dSJacob Faibussowitsch     PetscCall(VecNorm(lvec,NORM_INFINITY,&infty_error));
82149566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"Infinity error subassembling %1.6e\n",infty_error));
82159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rvec));
82169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lvec));
8217e7931f94SStefano Zampini   }
821828143c3dSStefano Zampini #endif
8219e7931f94SStefano Zampini 
822028143c3dSStefano Zampini   /* assemble new additional is (if any) */
822128143c3dSStefano Zampini   if (nis) {
822228143c3dSStefano Zampini     PetscInt **temp_idxs, *count_is, j, psum;
822328143c3dSStefano Zampini 
82249566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_idxs_is, MPI_STATUSES_IGNORE));
82259566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nis, &count_is));
822628143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
822728143c3dSStefano Zampini     psum     = 0;
822828143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
822928143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
823028143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
823128143c3dSStefano Zampini         count_is[j] += plen;         /* increment counting of buffer for j-th IS */
823228143c3dSStefano Zampini         psum += plen;
823328143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
823428143c3dSStefano Zampini       }
823528143c3dSStefano Zampini     }
82369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &temp_idxs));
82379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(psum, &temp_idxs[0]));
82388e3a54c0SPierre Jolivet     for (i = 1; i < nis; i++) temp_idxs[i] = PetscSafePointerPlusOffset(temp_idxs[i - 1], count_is[i - 1]);
82399566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(count_is, nis));
824028143c3dSStefano Zampini     ptr_idxs = recv_buffer_idxs_is;
824128143c3dSStefano Zampini     for (i = 0; i < n_recvs; i++) {
824228143c3dSStefano Zampini       for (j = 0; j < nis; j++) {
824328143c3dSStefano Zampini         PetscInt plen = *(ptr_idxs); /* first element is the local size of IS's indices */
82449566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&temp_idxs[j][count_is[j]], ptr_idxs + 1, plen));
824528143c3dSStefano Zampini         count_is[j] += plen;  /* increment starting point of buffer for j-th IS */
824628143c3dSStefano Zampini         ptr_idxs += plen + 1; /* shift pointer to received data */
824728143c3dSStefano Zampini       }
824828143c3dSStefano Zampini     }
824928143c3dSStefano Zampini     for (i = 0; i < nis; i++) {
82509566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[i]));
82519566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&count_is[i], temp_idxs[i]));
82529566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm_n, count_is[i], temp_idxs[i], PETSC_COPY_VALUES, &isarray[i]));
825328143c3dSStefano Zampini     }
82549566063dSJacob Faibussowitsch     PetscCall(PetscFree(count_is));
82559566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs[0]));
82569566063dSJacob Faibussowitsch     PetscCall(PetscFree(temp_idxs));
825728143c3dSStefano Zampini   }
8258e7931f94SStefano Zampini   /* free workspace */
82599566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_is));
82609566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs, MPI_STATUSES_IGNORE));
82619566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_buffer_idxs));
82629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(n_sends, send_req_vals, MPI_STATUSES_IGNORE));
8263e7931f94SStefano Zampini   if (isdense) {
82649566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(mat, &local_mat));
82659566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &send_buffer_vals));
82669566063dSJacob Faibussowitsch     PetscCall(MatISRestoreLocalMat(mat, &local_mat));
8267e7931f94SStefano Zampini   } else {
82689566063dSJacob Faibussowitsch     /* PetscCall(PetscFree(send_buffer_vals)); */
8269e7931f94SStefano Zampini   }
827028143c3dSStefano Zampini   if (nis) {
82719566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_idxs_is, MPI_STATUSES_IGNORE));
82729566063dSJacob Faibussowitsch     PetscCall(PetscFree(send_buffer_idxs_is));
827328143c3dSStefano Zampini   }
82741ae86dd6SStefano Zampini 
82751ae86dd6SStefano Zampini   if (nvecs) {
82769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_recvs, recv_req_vecs, MPI_STATUSES_IGNORE));
82779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Waitall(n_sends, send_req_vecs, MPI_STATUSES_IGNORE));
82789566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
82799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&nnsp_vec[0]));
82809566063dSJacob Faibussowitsch     PetscCall(VecCreate(comm_n, &nnsp_vec[0]));
82819566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(nnsp_vec[0], new_local_rows, PETSC_DECIDE));
82829566063dSJacob Faibussowitsch     PetscCall(VecSetType(nnsp_vec[0], VECSTANDARD));
82831ae86dd6SStefano Zampini     /* set values */
82841ae86dd6SStefano Zampini     ptr_vals = recv_buffer_vecs;
82851ae86dd6SStefano Zampini     ptr_idxs = recv_buffer_idxs_local;
82869566063dSJacob Faibussowitsch     PetscCall(VecGetArray(nnsp_vec[0], &send_buffer_vecs));
82871ae86dd6SStefano Zampini     for (i = 0; i < n_recvs; i++) {
82881ae86dd6SStefano Zampini       PetscInt j;
8289ad540459SPierre Jolivet       for (j = 0; j < *(ptr_idxs + 1); j++) send_buffer_vecs[*(ptr_idxs + 2 + j)] += *(ptr_vals + j);
82901ae86dd6SStefano Zampini       ptr_idxs += olengths_idxs[i];
82911ae86dd6SStefano Zampini       ptr_vals += olengths_idxs[i] - 2;
82921ae86dd6SStefano Zampini     }
82939566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(nnsp_vec[0], &send_buffer_vecs));
82949566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(nnsp_vec[0]));
82959566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(nnsp_vec[0]));
82961ae86dd6SStefano Zampini   }
82971ae86dd6SStefano Zampini 
82989566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_vecs));
82999566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_buffer_idxs_local));
83009566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs));
83019566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vals));
83029566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_vecs));
83039566063dSJacob Faibussowitsch   PetscCall(PetscFree(recv_req_idxs_is));
83049566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs));
83059566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vals));
83069566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_vecs));
83079566063dSJacob Faibussowitsch   PetscCall(PetscFree(send_req_idxs_is));
83089566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_vals));
83099566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths_idxs));
83109566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_vals));
83119566063dSJacob Faibussowitsch   PetscCall(PetscFree(olengths_idxs));
83129566063dSJacob Faibussowitsch   PetscCall(PetscFree(onodes));
831328143c3dSStefano Zampini   if (nis) {
83149566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilengths_idxs_is));
83159566063dSJacob Faibussowitsch     PetscCall(PetscFree(olengths_idxs_is));
83169566063dSJacob Faibussowitsch     PetscCall(PetscFree(onodes_is));
831728143c3dSStefano Zampini   }
83189566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&subcomm));
83196aad120cSJose E. Roman   if (destroy_mat) { /* destroy mat is true only if restrict comm is true and process will not participate */
83209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(mat_n));
832148a46eb9SPierre Jolivet     for (i = 0; i < nis; i++) PetscCall(ISDestroy(&isarray[i]));
83221ae86dd6SStefano Zampini     if (nvecs) { /* need to match VecDestroy nnsp_vec called in the other code path */
83239566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nnsp_vec[0]));
83241ae86dd6SStefano Zampini     }
832553a05cb3SStefano Zampini     *mat_n = NULL;
832628143c3dSStefano Zampini   }
83273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8328e7931f94SStefano Zampini }
8329a57a6d2fSStefano Zampini 
833012edc857SStefano Zampini /* temporary hack into ksp private data structure */
8331af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
833212edc857SStefano Zampini 
83339de2952eSStefano Zampini PetscErrorCode PCBDDCSetUpCoarseSolver(PC pc, Mat coarse_submat)
8334d71ae5a4SJacob Faibussowitsch {
8335c8587f34SStefano Zampini   PC_BDDC               *pcbddc = (PC_BDDC *)pc->data;
8336c8587f34SStefano Zampini   PC_IS                 *pcis   = (PC_IS *)pc->data;
83379de2952eSStefano Zampini   PCBDDCGraph            graph  = pcbddc->mat_graph;
83389de2952eSStefano Zampini   Mat                    coarse_mat, coarse_mat_is;
83391ae86dd6SStefano Zampini   Mat                    coarsedivudotp = NULL;
83401e0482f5SStefano Zampini   Mat                    coarseG, t_coarse_mat_is;
83419881197aSStefano Zampini   MatNullSpace           CoarseNullSpace = NULL;
834220a2ab83SStefano Zampini   ISLocalToGlobalMapping coarse_islg;
83434f819b78SStefano Zampini   IS                     coarse_is, *isarray, corners;
83446e683305SStefano Zampini   PetscInt               i, im_active = -1, active_procs = -1;
834530368db7SStefano Zampini   PetscInt               nis, nisdofs, nisneu, nisvert;
83469de2952eSStefano Zampini   PetscInt               coarse_eqs_per_proc, coarsening_ratio;
8347f9eb5b7dSStefano Zampini   PC                     pc_temp;
8348c8587f34SStefano Zampini   PCType                 coarse_pc_type;
8349c8587f34SStefano Zampini   KSPType                coarse_ksp_type;
8350f9eb5b7dSStefano Zampini   PetscBool              multilevel_requested, multilevel_allowed;
83519de2952eSStefano Zampini   PetscBool              coarse_reuse, multi_element = graph->multi_element;
83521e0482f5SStefano Zampini   PetscInt               ncoarse, nedcfield;
835368457ee5SStefano Zampini   PetscBool              compute_vecs = PETSC_FALSE;
835422bc73bbSStefano Zampini   PetscScalar           *array;
835557de7509SStefano Zampini   MatReuse               coarse_mat_reuse;
835657de7509SStefano Zampini   PetscBool              restr, full_restr, have_void;
8357e569e4e1SStefano Zampini   PetscMPIInt            size;
8358fdc09c96SStefano Zampini 
8359c8587f34SStefano Zampini   PetscFunctionBegin;
83609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8361c8587f34SStefano Zampini   /* Assign global numbering to coarse dofs */
836268457ee5SStefano 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 */
8363fa7f1dd8SStefano Zampini     PetscInt ocoarse_size;
83645a75c04eSSatish Balay     compute_vecs = PETSC_TRUE;
83657de4f681Sstefano_zampini 
83667de4f681Sstefano_zampini     pcbddc->new_primal_space = PETSC_TRUE;
8367fa7f1dd8SStefano Zampini     ocoarse_size             = pcbddc->coarse_size;
83689566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcbddc->global_primal_indices));
83699566063dSJacob Faibussowitsch     PetscCall(PCBDDCComputePrimalNumbering(pc, &pcbddc->coarse_size, &pcbddc->global_primal_indices));
8370f4ddd8eeSStefano Zampini     /* see if we can avoid some work */
8371fa7f1dd8SStefano Zampini     if (pcbddc->coarse_ksp) { /* coarse ksp has already been created */
837251bea450SStefano Zampini       /* if the coarse size is different or we are using adaptive selection, better to not reuse the coarse matrix */
837351bea450SStefano Zampini       if (ocoarse_size != pcbddc->coarse_size || pcbddc->adaptive_selection) {
83749566063dSJacob Faibussowitsch         PetscCall(KSPReset(pcbddc->coarse_ksp));
8375fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_FALSE;
8376fa7f1dd8SStefano Zampini       } else { /* we can safely reuse already computed coarse matrix */
8377fa7f1dd8SStefano Zampini         coarse_reuse = PETSC_TRUE;
8378f4ddd8eeSStefano Zampini       }
8379fa7f1dd8SStefano Zampini     } else { /* there's no coarse ksp, so we need to create the coarse matrix too */
8380fa7f1dd8SStefano Zampini       coarse_reuse = PETSC_FALSE;
8381f4ddd8eeSStefano Zampini     }
838270cf5478SStefano Zampini     /* reset any subassembling information */
838348a46eb9SPierre Jolivet     if (!coarse_reuse || pcbddc->recompute_topography) PetscCall(ISDestroy(&pcbddc->coarse_subassembling));
83846e683305SStefano Zampini   } else { /* primal space is unchanged, so we can reuse coarse matrix */
8385fa7f1dd8SStefano Zampini     coarse_reuse = PETSC_TRUE;
8386f4ddd8eeSStefano Zampini   }
838757de7509SStefano Zampini   if (coarse_reuse && pcbddc->coarse_ksp) {
83889566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(pcbddc->coarse_ksp, &coarse_mat, NULL));
83899566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarse_mat));
839057de7509SStefano Zampini     coarse_mat_reuse = MAT_REUSE_MATRIX;
839118a45a71SStefano Zampini   } else {
839257de7509SStefano Zampini     coarse_mat       = NULL;
839357de7509SStefano Zampini     coarse_mat_reuse = MAT_INITIAL_MATRIX;
83946e683305SStefano Zampini   }
8395e7931f94SStefano Zampini 
8396abbbba34SStefano Zampini   /* creates temporary l2gmap and IS for coarse indexes */
83979566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), pcbddc->local_primal_size, pcbddc->global_primal_indices, PETSC_COPY_VALUES, &coarse_is));
83989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(coarse_is, &coarse_islg));
8399abbbba34SStefano Zampini 
8400abbbba34SStefano Zampini   /* creates temporary MATIS object for coarse matrix */
84019de2952eSStefano Zampini   PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &t_coarse_mat_is));
84029de2952eSStefano Zampini   PetscCall(MatSetType(t_coarse_mat_is, MATIS));
84039de2952eSStefano Zampini   PetscCall(MatSetSizes(t_coarse_mat_is, PETSC_DECIDE, PETSC_DECIDE, pcbddc->coarse_size, pcbddc->coarse_size));
84049de2952eSStefano Zampini   PetscCall(MatISSetAllowRepeated(t_coarse_mat_is, PETSC_TRUE));
84059de2952eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(t_coarse_mat_is, coarse_islg, coarse_islg));
84069de2952eSStefano Zampini   PetscCall(MatISSetLocalMat(t_coarse_mat_is, coarse_submat));
84079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
84089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(t_coarse_mat_is, MAT_FINAL_ASSEMBLY));
84099de2952eSStefano Zampini   PetscCall(MatViewFromOptions(t_coarse_mat_is, (PetscObject)pc, "-pc_bddc_coarse_mat_is_view"));
8410abbbba34SStefano Zampini 
841157de7509SStefano Zampini   /* count "active" (i.e. with positive local size) and "void" processes */
8412f4f49eeaSPierre Jolivet   im_active = !!pcis->n;
84131c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&im_active, &active_procs, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
841457de7509SStefano Zampini 
841514f0bfb9SStefano Zampini   /* determine number of processes partecipating to coarse solver and compute subassembling pattern */
841628d58a37SPierre Jolivet   /* restr : whether we want to exclude senders (which are not receivers) from the subassembling pattern */
841757de7509SStefano Zampini   /* full_restr : just use the receivers from the subassembling pattern */
84189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
841957de7509SStefano Zampini   coarse_mat_is        = NULL;
842057de7509SStefano Zampini   multilevel_allowed   = PETSC_FALSE;
842157de7509SStefano Zampini   multilevel_requested = PETSC_FALSE;
8422e569e4e1SStefano Zampini   coarse_eqs_per_proc  = PetscMin(PetscMax(pcbddc->coarse_size, 1), pcbddc->coarse_eqs_per_proc);
84239de2952eSStefano Zampini   if (coarse_eqs_per_proc < 0 || size == 1) coarse_eqs_per_proc = PetscMax(pcbddc->coarse_size, 1);
842457de7509SStefano Zampini   if (pcbddc->current_level < pcbddc->max_levels) multilevel_requested = PETSC_TRUE;
8425e569e4e1SStefano Zampini   if (pcbddc->coarse_size <= pcbddc->coarse_eqs_limit) multilevel_requested = PETSC_FALSE;
84269de2952eSStefano Zampini   coarsening_ratio = multi_element ? 1 : pcbddc->coarsening_ratio;
842757de7509SStefano Zampini   if (multilevel_requested) {
84289de2952eSStefano Zampini     ncoarse    = active_procs / coarsening_ratio;
842957de7509SStefano Zampini     restr      = PETSC_FALSE;
843057de7509SStefano Zampini     full_restr = PETSC_FALSE;
843157de7509SStefano Zampini   } else {
8432e569e4e1SStefano Zampini     ncoarse    = pcbddc->coarse_size / coarse_eqs_per_proc + !!(pcbddc->coarse_size % coarse_eqs_per_proc);
843357de7509SStefano Zampini     restr      = PETSC_TRUE;
843457de7509SStefano Zampini     full_restr = PETSC_TRUE;
843557de7509SStefano Zampini   }
8436e569e4e1SStefano Zampini   if (!pcbddc->coarse_size || size == 1) multilevel_allowed = multilevel_requested = restr = full_restr = PETSC_FALSE;
843757de7509SStefano Zampini   ncoarse = PetscMax(1, ncoarse);
843857de7509SStefano Zampini   if (!pcbddc->coarse_subassembling) {
84399de2952eSStefano Zampini     if (coarsening_ratio > 1) {
8440bb360cb4SStefano Zampini       if (multilevel_requested) {
84419566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(pc->pmat, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8442bb360cb4SStefano Zampini       } else {
84439566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISGetSubassemblingPattern(t_coarse_mat_is, &ncoarse, pcbddc->coarse_adj_red, &pcbddc->coarse_subassembling, &have_void));
8444bb360cb4SStefano Zampini       }
8445a198735bSStefano Zampini     } else {
84467de4f681Sstefano_zampini       PetscMPIInt rank;
844728d58a37SPierre Jolivet 
84489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
8449e569e4e1SStefano Zampini       have_void = (active_procs == (PetscInt)size) ? PETSC_FALSE : PETSC_TRUE;
84509566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), 1, rank, 1, &pcbddc->coarse_subassembling));
8451a198735bSStefano Zampini     }
845257de7509SStefano Zampini   } else { /* if a subassembling pattern exists, then we can reuse the coarse ksp and compute the number of process involved */
845357de7509SStefano Zampini     PetscInt psum;
845457de7509SStefano Zampini     if (pcbddc->coarse_ksp) psum = 1;
845557de7509SStefano Zampini     else psum = 0;
84561c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&psum, &ncoarse, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
8457075e25bcSStefano Zampini     have_void = ncoarse < size ? PETSC_TRUE : PETSC_FALSE;
845857de7509SStefano Zampini   }
845957de7509SStefano Zampini   /* determine if we can go multilevel */
846057de7509SStefano Zampini   if (multilevel_requested) {
846157de7509SStefano Zampini     if (ncoarse > 1) multilevel_allowed = PETSC_TRUE; /* found enough processes */
846257de7509SStefano Zampini     else restr = full_restr = PETSC_TRUE;             /* 1 subdomain, use a direct solver */
846357de7509SStefano Zampini   }
846457de7509SStefano Zampini   if (multilevel_allowed && have_void) restr = PETSC_TRUE;
846557de7509SStefano Zampini 
8466e4d548c7SStefano Zampini   /* dump subassembling pattern */
846748a46eb9SPierre Jolivet   if (pcbddc->dbg_flag && multilevel_allowed) PetscCall(ISView(pcbddc->coarse_subassembling, pcbddc->dbg_viewer));
84686e683305SStefano Zampini   /* compute dofs splitting and neumann boundaries for coarse dofs */
84691e0482f5SStefano Zampini   nedcfield = -1;
84704f819b78SStefano Zampini   corners   = NULL;
84718966356dSPierre Jolivet   if (multilevel_allowed && !coarse_reuse && (pcbddc->n_ISForDofsLocal || pcbddc->NeumannBoundariesLocal || pcbddc->nedclocal || pcbddc->corner_selected)) { /* protects from unneeded computations */
84726e683305SStefano Zampini     PetscInt              *tidxs, *tidxs2, nout, tsize, i;
84736e683305SStefano Zampini     const PetscInt        *idxs;
84746e683305SStefano Zampini     ISLocalToGlobalMapping tmap;
84756e683305SStefano Zampini 
84766e683305SStefano Zampini     /* create map between primal indices (in local representative ordering) and local primal numbering */
84779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1, pcbddc->local_primal_size, pcbddc->primal_indices_local_idxs, PETSC_COPY_VALUES, &tmap));
84786e683305SStefano Zampini     /* allocate space for temporary storage */
84799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs));
84809566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pcbddc->local_primal_size, &tidxs2));
84816e683305SStefano Zampini     /* allocate for IS array */
84826e683305SStefano Zampini     nisdofs = pcbddc->n_ISForDofsLocal;
84831e0482f5SStefano Zampini     if (pcbddc->nedclocal) {
84841e0482f5SStefano Zampini       if (pcbddc->nedfield > -1) {
84851e0482f5SStefano Zampini         nedcfield = pcbddc->nedfield;
84861e0482f5SStefano Zampini       } else {
84871e0482f5SStefano Zampini         nedcfield = 0;
848863a3b9bcSJacob Faibussowitsch         PetscCheck(!nisdofs, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "This should not happen (%" PetscInt_FMT ")", nisdofs);
84891e0482f5SStefano Zampini         nisdofs = 1;
84901e0482f5SStefano Zampini       }
84911e0482f5SStefano Zampini     }
84926e683305SStefano Zampini     nisneu  = !!pcbddc->NeumannBoundariesLocal;
849327b6a85dSStefano Zampini     nisvert = 0; /* nisvert is not used */
849430368db7SStefano Zampini     nis     = nisdofs + nisneu + nisvert;
84959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nis, &isarray));
84966e683305SStefano Zampini     /* dofs splitting */
84976e683305SStefano Zampini     for (i = 0; i < nisdofs; i++) {
84989566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->ISForDofsLocal[i],0)); */
84991e0482f5SStefano Zampini       if (nedcfield != i) {
85009566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[i], &tsize));
85019566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[i], &idxs));
85029566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
85039566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[i], &idxs));
85041e0482f5SStefano Zampini       } else {
85059566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(pcbddc->nedclocal, &tsize));
85069566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(pcbddc->nedclocal, &idxs));
85079566063dSJacob Faibussowitsch         PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
850863a3b9bcSJacob Faibussowitsch         PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping coarse nedelec field! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
85099566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(pcbddc->nedclocal, &idxs));
85101e0482f5SStefano Zampini       }
85119566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85129566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[i]));
85139566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[i],0)); */
85146e683305SStefano Zampini     }
85156e683305SStefano Zampini     /* neumann boundaries */
85166e683305SStefano Zampini     if (pcbddc->NeumannBoundariesLocal) {
85179566063dSJacob Faibussowitsch       /* PetscCall(ISView(pcbddc->NeumannBoundariesLocal,0)); */
85189566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pcbddc->NeumannBoundariesLocal, &tsize));
85199566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pcbddc->NeumannBoundariesLocal, &idxs));
85209566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
85219566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pcbddc->NeumannBoundariesLocal, &idxs));
85229566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85239566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &isarray[nisdofs]));
85249566063dSJacob Faibussowitsch       /* PetscCall(ISView(isarray[nisdofs],0)); */
85256e683305SStefano Zampini     }
85264f819b78SStefano Zampini     /* coordinates */
85274f819b78SStefano Zampini     if (pcbddc->corner_selected) {
85289566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
85299566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(corners, &tsize));
85309566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(corners, &idxs));
85319566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(tmap, IS_GTOLM_DROP, tsize, idxs, &nout, tidxs));
853263a3b9bcSJacob Faibussowitsch       PetscCheck(tsize == nout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed when mapping corners! %" PetscInt_FMT " != %" PetscInt_FMT, tsize, nout);
85339566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(corners, &idxs));
85349566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &corners));
85359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(coarse_islg, nout, tidxs, tidxs2));
85369566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nout, tidxs2, PETSC_COPY_VALUES, &corners));
85374f819b78SStefano Zampini     }
85389566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs));
85399566063dSJacob Faibussowitsch     PetscCall(PetscFree(tidxs2));
85409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&tmap));
85416e683305SStefano Zampini   } else {
85426e683305SStefano Zampini     nis     = 0;
85436e683305SStefano Zampini     nisdofs = 0;
85446e683305SStefano Zampini     nisneu  = 0;
854530368db7SStefano Zampini     nisvert = 0;
85466e683305SStefano Zampini     isarray = NULL;
85476e683305SStefano Zampini   }
85486e683305SStefano Zampini   /* destroy no longer needed map */
85499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&coarse_islg));
85506e683305SStefano Zampini 
855157de7509SStefano Zampini   /* subassemble */
855257de7509SStefano Zampini   if (multilevel_allowed) {
85531ae86dd6SStefano Zampini     Vec       vp[1];
85541ae86dd6SStefano Zampini     PetscInt  nvecs = 0;
85559de2952eSStefano Zampini     PetscBool reuse;
85561ae86dd6SStefano Zampini 
85571ae86dd6SStefano Zampini     vp[0] = NULL;
85589de2952eSStefano Zampini     /* XXX HDIV also */
85591ae86dd6SStefano Zampini     if (pcbddc->benign_have_null) { /* propagate no-net-flux quadrature to coarser level */
85609566063dSJacob Faibussowitsch       PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &vp[0]));
85619566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(vp[0], pcbddc->local_primal_size, PETSC_DECIDE));
85629566063dSJacob Faibussowitsch       PetscCall(VecSetType(vp[0], VECSTANDARD));
85631ae86dd6SStefano Zampini       nvecs = 1;
85641ae86dd6SStefano Zampini 
85651ae86dd6SStefano Zampini       if (pcbddc->divudotp) {
8566a198735bSStefano Zampini         Mat      B, loc_divudotp;
85671ae86dd6SStefano Zampini         Vec      v, p;
85681ae86dd6SStefano Zampini         IS       dummy;
85691ae86dd6SStefano Zampini         PetscInt np;
85701ae86dd6SStefano Zampini 
85719566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(pcbddc->divudotp, &loc_divudotp));
85729566063dSJacob Faibussowitsch         PetscCall(MatGetSize(loc_divudotp, &np, NULL));
85739566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, np, 0, 1, &dummy));
85749566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(loc_divudotp, dummy, pcis->is_B_local, MAT_INITIAL_MATRIX, &B));
85759566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(B, &v, &p));
85769566063dSJacob Faibussowitsch         PetscCall(VecSet(p, 1.));
85779566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(B, p, v));
85789566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&p));
85799566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&B));
85809566063dSJacob Faibussowitsch         PetscCall(VecGetArray(vp[0], &array));
85819566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(pcbddc->vec1_P, array));
85829566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pcbddc->coarse_phi_B, v, pcbddc->vec1_P));
85839566063dSJacob Faibussowitsch         PetscCall(VecResetArray(pcbddc->vec1_P));
85849566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(vp[0], &array));
85859566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&dummy));
85869566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&v));
858774e2c79eSStefano Zampini       }
85881ae86dd6SStefano Zampini     }
85899de2952eSStefano Zampini     if (coarse_mat) reuse = PETSC_TRUE;
85909de2952eSStefano Zampini     else reuse = PETSC_FALSE;
85919de2952eSStefano Zampini     if (multi_element) {
85929de2952eSStefano Zampini       /* XXX divudotp */
85939de2952eSStefano Zampini       PetscCall(MatISSetAllowRepeated(t_coarse_mat_is, PETSC_FALSE));
85949de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
85959de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
85969de2952eSStefano Zampini     } else {
85979de2952eSStefano Zampini       PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &reuse, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
85989de2952eSStefano Zampini       if (reuse) {
85999566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_TRUE, &coarse_mat, nis, isarray, nvecs, vp));
860074e2c79eSStefano Zampini       } else {
86019566063dSJacob Faibussowitsch         PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, nis, isarray, nvecs, vp));
86021ae86dd6SStefano Zampini       }
86031ae86dd6SStefano Zampini       if (vp[0]) { /* vp[0] could have been placed on a different set of processes */
86041683a169SBarry Smith         PetscScalar       *arraym;
86051683a169SBarry Smith         const PetscScalar *arrayv;
86061ae86dd6SStefano Zampini         PetscInt           nl;
86079566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(vp[0], &nl));
86089566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, 1, nl, NULL, &coarsedivudotp));
86099566063dSJacob Faibussowitsch         PetscCall(MatDenseGetArray(coarsedivudotp, &arraym));
86109566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(vp[0], &arrayv));
86119566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(arraym, arrayv, nl));
86129566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(vp[0], &arrayv));
86139566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreArray(coarsedivudotp, &arraym));
86149566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&vp[0]));
8615a198735bSStefano Zampini       } else {
86169566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 0, 0, 1, NULL, &coarsedivudotp));
86171ae86dd6SStefano Zampini       }
86189de2952eSStefano Zampini     }
86191ae86dd6SStefano Zampini   } else {
86209de2952eSStefano Zampini     if (ncoarse != size) PetscCall(PCBDDCMatISSubassemble(t_coarse_mat_is, pcbddc->coarse_subassembling, 0, restr, full_restr, PETSC_FALSE, &coarse_mat_is, 0, NULL, 0, NULL));
86219de2952eSStefano Zampini     else {
86229de2952eSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)t_coarse_mat_is));
86239de2952eSStefano Zampini       coarse_mat_is = t_coarse_mat_is;
86249de2952eSStefano Zampini     }
86256e683305SStefano Zampini   }
862657de7509SStefano Zampini   if (coarse_mat_is || coarse_mat) {
862757de7509SStefano Zampini     if (!multilevel_allowed) {
86289566063dSJacob Faibussowitsch       PetscCall(MatConvert(coarse_mat_is, MATAIJ, coarse_mat_reuse, &coarse_mat));
86296e683305SStefano Zampini     } else {
863057de7509SStefano Zampini       /* if this matrix is present, it means we are not reusing the coarse matrix */
863157de7509SStefano Zampini       if (coarse_mat_is) {
863228b400f6SJacob Faibussowitsch         PetscCheck(!coarse_mat, PetscObjectComm((PetscObject)coarse_mat_is), PETSC_ERR_PLIB, "This should not happen");
86339566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)coarse_mat_is));
863457de7509SStefano Zampini         coarse_mat = coarse_mat_is;
863557de7509SStefano Zampini       }
8636779c1cceSStefano Zampini     }
8637779c1cceSStefano Zampini   }
86389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&t_coarse_mat_is));
86399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat_is));
86406e683305SStefano Zampini 
86416e683305SStefano Zampini   /* create local to global scatters for coarse problem */
864268457ee5SStefano Zampini   if (compute_vecs) {
86436e683305SStefano Zampini     PetscInt lrows;
86449566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&pcbddc->coarse_vec));
864557de7509SStefano Zampini     if (coarse_mat) {
86469566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(coarse_mat, &lrows, NULL));
86476e683305SStefano Zampini     } else {
86486e683305SStefano Zampini       lrows = 0;
86496e683305SStefano Zampini     }
86509566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pc), &pcbddc->coarse_vec));
86519566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(pcbddc->coarse_vec, lrows, PETSC_DECIDE));
86529566063dSJacob Faibussowitsch     PetscCall(VecSetType(pcbddc->coarse_vec, coarse_mat ? coarse_mat->defaultvectype : VECSTANDARD));
86539566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&pcbddc->coarse_loc_to_glob));
86549566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(pcbddc->vec1_P, NULL, pcbddc->coarse_vec, coarse_is, &pcbddc->coarse_loc_to_glob));
86556e683305SStefano Zampini   }
86569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&coarse_is));
8657c8587f34SStefano Zampini 
8658f9eb5b7dSStefano Zampini   /* set defaults for coarse KSP and PC */
8659f9eb5b7dSStefano Zampini   if (multilevel_allowed) {
8660f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPRICHARDSON;
8661f9eb5b7dSStefano Zampini     coarse_pc_type  = PCBDDC;
8662f9eb5b7dSStefano Zampini   } else {
8663f9eb5b7dSStefano Zampini     coarse_ksp_type = KSPPREONLY;
8664f9eb5b7dSStefano Zampini     coarse_pc_type  = PCREDUNDANT;
8665c8587f34SStefano Zampini   }
8666c8587f34SStefano Zampini 
86676e683305SStefano Zampini   /* print some info if requested */
86686e683305SStefano Zampini   if (pcbddc->dbg_flag) {
86696e683305SStefano Zampini     if (!multilevel_allowed) {
86709566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
86716e683305SStefano Zampini       if (multilevel_requested) {
86729de2952eSStefano Zampini         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Not enough active processes on level %" PetscInt_FMT " (active processes %" PetscInt_FMT ", coarsening ratio %" PetscInt_FMT ")\n", pcbddc->current_level, active_procs, coarsening_ratio));
86736e683305SStefano Zampini       } else if (pcbddc->max_levels) {
867463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Maximum number of requested levels reached (%" PetscInt_FMT ")\n", pcbddc->max_levels));
86756e683305SStefano Zampini       }
86769566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
86776e683305SStefano Zampini     }
86786e683305SStefano Zampini   }
86796e683305SStefano Zampini 
86801e0482f5SStefano Zampini   /* communicate coarse discrete gradient */
86811e0482f5SStefano Zampini   coarseG = NULL;
86821e0482f5SStefano Zampini   if (pcbddc->nedcG && multilevel_allowed) {
86831e0482f5SStefano Zampini     MPI_Comm ccomm;
86841e0482f5SStefano Zampini     if (coarse_mat) {
86851e0482f5SStefano Zampini       ccomm = PetscObjectComm((PetscObject)coarse_mat);
86861e0482f5SStefano Zampini     } else {
86871e0482f5SStefano Zampini       ccomm = MPI_COMM_NULL;
86881e0482f5SStefano Zampini     }
86899566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJRestrict(pcbddc->nedcG, ccomm, &coarseG));
86901e0482f5SStefano Zampini   }
86911e0482f5SStefano Zampini 
8692f9eb5b7dSStefano Zampini   /* create the coarse KSP object only once with defaults */
869357de7509SStefano Zampini   if (coarse_mat) {
869428d58a37SPierre Jolivet     PetscBool   isredundant, isbddc, force, valid;
86956a1308c2SStefano Zampini     PetscViewer dbg_viewer = NULL;
8696b94d7dedSBarry Smith     PetscBool   isset, issym, isher, isspd;
86977274672aSStefano Zampini 
86986e683305SStefano Zampini     if (pcbddc->dbg_flag) {
869957de7509SStefano Zampini       dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)coarse_mat));
87009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * pcbddc->current_level));
87016e683305SStefano Zampini     }
8702f9eb5b7dSStefano Zampini     if (!pcbddc->coarse_ksp) {
8703312be037SStefano Zampini       char   prefix[256], str_level[16];
8704e604994aSStefano Zampini       size_t len;
87051e0482f5SStefano Zampini 
87069566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)coarse_mat), &pcbddc->coarse_ksp));
87073821be0aSBarry Smith       PetscCall(KSPSetNestLevel(pcbddc->coarse_ksp, pc->kspnestlevel));
87089566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, pc->erroriffailure));
87099566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcbddc->coarse_ksp, (PetscObject)pc, 1));
87109566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(pcbddc->coarse_ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1));
87119566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
87129566063dSJacob Faibussowitsch       PetscCall(KSPSetType(pcbddc->coarse_ksp, coarse_ksp_type));
87139566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(pcbddc->coarse_ksp, KSP_NORM_NONE));
87149566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
87151e0482f5SStefano Zampini       /* TODO is this logic correct? should check for coarse_mat type */
87169566063dSJacob Faibussowitsch       PetscCall(PCSetType(pc_temp, coarse_pc_type));
8717e604994aSStefano Zampini       /* prefix */
8718c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(prefix, "", sizeof(prefix)));
8719c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(str_level, "", sizeof(str_level)));
8720e604994aSStefano Zampini       if (!pcbddc->current_level) {
87219566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, sizeof(prefix)));
87229566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, "pc_bddc_coarse_", sizeof(prefix)));
8723c8587f34SStefano Zampini       } else {
87249566063dSJacob Faibussowitsch         PetscCall(PetscStrlen(((PetscObject)pc)->prefix, &len));
8725312be037SStefano Zampini         if (pcbddc->current_level > 1) len -= 3;  /* remove "lX_" with X level number */
8726312be037SStefano Zampini         if (pcbddc->current_level > 10) len -= 1; /* remove another char from level number */
8727a126751eSBarry Smith         /* Nonstandard use of PetscStrncpy() to copy only a portion of the string */
87289566063dSJacob Faibussowitsch         PetscCall(PetscStrncpy(prefix, ((PetscObject)pc)->prefix, len + 1));
8729f4f49eeaSPierre Jolivet         PetscCall(PetscSNPrintf(str_level, sizeof(str_level), "l%d_", (int)pcbddc->current_level));
87309566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(prefix, str_level, sizeof(prefix)));
8731e604994aSStefano Zampini       }
87329566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(pcbddc->coarse_ksp, prefix));
87333e3c6dadSStefano Zampini       /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
87349566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
87359566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
87369566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
8737f9eb5b7dSStefano Zampini       /* allow user customization */
87389566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(pcbddc->coarse_ksp));
8739e569e4e1SStefano Zampini       /* get some info after set from options */
87409566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
874128d58a37SPierre Jolivet       /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
874228d58a37SPierre Jolivet       force = PETSC_FALSE;
87439566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
87449566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
87459566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
874628d58a37SPierre Jolivet       if (multilevel_allowed && !force && !valid) {
8747e569e4e1SStefano Zampini         isbddc = PETSC_TRUE;
87489566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc_temp, PCBDDC));
87499566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevel(pc_temp, pcbddc->current_level + 1));
87509566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetCoarseningRatio(pc_temp, pcbddc->coarsening_ratio));
87519566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetLevels(pc_temp, pcbddc->max_levels));
87524f819b78SStefano Zampini         if (pc_temp->ops->setfromoptions) { /* need to setfromoptions again, skipping the pc_type */
8753d0609cedSBarry Smith           PetscObjectOptionsBegin((PetscObject)pc_temp);
8754dbbe0bcdSBarry Smith           PetscCall((*pc_temp->ops->setfromoptions)(pc_temp, PetscOptionsObject));
8755dbbe0bcdSBarry Smith           PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pc_temp, PetscOptionsObject));
8756d0609cedSBarry Smith           PetscOptionsEnd();
87574f819b78SStefano Zampini           pc_temp->setfromoptionscalled++;
87584f819b78SStefano Zampini         }
8759e569e4e1SStefano Zampini       }
87603e3c6dadSStefano Zampini     }
87613e3c6dadSStefano Zampini     /* propagate BDDC info to the next level (these are dummy calls if pc_temp is not of type PCBDDC) */
87629566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(pcbddc->coarse_ksp, &pc_temp));
87633e3c6dadSStefano Zampini     if (nisdofs) {
87649566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetDofsSplitting(pc_temp, nisdofs, isarray));
876548a46eb9SPierre Jolivet       for (i = 0; i < nisdofs; i++) PetscCall(ISDestroy(&isarray[i]));
87663e3c6dadSStefano Zampini     }
87673e3c6dadSStefano Zampini     if (nisneu) {
87689566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetNeumannBoundaries(pc_temp, isarray[nisdofs]));
87699566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nisdofs]));
8770312be037SStefano Zampini     }
877130368db7SStefano Zampini     if (nisvert) {
87729566063dSJacob Faibussowitsch       PetscCall(PCBDDCSetPrimalVerticesIS(pc_temp, isarray[nis - 1]));
87739566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isarray[nis - 1]));
877430368db7SStefano Zampini     }
87751baa6e33SBarry Smith     if (coarseG) PetscCall(PCBDDCSetDiscreteGradient(pc_temp, coarseG, 1, nedcfield, PETSC_FALSE, PETSC_TRUE));
8776f9eb5b7dSStefano Zampini 
8777f9eb5b7dSStefano Zampini     /* get some info after set from options */
87789566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
87794f819b78SStefano Zampini 
8780b76f3995Sstefano_zampini     /* multilevel can only be requested via -pc_bddc_levels or PCBDDCSetLevels */
878148a46eb9SPierre Jolivet     if (isbddc && !multilevel_allowed) PetscCall(PCSetType(pc_temp, coarse_pc_type));
878228d58a37SPierre Jolivet     /* multilevel cannot be done with coarse PC different from BDDC, NN, HPDDM, unless forced to */
878328d58a37SPierre Jolivet     force = PETSC_FALSE;
87849566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)pc_temp)->prefix, "-pc_type_forced", &force, NULL));
87859566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompareAny((PetscObject)pc_temp, &valid, PCBDDC, PCNN, PCHPDDM, ""));
878648a46eb9SPierre Jolivet     if (multilevel_requested && multilevel_allowed && !valid && !force) PetscCall(PCSetType(pc_temp, PCBDDC));
87879566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCREDUNDANT, &isredundant));
87884f3a063dSStefano Zampini     if (isredundant) {
87894f3a063dSStefano Zampini       KSP inner_ksp;
87904f3a063dSStefano Zampini       PC  inner_pc;
87919326c5c6Sstefano_zampini 
87929566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc_temp, &inner_ksp));
87939566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(inner_ksp, &inner_pc));
87944f3a063dSStefano Zampini     }
8795f9eb5b7dSStefano Zampini 
879657de7509SStefano Zampini     /* parameters which miss an API */
87979566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc_temp, PCBDDC, &isbddc));
879857de7509SStefano Zampini     if (isbddc) {
8799720d30f9SStefano Zampini       PC_BDDC *pcbddc_coarse = (PC_BDDC *)pc_temp->data;
88007274672aSStefano Zampini 
8801720d30f9SStefano Zampini       pcbddc_coarse->detect_disconnected = PETSC_TRUE;
880257de7509SStefano Zampini       pcbddc_coarse->coarse_eqs_per_proc = pcbddc->coarse_eqs_per_proc;
8803e569e4e1SStefano Zampini       pcbddc_coarse->coarse_eqs_limit    = pcbddc->coarse_eqs_limit;
880427b6a85dSStefano Zampini       pcbddc_coarse->benign_saddle_point = pcbddc->benign_have_null;
880527b6a85dSStefano Zampini       if (pcbddc_coarse->benign_saddle_point) {
8806a198735bSStefano Zampini         Mat                    coarsedivudotp_is;
8807a198735bSStefano Zampini         ISLocalToGlobalMapping l2gmap, rl2g, cl2g;
8808a198735bSStefano Zampini         IS                     row, col;
8809a198735bSStefano Zampini         const PetscInt        *gidxs;
8810a198735bSStefano Zampini         PetscInt               n, st, M, N;
8811a198735bSStefano Zampini 
88129566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarsedivudotp, &n, NULL));
88139566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Scan(&n, &st, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)coarse_mat)));
8814a198735bSStefano Zampini         st = st - n;
88159566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)coarse_mat), 1, st, 1, &row));
88169566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalToGlobalMapping(coarse_mat, &l2gmap, NULL));
88179566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
88189566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetIndices(l2gmap, &gidxs));
88199566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)coarse_mat), n, gidxs, PETSC_COPY_VALUES, &col));
88209566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreIndices(l2gmap, &gidxs));
88219566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(row, &rl2g));
88229566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingCreateIS(col, &cl2g));
88239566063dSJacob Faibussowitsch         PetscCall(ISGetSize(row, &M));
88249566063dSJacob Faibussowitsch         PetscCall(MatGetSize(coarse_mat, &N, NULL));
88259566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&row));
88269566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&col));
88279566063dSJacob Faibussowitsch         PetscCall(MatCreate(PetscObjectComm((PetscObject)coarse_mat), &coarsedivudotp_is));
88289566063dSJacob Faibussowitsch         PetscCall(MatSetType(coarsedivudotp_is, MATIS));
88299566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(coarsedivudotp_is, PETSC_DECIDE, PETSC_DECIDE, M, N));
88309566063dSJacob Faibussowitsch         PetscCall(MatSetLocalToGlobalMapping(coarsedivudotp_is, rl2g, cl2g));
88319566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
88329566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
88339566063dSJacob Faibussowitsch         PetscCall(MatISSetLocalMat(coarsedivudotp_is, coarsedivudotp));
88349566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp));
88359566063dSJacob Faibussowitsch         PetscCall(PCBDDCSetDivergenceMat(pc_temp, coarsedivudotp_is, PETSC_FALSE, NULL));
88369566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&coarsedivudotp_is));
8837720d30f9SStefano Zampini         pcbddc_coarse->adaptive_userdefined = PETSC_TRUE;
8838bd2a564bSStefano Zampini         if (pcbddc->adaptive_threshold[0] == 0.0) pcbddc_coarse->deluxe_zerorows = PETSC_TRUE;
8839720d30f9SStefano Zampini       }
8840d4d8cf7bSStefano Zampini     }
88419881197aSStefano Zampini 
88423301b35fSStefano Zampini     /* propagate symmetry info of coarse matrix */
88439566063dSJacob Faibussowitsch     PetscCall(MatSetOption(coarse_mat, MAT_STRUCTURALLY_SYMMETRIC, PETSC_TRUE));
8844b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
8845b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SYMMETRIC, issym));
8846b94d7dedSBarry Smith     PetscCall(MatIsHermitianKnown(pc->pmat, &isset, &isher));
8847b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_HERMITIAN, isher));
8848b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
8849b94d7dedSBarry Smith     if (isset) PetscCall(MatSetOption(coarse_mat, MAT_SPD, isspd));
8850b94d7dedSBarry Smith 
885148a46eb9SPierre Jolivet     if (pcbddc->benign_saddle_point && !pcbddc->benign_have_null) PetscCall(MatSetOption(coarse_mat, MAT_SPD, PETSC_TRUE));
88526e683305SStefano Zampini     /* set operators */
88539566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(coarse_mat, (PetscObject)pc, "-pc_bddc_coarse_mat_view"));
88549566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(coarse_mat, ((PetscObject)pcbddc->coarse_ksp)->prefix));
88559566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(pcbddc->coarse_ksp, coarse_mat, coarse_mat));
88561baa6e33SBarry Smith     if (pcbddc->dbg_flag) PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * pcbddc->current_level));
88576e683305SStefano Zampini   }
88589566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarseG));
88599566063dSJacob Faibussowitsch   PetscCall(PetscFree(isarray));
8860b1ecc7b1SStefano Zampini #if 0
8861b9b85e73SStefano Zampini   {
8862b9b85e73SStefano Zampini     PetscViewer viewer;
8863b9b85e73SStefano Zampini     char filename[256];
8864a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(filename, PETSC_STATIC_ARRAY_LENGTH(filename), "coarse_mat_level%d.m",pcbddc->current_level));
88659566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)coarse_mat),filename,&viewer));
88669566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
88679566063dSJacob Faibussowitsch     PetscCall(MatView(coarse_mat,viewer));
88689566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
88699566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
8870b9b85e73SStefano Zampini   }
8871b9b85e73SStefano Zampini #endif
8872f9eb5b7dSStefano Zampini 
88734f819b78SStefano Zampini   if (corners) {
88744f819b78SStefano Zampini     Vec             gv;
88754f819b78SStefano Zampini     IS              is;
88764f819b78SStefano Zampini     const PetscInt *idxs;
88774f819b78SStefano Zampini     PetscInt        i, d, N, n, cdim = pcbddc->mat_graph->cdim;
88784f819b78SStefano Zampini     PetscScalar    *coords;
88794f819b78SStefano Zampini 
888028b400f6SJacob Faibussowitsch     PetscCheck(pcbddc->mat_graph->cloc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local coordinates");
88819566063dSJacob Faibussowitsch     PetscCall(VecGetSize(pcbddc->coarse_vec, &N));
88829566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(pcbddc->coarse_vec, &n));
88839566063dSJacob Faibussowitsch     PetscCall(VecCreate(PetscObjectComm((PetscObject)pcbddc->coarse_vec), &gv));
88849566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(gv, cdim));
88859566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(gv, n * cdim, N * cdim));
88869566063dSJacob Faibussowitsch     PetscCall(VecSetType(gv, VECSTANDARD));
88879566063dSJacob Faibussowitsch     PetscCall(VecSetFromOptions(gv));
88889566063dSJacob Faibussowitsch     PetscCall(VecSet(gv, PETSC_MAX_REAL)); /* we only propagate coordinates from vertices constraints */
88894f819b78SStefano Zampini 
88909566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
88919566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &n));
88929566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, &idxs));
88939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * cdim, &coords));
88944f819b78SStefano Zampini     for (i = 0; i < n; i++) {
8895ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) coords[cdim * i + d] = pcbddc->mat_graph->coords[cdim * idxs[i] + d];
88964f819b78SStefano Zampini     }
88979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, &idxs));
88989566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &is));
88994f819b78SStefano Zampini 
89009566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(corners, &n));
89019566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(corners, &idxs));
89029566063dSJacob Faibussowitsch     PetscCall(VecSetValuesBlocked(gv, n, idxs, coords, INSERT_VALUES));
89039566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(corners, &idxs));
89049566063dSJacob Faibussowitsch     PetscCall(PetscFree(coords));
89059566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(gv));
89069566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(gv));
89079566063dSJacob Faibussowitsch     PetscCall(VecGetArray(gv, &coords));
89084f819b78SStefano Zampini     if (pcbddc->coarse_ksp) {
89094f819b78SStefano Zampini       PC        coarse_pc;
89104f819b78SStefano Zampini       PetscBool isbddc;
89114f819b78SStefano Zampini 
89129566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &coarse_pc));
89139566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)coarse_pc, PCBDDC, &isbddc));
89144f819b78SStefano Zampini       if (isbddc) { /* coarse coordinates have PETSC_MAX_REAL, specific for BDDC */
89154f819b78SStefano Zampini         PetscReal *realcoords;
89164f819b78SStefano Zampini 
89179566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(gv, &n));
89184f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
89199566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(n, &realcoords));
89204f819b78SStefano Zampini         for (i = 0; i < n; i++) realcoords[i] = PetscRealPart(coords[i]);
89214f819b78SStefano Zampini #else
89224f819b78SStefano Zampini         realcoords = coords;
89234f819b78SStefano Zampini #endif
89249566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(coarse_pc, cdim, n / cdim, realcoords));
89254f819b78SStefano Zampini #if defined(PETSC_USE_COMPLEX)
89269566063dSJacob Faibussowitsch         PetscCall(PetscFree(realcoords));
89274f819b78SStefano Zampini #endif
89284f819b78SStefano Zampini       }
89294f819b78SStefano Zampini     }
89309566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(gv, &coords));
89319566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gv));
89324f819b78SStefano Zampini   }
89339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&corners));
89344f819b78SStefano Zampini 
893598a51de6SStefano Zampini   if (pcbddc->coarse_ksp) {
893698a51de6SStefano Zampini     Vec crhs, csol;
893704708bb6SStefano Zampini 
89389566063dSJacob Faibussowitsch     PetscCall(KSPGetSolution(pcbddc->coarse_ksp, &csol));
89399566063dSJacob Faibussowitsch     PetscCall(KSPGetRhs(pcbddc->coarse_ksp, &crhs));
8940f4f49eeaSPierre Jolivet     if (!csol) PetscCall(MatCreateVecs(coarse_mat, &pcbddc->coarse_ksp->vec_sol, NULL));
8941f4f49eeaSPierre Jolivet     if (!crhs) PetscCall(MatCreateVecs(coarse_mat, NULL, &pcbddc->coarse_ksp->vec_rhs));
8942b0f5fe93SStefano Zampini   }
89439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarsedivudotp));
8944b0f5fe93SStefano Zampini 
8945b0f5fe93SStefano Zampini   /* compute null space for coarse solver if the benign trick has been requested */
8946b0f5fe93SStefano Zampini   if (pcbddc->benign_null) {
89479566063dSJacob Faibussowitsch     PetscCall(VecSet(pcbddc->vec1_P, 0.));
894848a46eb9SPierre 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));
89499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(pcbddc->vec1_P));
89509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(pcbddc->vec1_P));
89519566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
89529566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(pcbddc->coarse_loc_to_glob, pcbddc->vec1_P, pcbddc->coarse_vec, INSERT_VALUES, SCATTER_FORWARD));
8953b0f5fe93SStefano Zampini     if (coarse_mat) {
8954b0f5fe93SStefano Zampini       Vec          nullv;
8955b0f5fe93SStefano Zampini       PetscScalar *array, *array2;
8956b0f5fe93SStefano Zampini       PetscInt     nl;
8957b0f5fe93SStefano Zampini 
89589566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &nullv, NULL));
89599566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(nullv, &nl));
89609566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
89619566063dSJacob Faibussowitsch       PetscCall(VecGetArray(nullv, &array2));
89629566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(array2, array, nl));
89639566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(nullv, &array2));
89649566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(pcbddc->coarse_vec, (const PetscScalar **)&array));
89659566063dSJacob Faibussowitsch       PetscCall(VecNormalize(nullv, NULL));
89669566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)coarse_mat), PETSC_FALSE, 1, &nullv, &CoarseNullSpace));
89679566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&nullv));
8968b0f5fe93SStefano Zampini     }
8969b0f5fe93SStefano Zampini   }
89709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSetUp[pcbddc->current_level], pc, 0, 0, 0));
8971b0f5fe93SStefano Zampini 
89729566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
8973b0f5fe93SStefano Zampini   if (pcbddc->coarse_ksp) {
8974b0f5fe93SStefano Zampini     PetscBool ispreonly;
8975b0f5fe93SStefano Zampini 
8976b0f5fe93SStefano Zampini     if (CoarseNullSpace) {
8977b0f5fe93SStefano Zampini       PetscBool isnull;
89787c625d9fSStefano Zampini 
89799566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceTest(CoarseNullSpace, coarse_mat, &isnull));
89801baa6e33SBarry Smith       if (isnull) PetscCall(MatSetNullSpace(coarse_mat, CoarseNullSpace));
8981bef83e63SStefano Zampini       /* TODO: add local nullspaces (if any) */
8982b0f5fe93SStefano Zampini     }
8983b0f5fe93SStefano Zampini     /* setup coarse ksp */
89849566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(pcbddc->coarse_ksp));
8985cbcc2c2aSStefano Zampini     /* Check coarse problem if in debug mode or if solving with an iterative method */
89869566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pcbddc->coarse_ksp, KSPPREONLY, &ispreonly));
89876e683305SStefano Zampini     if (pcbddc->dbg_flag || (!ispreonly && pcbddc->use_coarse_estimates)) {
8988c8587f34SStefano Zampini       KSP         check_ksp;
89892b510759SStefano Zampini       KSPType     check_ksp_type;
8990c8587f34SStefano Zampini       PC          check_pc;
89916e683305SStefano Zampini       Vec         check_vec, coarse_vec;
89926a1308c2SStefano Zampini       PetscReal   abs_infty_error, infty_error, lambda_min = 1.0, lambda_max = 1.0;
89932b510759SStefano Zampini       PetscInt    its;
89946e683305SStefano Zampini       PetscBool   compute_eigs;
89956e683305SStefano Zampini       PetscReal  *eigs_r, *eigs_c;
89966e683305SStefano Zampini       PetscInt    neigs;
89978e185a42SStefano Zampini       const char *prefix;
8998c8587f34SStefano Zampini 
89992b510759SStefano Zampini       /* Create ksp object suitable for estimation of extreme eigenvalues */
90009566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pcbddc->coarse_ksp), &check_ksp));
90013821be0aSBarry Smith       PetscCall(KSPSetNestLevel(check_ksp, pc->kspnestlevel));
90029566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)check_ksp, (PetscObject)pcbddc->coarse_ksp, 0));
90039566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(pcbddc->coarse_ksp, PETSC_FALSE));
90049566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(check_ksp, coarse_mat, coarse_mat));
90059566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(check_ksp, 1.e-12, 1.e-12, PETSC_DEFAULT, pcbddc->coarse_size));
9006e4d548c7SStefano Zampini       /* prevent from setup unneeded object */
90079566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(check_ksp, &check_pc));
90089566063dSJacob Faibussowitsch       PetscCall(PCSetType(check_pc, PCNONE));
90092b510759SStefano Zampini       if (ispreonly) {
90102b510759SStefano Zampini         check_ksp_type = KSPPREONLY;
90116e683305SStefano Zampini         compute_eigs   = PETSC_FALSE;
90122b510759SStefano Zampini       } else {
9013cbcc2c2aSStefano Zampini         check_ksp_type = KSPGMRES;
90146e683305SStefano Zampini         compute_eigs   = PETSC_TRUE;
9015c8587f34SStefano Zampini       }
90169566063dSJacob Faibussowitsch       PetscCall(KSPSetType(check_ksp, check_ksp_type));
90179566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(check_ksp, compute_eigs));
90189566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeEigenvalues(check_ksp, compute_eigs));
90199566063dSJacob Faibussowitsch       PetscCall(KSPGMRESSetRestart(check_ksp, pcbddc->coarse_size + 1));
90209566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(pcbddc->coarse_ksp, &prefix));
90219566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(check_ksp, prefix));
90229566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(check_ksp, "check_"));
90239566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(check_ksp));
90249566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(check_ksp));
90259566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(pcbddc->coarse_ksp, &check_pc));
90269566063dSJacob Faibussowitsch       PetscCall(KSPSetPC(check_ksp, check_pc));
9027c8587f34SStefano Zampini       /* create random vec */
90289566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(coarse_mat, &coarse_vec, &check_vec));
90299566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(check_vec, NULL));
90309566063dSJacob Faibussowitsch       PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
9031c8587f34SStefano Zampini       /* solve coarse problem */
90329566063dSJacob Faibussowitsch       PetscCall(KSPSolve(check_ksp, coarse_vec, coarse_vec));
90339566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(check_ksp, pc, coarse_vec));
9034cbcc2c2aSStefano Zampini       /* set eigenvalue estimation if preonly has not been requested */
90356e683305SStefano Zampini       if (compute_eigs) {
90369566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_r));
90379566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(pcbddc->coarse_size + 1, &eigs_c));
90389566063dSJacob Faibussowitsch         PetscCall(KSPComputeEigenvalues(check_ksp, pcbddc->coarse_size + 1, eigs_r, eigs_c, &neigs));
90391ae86dd6SStefano Zampini         if (neigs) {
90406e683305SStefano Zampini           lambda_max = eigs_r[neigs - 1];
90416e683305SStefano Zampini           lambda_min = eigs_r[0];
90426e683305SStefano Zampini           if (pcbddc->use_coarse_estimates) {
90432701bc32SStefano Zampini             if (lambda_max >= lambda_min) { /* using PETSC_SMALL since lambda_max == lambda_min is not allowed by KSPChebyshevSetEigenvalues */
90449566063dSJacob Faibussowitsch               PetscCall(KSPChebyshevSetEigenvalues(pcbddc->coarse_ksp, lambda_max + PETSC_SMALL, lambda_min));
90459566063dSJacob Faibussowitsch               PetscCall(KSPRichardsonSetScale(pcbddc->coarse_ksp, 2.0 / (lambda_max + lambda_min)));
9046cbcc2c2aSStefano Zampini             }
9047c8587f34SStefano Zampini           }
9048c8587f34SStefano Zampini         }
90491ae86dd6SStefano Zampini       }
9050cbcc2c2aSStefano Zampini 
9051c8587f34SStefano Zampini       /* check coarse problem residual error */
90526e683305SStefano Zampini       if (pcbddc->dbg_flag) {
90536e683305SStefano Zampini         PetscViewer dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pcbddc->coarse_ksp));
90549566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
90559566063dSJacob Faibussowitsch         PetscCall(VecAXPY(check_vec, -1.0, coarse_vec));
90569566063dSJacob Faibussowitsch         PetscCall(VecNorm(check_vec, NORM_INFINITY, &infty_error));
90579566063dSJacob Faibussowitsch         PetscCall(MatMult(coarse_mat, check_vec, coarse_vec));
90589566063dSJacob Faibussowitsch         PetscCall(VecNorm(coarse_vec, NORM_INFINITY, &abs_infty_error));
90599566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem details (use estimates %d)\n", pcbddc->use_coarse_estimates));
9060f4f49eeaSPierre Jolivet         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pcbddc->coarse_ksp, dbg_viewer));
90619566063dSJacob Faibussowitsch         PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)(check_pc), dbg_viewer));
906263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem exact infty_error   : %1.6e\n", (double)infty_error));
906363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem residual infty_error: %1.6e\n", (double)abs_infty_error));
906448a46eb9SPierre Jolivet         if (CoarseNullSpace) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "Coarse problem is singular\n"));
90656e683305SStefano Zampini         if (compute_eigs) {
90666e683305SStefano Zampini           PetscReal          lambda_max_s, lambda_min_s;
9067b03ebc13SStefano Zampini           KSPConvergedReason reason;
90689566063dSJacob Faibussowitsch           PetscCall(KSPGetType(check_ksp, &check_ksp_type));
90699566063dSJacob Faibussowitsch           PetscCall(KSPGetIterationNumber(check_ksp, &its));
90709566063dSJacob Faibussowitsch           PetscCall(KSPGetConvergedReason(check_ksp, &reason));
90719566063dSJacob Faibussowitsch           PetscCall(KSPComputeExtremeSingularValues(check_ksp, &lambda_max_s, &lambda_min_s));
907263a3b9bcSJacob 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));
907348a46eb9SPierre Jolivet           for (i = 0; i < neigs; i++) PetscCall(PetscViewerASCIIPrintf(dbg_viewer, "%1.6e %1.6ei\n", (double)eigs_r[i], (double)eigs_c[i]));
90746e683305SStefano Zampini         }
90759566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(dbg_viewer));
90769566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(dbg_viewer, 2 * (pcbddc->current_level + 1)));
90776e683305SStefano Zampini       }
90789566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&check_vec));
90799566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&coarse_vec));
90809566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&check_ksp));
90816e683305SStefano Zampini       if (compute_eigs) {
90829566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_r));
90839566063dSJacob Faibussowitsch         PetscCall(PetscFree(eigs_c));
9084c8587f34SStefano Zampini       }
90856e683305SStefano Zampini     }
90866e683305SStefano Zampini   }
90879566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&CoarseNullSpace));
9088cbcc2c2aSStefano Zampini   /* print additional info */
9089cbcc2c2aSStefano Zampini   if (pcbddc->dbg_flag) {
90906e683305SStefano Zampini     /* waits until all processes reaches this point */
90919566063dSJacob Faibussowitsch     PetscCall(PetscBarrier((PetscObject)pc));
909263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Coarse solver setup completed at level %" PetscInt_FMT "\n", pcbddc->current_level));
90939566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9094cbcc2c2aSStefano Zampini   }
9095cbcc2c2aSStefano Zampini 
90962b510759SStefano Zampini   /* free memory */
90979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&coarse_mat));
90989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_CoarseSolver[pcbddc->current_level], pc, 0, 0, 0));
90993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9100c8587f34SStefano Zampini }
9101674ae819SStefano Zampini 
9102d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputePrimalNumbering(PC pc, PetscInt *coarse_size_n, PetscInt **local_primal_indices_n)
9103d71ae5a4SJacob Faibussowitsch {
9104f34684f1SStefano Zampini   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
9105f34684f1SStefano Zampini   PC_IS          *pcis   = (PC_IS *)pc->data;
9106dc456d91SStefano Zampini   IS              subset, subset_mult, subset_n;
9107dc456d91SStefano Zampini   PetscInt        local_size, coarse_size = 0;
910873be2a3aSStefano Zampini   PetscInt       *local_primal_indices = NULL;
9109dc456d91SStefano Zampini   const PetscInt *t_local_primal_indices;
9110f34684f1SStefano Zampini 
9111f34684f1SStefano Zampini   PetscFunctionBegin;
9112f34684f1SStefano Zampini   /* Compute global number of coarse dofs */
911308401ef6SPierre Jolivet   PetscCheck(!pcbddc->local_primal_size || pcbddc->local_primal_ref_node, PETSC_COMM_SELF, PETSC_ERR_PLIB, "BDDC ConstraintsSetUp should be called first");
9114f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_node, PETSC_COPY_VALUES, &subset_n));
91159566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyIS(pcis->mapping, subset_n, &subset));
91169566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9117f4f49eeaSPierre Jolivet   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc->pmat), pcbddc->local_primal_size_cc, pcbddc->local_primal_ref_mult, PETSC_COPY_VALUES, &subset_mult));
91189566063dSJacob Faibussowitsch   PetscCall(ISRenumber(subset, subset_mult, &coarse_size, &subset_n));
91199566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset));
91209566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_mult));
91219566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(subset_n, &local_size));
912263a3b9bcSJacob 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);
91239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(local_size, &local_primal_indices));
91249566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(subset_n, &t_local_primal_indices));
91259566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(local_primal_indices, t_local_primal_indices, local_size));
91269566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(subset_n, &t_local_primal_indices));
91279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&subset_n));
9128f34684f1SStefano Zampini 
9129f34684f1SStefano Zampini   if (pcbddc->dbg_flag) {
91309566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
91319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "--------------------------------------------------\n"));
91329de2952eSStefano Zampini     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "Size of coarse problem is %" PetscInt_FMT "\n", coarse_size));
91339566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
9134f34684f1SStefano Zampini   }
91356080607fSStefano Zampini 
9136f34684f1SStefano Zampini   /* get back data */
9137f34684f1SStefano Zampini   *coarse_size_n          = coarse_size;
9138f34684f1SStefano Zampini   *local_primal_indices_n = local_primal_indices;
91393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9140674ae819SStefano Zampini }
9141674ae819SStefano Zampini 
9142d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGlobalToLocal(VecScatter g2l_ctx, Vec gwork, Vec lwork, IS globalis, IS *localis)
9143d71ae5a4SJacob Faibussowitsch {
9144e456f2a8SStefano Zampini   IS           localis_t;
9145a7dc3881SStefano Zampini   PetscInt     i, lsize, *idxs, n;
9146e456f2a8SStefano Zampini   PetscScalar *vals;
9147e456f2a8SStefano Zampini 
9148e456f2a8SStefano Zampini   PetscFunctionBegin;
9149a7dc3881SStefano Zampini   /* get indices in local ordering exploiting local to global map */
91509566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(globalis, &lsize));
91519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &vals));
9152e456f2a8SStefano Zampini   for (i = 0; i < lsize; i++) vals[i] = 1.0;
91539566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(globalis, (const PetscInt **)&idxs));
91549566063dSJacob Faibussowitsch   PetscCall(VecSet(gwork, 0.0));
91559566063dSJacob Faibussowitsch   PetscCall(VecSet(lwork, 0.0));
91561035eff8SStefano Zampini   if (idxs) { /* multilevel guard */
91579566063dSJacob Faibussowitsch     PetscCall(VecSetOption(gwork, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
91589566063dSJacob Faibussowitsch     PetscCall(VecSetValues(gwork, lsize, idxs, vals, INSERT_VALUES));
91591035eff8SStefano Zampini   }
91609566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(gwork));
91619566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(globalis, (const PetscInt **)&idxs));
91629566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
91639566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(gwork));
9164a7dc3881SStefano Zampini   /* now compute set in local ordering */
91659566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
91669566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(g2l_ctx, gwork, lwork, INSERT_VALUES, SCATTER_FORWARD));
91679566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(lwork, (const PetscScalar **)&vals));
91689566063dSJacob Faibussowitsch   PetscCall(VecGetSize(lwork, &n));
9169a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9170ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) lsize++;
9171e456f2a8SStefano Zampini   }
91729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &idxs));
9173a7dc3881SStefano Zampini   for (i = 0, lsize = 0; i < n; i++) {
9174ad540459SPierre Jolivet     if (PetscRealPart(vals[i]) > 0.5) idxs[lsize++] = i;
9175e456f2a8SStefano Zampini   }
91769566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(lwork, (const PetscScalar **)&vals));
91779566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)gwork), lsize, idxs, PETSC_OWN_POINTER, &localis_t));
9178e456f2a8SStefano Zampini   *localis = localis_t;
91793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9180e456f2a8SStefano Zampini }
9181906d46d4SStefano Zampini 
9182d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCComputeFakeChange(PC pc, PetscBool constraints, PCBDDCGraph graph, PCBDDCSubSchurs schurs, Mat *change, IS *change_primal, IS *change_primal_mult, PetscBool *change_with_qr)
9183d71ae5a4SJacob Faibussowitsch {
91847c625d9fSStefano Zampini   PC_IS   *pcis   = (PC_IS *)pc->data;
91857c625d9fSStefano Zampini   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
91867c625d9fSStefano Zampini   PC_IS   *pcisf;
91877c625d9fSStefano Zampini   PC_BDDC *pcbddcf;
91887c625d9fSStefano Zampini   PC       pcf;
91897c625d9fSStefano Zampini 
91907c625d9fSStefano Zampini   PetscFunctionBegin;
91917c625d9fSStefano Zampini   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &pcf));
91927c625d9fSStefano Zampini   PetscCall(PCSetOperators(pcf, pc->mat, pc->pmat));
91937c625d9fSStefano Zampini   PetscCall(PCSetType(pcf, PCBDDC));
91947c625d9fSStefano Zampini 
91957c625d9fSStefano Zampini   pcisf   = (PC_IS *)pcf->data;
919632fe681dSStefano Zampini   pcbddcf = (PC_BDDC *)pcf->data;
919732fe681dSStefano Zampini 
91987c625d9fSStefano Zampini   pcisf->is_B_local = pcis->is_B_local;
91997c625d9fSStefano Zampini   pcisf->vec1_N     = pcis->vec1_N;
92007c625d9fSStefano Zampini   pcisf->BtoNmap    = pcis->BtoNmap;
92017c625d9fSStefano Zampini   pcisf->n          = pcis->n;
92027c625d9fSStefano Zampini   pcisf->n_B        = pcis->n_B;
92037c625d9fSStefano Zampini 
92047c625d9fSStefano Zampini   PetscCall(PetscFree(pcbddcf->mat_graph));
920532fe681dSStefano Zampini   PetscCall(PetscFree(pcbddcf->sub_schurs));
92067c625d9fSStefano Zampini   pcbddcf->mat_graph             = graph ? graph : pcbddc->mat_graph;
920732fe681dSStefano Zampini   pcbddcf->sub_schurs            = schurs;
920832fe681dSStefano Zampini   pcbddcf->adaptive_selection    = schurs ? PETSC_TRUE : PETSC_FALSE;
920932fe681dSStefano Zampini   pcbddcf->adaptive_threshold[0] = pcbddc->adaptive_threshold[0];
921032fe681dSStefano Zampini   pcbddcf->adaptive_threshold[1] = pcbddc->adaptive_threshold[1];
921132fe681dSStefano Zampini   pcbddcf->adaptive_nmin         = pcbddc->adaptive_nmin;
921232fe681dSStefano Zampini   pcbddcf->adaptive_nmax         = pcbddc->adaptive_nmax;
92137c625d9fSStefano Zampini   pcbddcf->use_faces             = PETSC_TRUE;
921432fe681dSStefano Zampini   pcbddcf->use_change_of_basis   = (PetscBool)!constraints;
921532fe681dSStefano Zampini   pcbddcf->use_change_on_faces   = (PetscBool)!constraints;
921632fe681dSStefano Zampini   pcbddcf->use_qr_single         = (PetscBool)!constraints;
92177c625d9fSStefano Zampini   pcbddcf->fake_change           = PETSC_TRUE;
921832fe681dSStefano Zampini   pcbddcf->dbg_flag              = pcbddc->dbg_flag;
921932fe681dSStefano Zampini 
922032fe681dSStefano Zampini   PetscCall(PCBDDCAdaptiveSelection(pcf));
92217c625d9fSStefano Zampini   PetscCall(PCBDDCConstraintsSetUp(pcf));
92227c625d9fSStefano Zampini 
92237c625d9fSStefano Zampini   *change = pcbddcf->ConstraintMatrix;
92247c625d9fSStefano 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));
92257c625d9fSStefano 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));
92267c625d9fSStefano Zampini   if (change_with_qr) *change_with_qr = pcbddcf->use_qr_single;
92277c625d9fSStefano Zampini 
922832fe681dSStefano Zampini   if (schurs) pcbddcf->sub_schurs = NULL;
92297c625d9fSStefano Zampini   pcbddcf->ConstraintMatrix = NULL;
923032fe681dSStefano Zampini   pcbddcf->mat_graph        = NULL;
923132fe681dSStefano Zampini   pcisf->is_B_local         = NULL;
923232fe681dSStefano Zampini   pcisf->vec1_N             = NULL;
923332fe681dSStefano Zampini   pcisf->BtoNmap            = NULL;
92347c625d9fSStefano Zampini   PetscCall(PCDestroy(&pcf));
92353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92367c625d9fSStefano Zampini }
92377c625d9fSStefano Zampini 
9238d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCSetUpSubSchurs(PC pc)
9239d71ae5a4SJacob Faibussowitsch {
9240a64f4aa4SStefano Zampini   PC_IS          *pcis       = (PC_IS *)pc->data;
9241b96c3477SStefano Zampini   PC_BDDC        *pcbddc     = (PC_BDDC *)pc->data;
9242b96c3477SStefano Zampini   PCBDDCSubSchurs sub_schurs = pcbddc->sub_schurs;
9243a64f4aa4SStefano Zampini   Mat             S_j;
9244b96c3477SStefano Zampini   PetscInt       *used_xadj, *used_adjncy;
9245b96c3477SStefano Zampini   PetscBool       free_used_adj;
9246b96c3477SStefano Zampini 
9247b96c3477SStefano Zampini   PetscFunctionBegin;
92489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
9249b96c3477SStefano Zampini   /* decide the adjacency to be used for determining internal problems for local schur on subsets */
9250b96c3477SStefano Zampini   free_used_adj = PETSC_FALSE;
925108122e43SStefano Zampini   if (pcbddc->sub_schurs_layers == -1) {
9252b96c3477SStefano Zampini     used_xadj   = NULL;
9253b96c3477SStefano Zampini     used_adjncy = NULL;
9254b96c3477SStefano Zampini   } else {
925508122e43SStefano Zampini     if (pcbddc->sub_schurs_use_useradj && pcbddc->mat_graph->xadj) {
925608122e43SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
925708122e43SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
925808122e43SStefano Zampini     } else if (pcbddc->computed_rowadj) {
9259b96c3477SStefano Zampini       used_xadj   = pcbddc->mat_graph->xadj;
9260b96c3477SStefano Zampini       used_adjncy = pcbddc->mat_graph->adjncy;
9261b96c3477SStefano Zampini     } else {
92622fffb893SStefano Zampini       PetscBool       flg_row = PETSC_FALSE;
9263b96c3477SStefano Zampini       const PetscInt *xadj, *adjncy;
9264b96c3477SStefano Zampini       PetscInt        nvtxs;
9265b96c3477SStefano Zampini 
92669566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
92672fffb893SStefano Zampini       if (flg_row) {
92689566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(nvtxs + 1, &used_xadj, xadj[nvtxs], &used_adjncy));
92699566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_xadj, xadj, nvtxs + 1));
92709566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(used_adjncy, adjncy, xadj[nvtxs]));
9271b96c3477SStefano Zampini         free_used_adj = PETSC_TRUE;
92722fffb893SStefano Zampini       } else {
92732fffb893SStefano Zampini         pcbddc->sub_schurs_layers = -1;
92742fffb893SStefano Zampini         used_xadj                 = NULL;
92752fffb893SStefano Zampini         used_adjncy               = NULL;
92762fffb893SStefano Zampini       }
92779566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(pcbddc->local_mat, 0, PETSC_TRUE, PETSC_FALSE, &nvtxs, &xadj, &adjncy, &flg_row));
9278b96c3477SStefano Zampini     }
9279b96c3477SStefano Zampini   }
9280d5574798SStefano Zampini 
9281d5574798SStefano Zampini   /* setup sub_schurs data */
92829566063dSJacob Faibussowitsch   PetscCall(MatCreateSchurComplement(pcis->A_II, pcis->pA_II, pcis->A_IB, pcis->A_BI, pcis->A_BB, &S_j));
9283df4d28bfSStefano Zampini   if (!sub_schurs->schur_explicit) {
9284df4d28bfSStefano Zampini     /* pcbddc->ksp_D up to date only if not using MatFactor with Schur complement support */
92859566063dSJacob Faibussowitsch     PetscCall(MatSchurComplementSetKSP(S_j, pcbddc->ksp_D));
92869566063dSJacob 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));
9287a64f4aa4SStefano Zampini   } else {
928872b8c272SStefano Zampini     Mat       change        = NULL;
92899d54b7f4SStefano Zampini     Vec       scaling       = NULL;
9290111315fdSstefano_zampini     IS        change_primal = NULL, iP;
9291111315fdSstefano_zampini     PetscInt  benign_n;
9292111315fdSstefano_zampini     PetscBool reuse_solvers     = (PetscBool)!pcbddc->use_change_of_basis;
92937ebab0bbSStefano Zampini     PetscBool need_change       = PETSC_FALSE;
9294111315fdSstefano_zampini     PetscBool discrete_harmonic = PETSC_FALSE;
9295a3df083aSStefano Zampini 
92965feab87aSStefano Zampini     if (!pcbddc->use_vertices && reuse_solvers) {
92975feab87aSStefano Zampini       PetscInt n_vertices;
92985feab87aSStefano Zampini 
92999566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(sub_schurs->is_vertices, &n_vertices));
93002034aafcSStefano Zampini       reuse_solvers = (PetscBool)!n_vertices;
93015feab87aSStefano Zampini     }
9302a3df083aSStefano Zampini     if (!pcbddc->benign_change_explicit) {
9303a3df083aSStefano Zampini       benign_n = pcbddc->benign_n;
9304ca92afb2SStefano Zampini     } else {
9305a3df083aSStefano Zampini       benign_n = 0;
9306ca92afb2SStefano Zampini     }
9307b7ab4a40SStefano Zampini     /* sub_schurs->change is a local object; instead, PCBDDCConstraintsSetUp and the quantities used in the test below are logically collective on pc.
9308b7ab4a40SStefano Zampini        We need a global reduction to avoid possible deadlocks.
9309b7ab4a40SStefano Zampini        We assume that sub_schurs->change is created once, and then reused for different solves, unless the topography has been recomputed */
931072b8c272SStefano Zampini     if (pcbddc->adaptive_userdefined || (pcbddc->deluxe_zerorows && !pcbddc->use_change_of_basis)) {
931122db5ddcSStefano Zampini       PetscBool have_loc_change = (PetscBool)(!!sub_schurs->change);
93121c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&have_loc_change, &need_change, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
931322db5ddcSStefano Zampini       need_change = (PetscBool)(!need_change);
9314b7ab4a40SStefano Zampini     }
93157c625d9fSStefano Zampini     /* If the user defines additional constraints, we import them here */
9316b7ab4a40SStefano Zampini     if (need_change) {
931728b400f6SJacob Faibussowitsch       PetscCheck(!pcbddc->sub_schurs_rebuild, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot compute change of basis with a different graph");
931832fe681dSStefano Zampini       PetscCall(PCBDDCComputeFakeChange(pc, PETSC_FALSE, NULL, NULL, &change, &change_primal, NULL, &sub_schurs->change_with_qr));
931988c03ad3SStefano Zampini     }
93209d54b7f4SStefano Zampini     if (!pcbddc->use_deluxe_scaling) scaling = pcis->D;
9321111315fdSstefano_zampini 
93229566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_iP", (PetscObject *)&iP));
9323111315fdSstefano_zampini     if (iP) {
9324d0609cedSBarry Smith       PetscOptionsBegin(PetscObjectComm((PetscObject)iP), sub_schurs->prefix, "BDDC sub_schurs options", "PC");
93259566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-sub_schurs_discrete_harmonic", NULL, NULL, discrete_harmonic, &discrete_harmonic, NULL));
9326d0609cedSBarry Smith       PetscOptionsEnd();
9327111315fdSstefano_zampini     }
9328111315fdSstefano_zampini     if (discrete_harmonic) {
9329111315fdSstefano_zampini       Mat A;
93309566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pcbddc->local_mat, MAT_COPY_VALUES, &A));
93319566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumnsIS(A, iP, 1.0, NULL, NULL));
93329566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)A, "__KSPFETIDP_iP", (PetscObject)iP));
93339371c9d4SSatish 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,
93349371c9d4SSatish Balay                                      pcbddc->benign_zerodiag_subs, change, change_primal));
93359566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A));
9336111315fdSstefano_zampini     } else {
93379371c9d4SSatish 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,
93389371c9d4SSatish Balay                                      pcbddc->benign_p0_lidx, pcbddc->benign_zerodiag_subs, change, change_primal));
9339111315fdSstefano_zampini     }
93409566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&change));
93419566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&change_primal));
9342ca92afb2SStefano Zampini   }
93439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S_j));
9344b96c3477SStefano Zampini 
9345b96c3477SStefano Zampini   /* free adjacency */
93461baa6e33SBarry Smith   if (free_used_adj) PetscCall(PetscFree2(used_xadj, used_adjncy));
93479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_BDDC_Schurs[pcbddc->current_level], pc, 0, 0, 0));
93483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9349b96c3477SStefano Zampini }
9350b96c3477SStefano Zampini 
9351d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCInitSubSchurs(PC pc)
9352d71ae5a4SJacob Faibussowitsch {
9353b96c3477SStefano Zampini   PC_IS      *pcis   = (PC_IS *)pc->data;
9354b96c3477SStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
9355b96c3477SStefano Zampini   PCBDDCGraph graph;
9356b96c3477SStefano Zampini 
9357b96c3477SStefano Zampini   PetscFunctionBegin;
9358b96c3477SStefano Zampini   /* attach interface graph for determining subsets */
935908122e43SStefano Zampini   if (pcbddc->sub_schurs_rebuild) { /* in case rebuild has been requested, it uses a graph generated only by the neighbouring information */
93603301b35fSStefano Zampini     IS       verticesIS, verticescomm;
93613301b35fSStefano Zampini     PetscInt vsize, *idxs;
9362b96c3477SStefano Zampini 
93639566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
93649566063dSJacob Faibussowitsch     PetscCall(ISGetSize(verticesIS, &vsize));
93659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(verticesIS, (const PetscInt **)&idxs));
93669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), vsize, idxs, PETSC_COPY_VALUES, &verticescomm));
93679566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(verticesIS, (const PetscInt **)&idxs));
93689566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph, NULL, NULL, NULL, NULL, &verticesIS));
93699566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphCreate(&graph));
93709566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphInit(graph, pcbddc->mat_graph->l2gmap, pcbddc->mat_graph->nvtxs_global, pcbddc->graphmaxcount));
93719566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphSetUp(graph, pcbddc->mat_graph->custom_minimal_size, NULL, pcbddc->DirichletBoundariesLocal, 0, NULL, verticescomm));
93729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&verticescomm));
93739566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphComputeConnectedComponents(graph));
9374b96c3477SStefano Zampini   } else {
9375b96c3477SStefano Zampini     graph = pcbddc->mat_graph;
9376b96c3477SStefano Zampini   }
9377e4d548c7SStefano Zampini   /* print some info */
93785c643e28SStefano Zampini   if (pcbddc->dbg_flag && !pcbddc->sub_schurs_rebuild) {
9379e4d548c7SStefano Zampini     IS       vertices;
9380e4d548c7SStefano Zampini     PetscInt nv, nedges, nfaces;
93819566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphASCIIView(graph, pcbddc->dbg_flag, pcbddc->dbg_viewer));
93829566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphGetCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
93839566063dSJacob Faibussowitsch     PetscCall(ISGetSize(vertices, &nv));
93849566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
93859566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "--------------------------------------------------------------\n"));
938663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate vertices (%d)\n", PetscGlobalRank, nv, pcbddc->use_vertices));
938763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate edges    (%d)\n", PetscGlobalRank, nedges, pcbddc->use_edges));
938863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(pcbddc->dbg_viewer, "Subdomain %04d got %02" PetscInt_FMT " local candidate faces    (%d)\n", PetscGlobalRank, nfaces, pcbddc->use_faces));
93899566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
93909566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
93919566063dSJacob Faibussowitsch     PetscCall(PCBDDCGraphRestoreCandidatesIS(graph, &nfaces, NULL, &nedges, NULL, &vertices));
9392e4d548c7SStefano Zampini   }
9393b96c3477SStefano Zampini 
9394b96c3477SStefano Zampini   /* sub_schurs init */
939548a46eb9SPierre Jolivet   if (!pcbddc->sub_schurs) PetscCall(PCBDDCSubSchursCreate(&pcbddc->sub_schurs));
939632fe681dSStefano 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));
9397a64f4aa4SStefano Zampini 
9398b96c3477SStefano Zampini   /* free graph struct */
939948a46eb9SPierre Jolivet   if (pcbddc->sub_schurs_rebuild) PetscCall(PCBDDCGraphDestroy(&graph));
94003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9401b96c3477SStefano Zampini }
9402fa34dd3eSStefano Zampini 
94039de2952eSStefano Zampini static PetscErrorCode PCBDDCViewGlobalIS(PC pc, IS is, PetscViewer viewer)
94049de2952eSStefano Zampini {
94059de2952eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)pc->pmat->data;
94069de2952eSStefano Zampini   PetscInt        n     = pc->pmat->rmap->n, ln, ni, st;
94079de2952eSStefano Zampini   const PetscInt *idxs;
94089de2952eSStefano Zampini   IS              gis;
94099de2952eSStefano Zampini 
94109de2952eSStefano Zampini   PetscFunctionBegin;
94119de2952eSStefano Zampini   if (!is) PetscFunctionReturn(PETSC_SUCCESS);
94129de2952eSStefano Zampini   PetscCall(MatGetOwnershipRange(pc->pmat, &st, NULL));
94139de2952eSStefano Zampini   PetscCall(MatGetLocalSize(matis->A, NULL, &ln));
94149de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_leafdata, ln));
94159de2952eSStefano Zampini   PetscCall(PetscArrayzero(matis->sf_rootdata, n));
94169de2952eSStefano Zampini   PetscCall(ISGetLocalSize(is, &ni));
94179de2952eSStefano Zampini   PetscCall(ISGetIndices(is, &idxs));
94189de2952eSStefano Zampini   for (PetscInt i = 0; i < ni; i++) {
94199de2952eSStefano Zampini     if (idxs[i] < 0 || idxs[i] >= ln) continue;
94209de2952eSStefano Zampini     matis->sf_leafdata[idxs[i]] = 1;
94219de2952eSStefano Zampini   }
94229de2952eSStefano Zampini   PetscCall(ISRestoreIndices(is, &idxs));
94239de2952eSStefano Zampini   PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
94249de2952eSStefano Zampini   PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, matis->sf_leafdata, matis->sf_rootdata, MPI_SUM));
94259de2952eSStefano Zampini   ln = 0;
94269de2952eSStefano Zampini   for (PetscInt i = 0; i < n; i++) {
94279de2952eSStefano Zampini     if (matis->sf_rootdata[i]) matis->sf_rootdata[ln++] = i + st;
94289de2952eSStefano Zampini   }
94299de2952eSStefano Zampini   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), ln, matis->sf_rootdata, PETSC_USE_POINTER, &gis));
94309de2952eSStefano Zampini   PetscCall(ISView(gis, viewer));
94319de2952eSStefano Zampini   PetscCall(ISDestroy(&gis));
94329de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
94339de2952eSStefano Zampini }
94349de2952eSStefano Zampini 
94359de2952eSStefano Zampini PetscErrorCode PCBDDCLoadOrViewCustomization(PC pc, PetscBool load, const char *outfile)
94369de2952eSStefano Zampini {
94379de2952eSStefano Zampini   PetscInt    header[11];
94389de2952eSStefano Zampini   PC_BDDC    *pcbddc = (PC_BDDC *)pc->data;
94399de2952eSStefano Zampini   PetscViewer viewer;
94409de2952eSStefano Zampini   MPI_Comm    comm = PetscObjectComm((PetscObject)pc);
94419de2952eSStefano Zampini 
94429de2952eSStefano Zampini   PetscFunctionBegin;
94439de2952eSStefano Zampini   PetscCall(PetscViewerBinaryOpen(comm, outfile ? outfile : "bddc_dump.dat", load ? FILE_MODE_READ : FILE_MODE_WRITE, &viewer));
94449de2952eSStefano Zampini   if (load) {
94459de2952eSStefano Zampini     IS  is;
94469de2952eSStefano Zampini     Mat A;
94479de2952eSStefano Zampini 
94489de2952eSStefano Zampini     PetscCall(PetscViewerBinaryRead(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), NULL, PETSC_INT));
94499de2952eSStefano Zampini     PetscCheck(header[0] == 0 || header[0] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94509de2952eSStefano Zampini     PetscCheck(header[1] == 0 || header[1] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94519de2952eSStefano Zampini     PetscCheck(header[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94529de2952eSStefano Zampini     PetscCheck(header[3] == 0 || header[3] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94539de2952eSStefano Zampini     PetscCheck(header[4] == 0 || header[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94549de2952eSStefano Zampini     PetscCheck(header[5] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94559de2952eSStefano Zampini     PetscCheck(header[7] == 0 || header[7] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94569de2952eSStefano Zampini     PetscCheck(header[8] == 0 || header[8] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94579de2952eSStefano Zampini     PetscCheck(header[9] == 0 || header[9] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94589de2952eSStefano Zampini     PetscCheck(header[10] == 0 || header[10] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a BDDC dump next in file");
94599de2952eSStefano Zampini     if (header[0]) {
94609de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
94619de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
94629de2952eSStefano Zampini       PetscCall(PCBDDCSetDirichletBoundaries(pc, is));
94639de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
94649de2952eSStefano Zampini     }
94659de2952eSStefano Zampini     if (header[1]) {
94669de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
94679de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
94689de2952eSStefano Zampini       PetscCall(PCBDDCSetNeumannBoundaries(pc, is));
94699de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
94709de2952eSStefano Zampini     }
94719de2952eSStefano Zampini     if (header[2]) {
94729de2952eSStefano Zampini       IS *isarray;
94739de2952eSStefano Zampini 
94749de2952eSStefano Zampini       PetscCall(PetscMalloc1(header[2], &isarray));
94759de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) {
94769de2952eSStefano Zampini         PetscCall(ISCreate(comm, &isarray[i]));
94779de2952eSStefano Zampini         PetscCall(ISLoad(isarray[i], viewer));
94789de2952eSStefano Zampini       }
94799de2952eSStefano Zampini       PetscCall(PCBDDCSetDofsSplitting(pc, header[2], isarray));
94809de2952eSStefano Zampini       for (PetscInt i = 0; i < header[2]; i++) PetscCall(ISDestroy(&isarray[i]));
94819de2952eSStefano Zampini       PetscCall(PetscFree(isarray));
94829de2952eSStefano Zampini     }
94839de2952eSStefano Zampini     if (header[3]) {
94849de2952eSStefano Zampini       PetscCall(ISCreate(comm, &is));
94859de2952eSStefano Zampini       PetscCall(ISLoad(is, viewer));
94869de2952eSStefano Zampini       PetscCall(PCBDDCSetPrimalVerticesIS(pc, is));
94879de2952eSStefano Zampini       PetscCall(ISDestroy(&is));
94889de2952eSStefano Zampini     }
94899de2952eSStefano Zampini     if (header[4]) {
94909de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
94919de2952eSStefano Zampini       PetscCall(MatSetType(A, MATAIJ));
94929de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
94939de2952eSStefano Zampini       PetscCall(PCBDDCSetDiscreteGradient(pc, A, header[5], header[6], (PetscBool)header[7], (PetscBool)header[8]));
94949de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
94959de2952eSStefano Zampini     }
94969de2952eSStefano Zampini     if (header[9]) {
94979de2952eSStefano Zampini       PetscCall(MatCreate(comm, &A));
94989de2952eSStefano Zampini       PetscCall(MatSetType(A, MATIS));
94999de2952eSStefano Zampini       PetscCall(MatLoad(A, viewer));
95009de2952eSStefano Zampini       PetscCall(PCBDDCSetDivergenceMat(pc, A, (PetscBool)header[10], NULL));
95019de2952eSStefano Zampini       PetscCall(MatDestroy(&A));
95029de2952eSStefano Zampini     }
95039de2952eSStefano Zampini   } else {
95049de2952eSStefano Zampini     header[0]  = (PetscInt) !!pcbddc->DirichletBoundariesLocal;
95059de2952eSStefano Zampini     header[1]  = (PetscInt) !!pcbddc->NeumannBoundariesLocal;
95069de2952eSStefano Zampini     header[2]  = pcbddc->n_ISForDofsLocal;
95079de2952eSStefano Zampini     header[3]  = (PetscInt) !!pcbddc->user_primal_vertices_local;
95089de2952eSStefano Zampini     header[4]  = (PetscInt) !!pcbddc->discretegradient;
95099de2952eSStefano Zampini     header[5]  = pcbddc->nedorder;
95109de2952eSStefano Zampini     header[6]  = pcbddc->nedfield;
95119de2952eSStefano Zampini     header[7]  = (PetscInt)pcbddc->nedglobal;
95129de2952eSStefano Zampini     header[8]  = (PetscInt)pcbddc->conforming;
95139de2952eSStefano Zampini     header[9]  = (PetscInt) !!pcbddc->divudotp;
95149de2952eSStefano Zampini     header[10] = (PetscInt)pcbddc->divudotp_trans;
95159de2952eSStefano Zampini     if (header[4]) header[3] = 0;
95169de2952eSStefano Zampini 
95179de2952eSStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, header, PETSC_STATIC_ARRAY_LENGTH(header), PETSC_INT));
95189de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->DirichletBoundariesLocal, viewer));
95199de2952eSStefano Zampini     PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->NeumannBoundariesLocal, viewer));
95209de2952eSStefano Zampini     for (PetscInt i = 0; i < header[2]; i++) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->ISForDofsLocal[i], viewer));
95219de2952eSStefano Zampini     if (header[3]) PetscCall(PCBDDCViewGlobalIS(pc, pcbddc->user_primal_vertices_local, viewer));
95229de2952eSStefano Zampini     if (header[4]) PetscCall(MatView(pcbddc->discretegradient, viewer));
95239de2952eSStefano Zampini     if (header[9]) PetscCall(MatView(pcbddc->divudotp, viewer));
95249de2952eSStefano Zampini   }
95259de2952eSStefano Zampini   PetscCall(PetscViewerDestroy(&viewer));
95269de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
95279de2952eSStefano Zampini }
95289de2952eSStefano Zampini 
95291e0482f5SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
9530ba38deedSJacob Faibussowitsch static PetscErrorCode MatMPIAIJRestrict(Mat A, MPI_Comm ccomm, Mat *B)
9531d71ae5a4SJacob Faibussowitsch {
95321e0482f5SStefano Zampini   Mat         At;
95331e0482f5SStefano Zampini   IS          rows;
95341e0482f5SStefano Zampini   PetscInt    rst, ren;
95351e0482f5SStefano Zampini   PetscLayout rmap;
95361e0482f5SStefano Zampini 
95371e0482f5SStefano Zampini   PetscFunctionBegin;
95381e0482f5SStefano Zampini   rst = ren = 0;
95391e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
95409566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(ccomm, &rmap));
95419566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(rmap, A->rmap->N));
95429566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(rmap, 1));
95439566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rmap));
95449566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rmap, &rst, &ren));
95451e0482f5SStefano Zampini   }
95469566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), ren - rst, rst, 1, &rows));
95479566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, &At));
95489566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rows));
95491e0482f5SStefano Zampini 
95501e0482f5SStefano Zampini   if (ccomm != MPI_COMM_NULL) {
95511e0482f5SStefano Zampini     Mat_MPIAIJ *a, *b;
95521e0482f5SStefano Zampini     IS          from, to;
95531e0482f5SStefano Zampini     Vec         gvec;
95541e0482f5SStefano Zampini     PetscInt    lsize;
95551e0482f5SStefano Zampini 
95569566063dSJacob Faibussowitsch     PetscCall(MatCreate(ccomm, B));
95579566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*B, ren - rst, PETSC_DECIDE, PETSC_DECIDE, At->cmap->N));
95589566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, MATAIJ));
95599566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&((*B)->rmap)));
95609566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp((*B)->cmap));
95611e0482f5SStefano Zampini     a = (Mat_MPIAIJ *)At->data;
95621e0482f5SStefano Zampini     b = (Mat_MPIAIJ *)(*B)->data;
95639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(ccomm, &b->size));
95649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(ccomm, &b->rank));
95659566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->A));
95669566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->B));
95671e0482f5SStefano Zampini     b->A = a->A;
95681e0482f5SStefano Zampini     b->B = a->B;
95691e0482f5SStefano Zampini 
95701e0482f5SStefano Zampini     b->donotstash   = a->donotstash;
95711e0482f5SStefano Zampini     b->roworiented  = a->roworiented;
95720a545947SLisandro Dalcin     b->rowindices   = NULL;
95730a545947SLisandro Dalcin     b->rowvalues    = NULL;
95741e0482f5SStefano Zampini     b->getrowactive = PETSC_FALSE;
95751e0482f5SStefano Zampini 
95761e0482f5SStefano Zampini     (*B)->rmap         = rmap;
95771e0482f5SStefano Zampini     (*B)->factortype   = A->factortype;
95781e0482f5SStefano Zampini     (*B)->assembled    = PETSC_TRUE;
95791e0482f5SStefano Zampini     (*B)->insertmode   = NOT_SET_VALUES;
95801e0482f5SStefano Zampini     (*B)->preallocated = PETSC_TRUE;
95811e0482f5SStefano Zampini 
95821e0482f5SStefano Zampini     if (a->colmap) {
95831e0482f5SStefano Zampini #if defined(PETSC_USE_CTABLE)
9584eec179cfSJacob Faibussowitsch       PetscCall(PetscHMapIDuplicate(a->colmap, &b->colmap));
95851e0482f5SStefano Zampini #else
95869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(At->cmap->N, &b->colmap));
95879566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(b->colmap, a->colmap, At->cmap->N));
95881e0482f5SStefano Zampini #endif
95890a545947SLisandro Dalcin     } else b->colmap = NULL;
95901e0482f5SStefano Zampini     if (a->garray) {
95911e0482f5SStefano Zampini       PetscInt len;
95921e0482f5SStefano Zampini       len = a->B->cmap->n;
95939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(len + 1, &b->garray));
95949566063dSJacob Faibussowitsch       if (len) PetscCall(PetscArraycpy(b->garray, a->garray, len));
95950a545947SLisandro Dalcin     } else b->garray = NULL;
95961e0482f5SStefano Zampini 
95979566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)a->lvec));
95981e0482f5SStefano Zampini     b->lvec = a->lvec;
95991e0482f5SStefano Zampini 
96001e0482f5SStefano Zampini     /* cannot use VecScatterCopy */
96019566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(b->lvec, &lsize));
96029566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(ccomm, lsize, b->garray, PETSC_USE_POINTER, &from));
96039566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, lsize, 0, 1, &to));
96049566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(*B, &gvec, NULL));
96059566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(gvec, from, b->lvec, to, &b->Mvctx));
96069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
96079566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&to));
96089566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gvec));
96091e0482f5SStefano Zampini   }
96109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&At));
96113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96121e0482f5SStefano Zampini }
96139de2952eSStefano Zampini 
96149de2952eSStefano Zampini /* same as MatCreateSubMatrix(A, rows, NULL,...) but allows repeated rows */
96159de2952eSStefano Zampini static PetscErrorCode MatAIJExtractRows(Mat A, IS rows, Mat *sA)
96169de2952eSStefano Zampini {
96179de2952eSStefano Zampini   PetscBool isaij;
96189de2952eSStefano Zampini   MPI_Comm  comm;
96199de2952eSStefano Zampini 
96209de2952eSStefano Zampini   PetscFunctionBegin;
96219de2952eSStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
96229de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &isaij, MATSEQAIJ, MATMPIAIJ, ""));
96239de2952eSStefano Zampini   PetscCheck(isaij, comm, PETSC_ERR_SUP, "Not implemented");
96249de2952eSStefano Zampini   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isaij));
96259de2952eSStefano Zampini   if (isaij) { /* SeqAIJ supports repeated rows */
96269de2952eSStefano Zampini     PetscCall(MatCreateSubMatrix(A, rows, NULL, MAT_INITIAL_MATRIX, sA));
96279de2952eSStefano Zampini   } else {
96289de2952eSStefano Zampini     Mat                A_loc;
96299de2952eSStefano Zampini     Mat_SeqAIJ        *da;
96309de2952eSStefano Zampini     PetscSF            sf;
96319de2952eSStefano Zampini     PetscInt           ni, *di, *dj, m = A->rmap->n, c, *ldata, *rdata;
96329de2952eSStefano Zampini     PetscScalar       *daa;
96339de2952eSStefano Zampini     const PetscInt    *idxs;
96349de2952eSStefano Zampini     const PetscSFNode *iremotes;
96359de2952eSStefano Zampini     PetscSFNode       *remotes;
96369de2952eSStefano Zampini 
96379de2952eSStefano Zampini     /* SF for incoming rows */
96389de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &sf));
96399de2952eSStefano Zampini     PetscCall(ISGetLocalSize(rows, &ni));
96409de2952eSStefano Zampini     PetscCall(ISGetIndices(rows, &idxs));
96419de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, ni, NULL, PETSC_USE_POINTER, idxs));
96429de2952eSStefano Zampini     PetscCall(ISRestoreIndices(rows, &idxs));
96439de2952eSStefano Zampini 
96449de2952eSStefano Zampini     PetscCall(MatMPIAIJGetLocalMat(A, MAT_INITIAL_MATRIX, &A_loc));
96459de2952eSStefano Zampini     da = (Mat_SeqAIJ *)A_loc->data;
96469de2952eSStefano Zampini     PetscCall(PetscMalloc2(2 * ni, &ldata, 2 * m, &rdata));
96479de2952eSStefano Zampini     for (PetscInt i = 0; i < m; i++) {
96489de2952eSStefano Zampini       rdata[2 * i + 0] = da->i[i + 1] - da->i[i];
96499de2952eSStefano Zampini       rdata[2 * i + 1] = da->i[i];
96509de2952eSStefano Zampini     }
96519de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
96529de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, rdata, ldata, MPI_REPLACE));
96539de2952eSStefano Zampini     PetscCall(PetscMalloc1(ni + 1, &di));
96549de2952eSStefano Zampini     di[0] = 0;
96559de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) di[i + 1] = di[i] + ldata[2 * i + 0];
96569de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &dj));
96579de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &daa));
96589de2952eSStefano Zampini     PetscCall(PetscMalloc1(di[ni], &remotes));
96599de2952eSStefano Zampini 
96609de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(sf, NULL, NULL, NULL, &iremotes));
96619de2952eSStefano Zampini 
96629de2952eSStefano Zampini     /* SF graph for nonzeros */
96639de2952eSStefano Zampini     c = 0;
96649de2952eSStefano Zampini     for (PetscInt i = 0; i < ni; i++) {
96659de2952eSStefano Zampini       const PetscInt rank  = iremotes[i].rank;
96669de2952eSStefano Zampini       const PetscInt rsize = ldata[2 * i];
96679de2952eSStefano Zampini       for (PetscInt j = 0; j < rsize; j++) {
96689de2952eSStefano Zampini         remotes[c].rank  = rank;
96699de2952eSStefano Zampini         remotes[c].index = ldata[2 * i + 1] + j;
96709de2952eSStefano Zampini         c++;
96719de2952eSStefano Zampini       }
96729de2952eSStefano Zampini     }
96739de2952eSStefano Zampini     PetscCheck(c == di[ni], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of local nonzeros %" PetscInt_FMT " != %" PetscInt_FMT, c, di[ni]);
96749de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(sf, da->i[m], di[ni], NULL, PETSC_USE_POINTER, remotes, PETSC_USE_POINTER));
96759de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
96769de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, da->j, dj, MPI_REPLACE));
96779de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
96789de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, da->a, daa, MPI_REPLACE));
96799de2952eSStefano Zampini 
96809de2952eSStefano Zampini     PetscCall(MatCreateMPIAIJWithArrays(comm, ni, A->cmap->n, PETSC_DECIDE, A->cmap->N, di, dj, daa, sA));
96819de2952eSStefano Zampini     PetscCall(MatDestroy(&A_loc));
96829de2952eSStefano Zampini     PetscCall(PetscSFDestroy(&sf));
96839de2952eSStefano Zampini     PetscCall(PetscFree(di));
96849de2952eSStefano Zampini     PetscCall(PetscFree(dj));
96859de2952eSStefano Zampini     PetscCall(PetscFree(daa));
96869de2952eSStefano Zampini     PetscCall(PetscFree(remotes));
96879de2952eSStefano Zampini     PetscCall(PetscFree2(ldata, rdata));
96889de2952eSStefano Zampini   }
96899de2952eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
96909de2952eSStefano Zampini }
9691