xref: /petsc/src/ksp/ksp/impls/fetidp/fetidp.c (revision a958fbfc1c07da5d8abfa22584ccb9c44e85e9ad)
1 #include <petsc/private/kspimpl.h> /*I <petscksp.h> I*/
2 #include <petsc/private/pcbddcimpl.h>
3 #include <petsc/private/pcbddcprivateimpl.h>
4 #include <petscdm.h>
5 
6 static PetscBool  cited  = PETSC_FALSE;
7 static PetscBool  cited2 = PETSC_FALSE;
8 static const char citation[] =
9 "@article{ZampiniPCBDDC,\n"
10 "author = {Stefano Zampini},\n"
11 "title = {{PCBDDC}: A Class of Robust Dual-Primal Methods in {PETS}c},\n"
12 "journal = {SIAM Journal on Scientific Computing},\n"
13 "volume = {38},\n"
14 "number = {5},\n"
15 "pages = {S282-S306},\n"
16 "year = {2016},\n"
17 "doi = {10.1137/15M1025785},\n"
18 "URL = {http://dx.doi.org/10.1137/15M1025785},\n"
19 "eprint = {http://dx.doi.org/10.1137/15M1025785}\n"
20 "}\n"
21 "@article{ZampiniDualPrimal,\n"
22 "author = {Stefano Zampini},\n"
23 "title = {{D}ual-{P}rimal methods for the cardiac {B}idomain model},\n"
24 "volume = {24},\n"
25 "number = {04},\n"
26 "pages = {667-696},\n"
27 "year = {2014},\n"
28 "doi = {10.1142/S0218202513500632},\n"
29 "URL = {https://www.worldscientific.com/doi/abs/10.1142/S0218202513500632},\n"
30 "eprint = {https://www.worldscientific.com/doi/pdf/10.1142/S0218202513500632}\n"
31 "}\n";
32 static const char citation2[] =
33 "@article{li2013nonoverlapping,\n"
34 "title={A nonoverlapping domain decomposition method for incompressible Stokes equations with continuous pressures},\n"
35 "author={Li, Jing and Tu, Xuemin},\n"
36 "journal={SIAM Journal on Numerical Analysis},\n"
37 "volume={51},\n"
38 "number={2},\n"
39 "pages={1235--1253},\n"
40 "year={2013},\n"
41 "publisher={Society for Industrial and Applied Mathematics}\n"
42 "}\n";
43 
44 /*
45     This file implements the FETI-DP method in PETSc as part of KSP.
46 */
47 typedef struct {
48   KSP parentksp;
49 } KSP_FETIDPMon;
50 
51 typedef struct {
52   KSP              innerksp;         /* the KSP for the Lagrange multipliers */
53   PC               innerbddc;        /* the inner BDDC object */
54   PetscBool        fully_redundant;  /* true for using a fully redundant set of multipliers */
55   PetscBool        userbddc;         /* true if the user provided the PCBDDC object */
56   PetscBool        saddlepoint;      /* support for saddle point problems */
57   IS               pP;               /* index set for pressure variables */
58   Vec              rhs_flip;         /* see KSPFETIDPSetUpOperators */
59   KSP_FETIDPMon    *monctx;          /* monitor context, used to pass user defined monitors
60                                         in the physical space */
61   PetscObjectState matstate;         /* these are needed just in the saddle point case */
62   PetscObjectState matnnzstate;      /* where we are going to use MatZeroRows on pmat */
63   PetscBool        statechanged;
64   PetscBool        check;
65 } KSP_FETIDP;
66 
67 static PetscErrorCode KSPFETIDPSetPressureOperator_FETIDP(KSP ksp, Mat P)
68 {
69   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
70 
71   PetscFunctionBegin;
72   if (P) fetidp->saddlepoint = PETSC_TRUE;
73   PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject)P));
74   PetscFunctionReturn(0);
75 }
76 
77 /*@
78  KSPFETIDPSetPressureOperator - Sets the operator used to setup the pressure preconditioner for saddle point FETI-DP.
79 
80    Collective on ksp
81 
82    Input Parameters:
83 +  ksp - the FETI-DP Krylov solver
84 -  P - the linear operator to be preconditioned, usually the mass matrix.
85 
86    Level: advanced
87 
88    Notes:
89     The operator can be either passed in a) monolithic global ordering, b) pressure-only global ordering
90           or c) interface pressure ordering (if -ksp_fetidp_pressure_all false).
91           In cases b) and c), the pressure ordering of dofs needs to satisfy
92              pid_1 < pid_2  iff  gid_1 < gid_2
93           where pid_1 and pid_2 are two different pressure dof numbers and gid_1 and gid_2 the corresponding
94           id in the monolithic global ordering.
95 
96 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPGetInnerBDDC`, `KSPFETIDPGetInnerKSP`, `KSPSetOperators`
97 @*/
98 PetscErrorCode KSPFETIDPSetPressureOperator(KSP ksp, Mat P)
99 {
100   PetscFunctionBegin;
101   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
102   if (P) PetscValidHeaderSpecific(P,MAT_CLASSID,2);
103   PetscTryMethod(ksp,"KSPFETIDPSetPressureOperator_C",(KSP,Mat),(ksp,P));
104   PetscFunctionReturn(0);
105 }
106 
107 static PetscErrorCode KSPFETIDPGetInnerKSP_FETIDP(KSP ksp, KSP* innerksp)
108 {
109   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
110 
111   PetscFunctionBegin;
112   *innerksp = fetidp->innerksp;
113   PetscFunctionReturn(0);
114 }
115 
116 /*@
117  KSPFETIDPGetInnerKSP - Gets the KSP object for the Lagrange multipliers
118 
119    Input Parameters:
120 +  ksp - the FETI-DP KSP
121 -  innerksp - the KSP for the multipliers
122 
123    Level: advanced
124 
125    Notes:
126 
127 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC`, `KSPFETIDPGetInnerBDDC`
128 @*/
129 PetscErrorCode KSPFETIDPGetInnerKSP(KSP ksp, KSP* innerksp)
130 {
131   PetscFunctionBegin;
132   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
133   PetscValidPointer(innerksp,2);
134   PetscUseMethod(ksp,"KSPFETIDPGetInnerKSP_C",(KSP,KSP*),(ksp,innerksp));
135   PetscFunctionReturn(0);
136 }
137 
138 static PetscErrorCode KSPFETIDPGetInnerBDDC_FETIDP(KSP ksp, PC* pc)
139 {
140   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
141 
142   PetscFunctionBegin;
143   *pc = fetidp->innerbddc;
144   PetscFunctionReturn(0);
145 }
146 
147 /*@
148  KSPFETIDPGetInnerBDDC - Gets the BDDC preconditioner used to setup the FETI-DP matrix for the Lagrange multipliers
149 
150    Input Parameters:
151 +  ksp - the FETI-DP Krylov solver
152 -  pc - the BDDC preconditioner
153 
154    Level: advanced
155 
156    Notes:
157 
158 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC`, `KSPFETIDPGetInnerKSP`
159 @*/
160 PetscErrorCode KSPFETIDPGetInnerBDDC(KSP ksp, PC* pc)
161 {
162   PetscFunctionBegin;
163   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
164   PetscValidPointer(pc,2);
165   PetscUseMethod(ksp,"KSPFETIDPGetInnerBDDC_C",(KSP,PC*),(ksp,pc));
166   PetscFunctionReturn(0);
167 }
168 
169 static PetscErrorCode KSPFETIDPSetInnerBDDC_FETIDP(KSP ksp, PC pc)
170 {
171   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
172 
173   PetscFunctionBegin;
174   PetscCall(PetscObjectReference((PetscObject)pc));
175   PetscCall(PCDestroy(&fetidp->innerbddc));
176   fetidp->innerbddc = pc;
177   fetidp->userbddc  = PETSC_TRUE;
178   PetscFunctionReturn(0);
179 }
180 
181 /*@
182  KSPFETIDPSetInnerBDDC - Sets the BDDC preconditioner used to setup the FETI-DP matrix for the Lagrange multipliers
183 
184    Collective on ksp
185 
186    Input Parameters:
187 +  ksp - the FETI-DP Krylov solver
188 -  pc - the BDDC preconditioner
189 
190    Level: advanced
191 
192    Notes:
193 
194 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPGetInnerBDDC`, `KSPFETIDPGetInnerKSP`
195 @*/
196 PetscErrorCode KSPFETIDPSetInnerBDDC(KSP ksp, PC pc)
197 {
198   PetscBool      isbddc;
199 
200   PetscFunctionBegin;
201   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
202   PetscValidHeaderSpecific(pc,PC_CLASSID,2);
203   PetscCall(PetscObjectTypeCompare((PetscObject)pc,PCBDDC,&isbddc));
204   PetscCheck(isbddc,PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_WRONG,"KSPFETIDPSetInnerBDDC need a PCBDDC preconditioner");
205   PetscTryMethod(ksp,"KSPFETIDPSetInnerBDDC_C",(KSP,PC),(ksp,pc));
206   PetscFunctionReturn(0);
207 }
208 
209 static PetscErrorCode KSPBuildSolution_FETIDP(KSP ksp,Vec v,Vec *V)
210 {
211   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
212   Mat            F;
213   Vec            Xl;
214 
215   PetscFunctionBegin;
216   PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL));
217   PetscCall(KSPBuildSolution(fetidp->innerksp,NULL,&Xl));
218   if (v) {
219     PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,v));
220     *V   = v;
221   } else {
222     PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,*V));
223   }
224   PetscFunctionReturn(0);
225 }
226 
227 static PetscErrorCode KSPMonitor_FETIDP(KSP ksp,PetscInt it,PetscReal rnorm,void* ctx)
228 {
229   KSP_FETIDPMon  *monctx = (KSP_FETIDPMon*)ctx;
230 
231   PetscFunctionBegin;
232   PetscCall(KSPMonitor(monctx->parentksp,it,rnorm));
233   PetscFunctionReturn(0);
234 }
235 
236 static PetscErrorCode KSPComputeEigenvalues_FETIDP(KSP ksp,PetscInt nmax,PetscReal *r,PetscReal *c,PetscInt *neig)
237 {
238   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
239 
240   PetscFunctionBegin;
241   PetscCall(KSPComputeEigenvalues(fetidp->innerksp,nmax,r,c,neig));
242   PetscFunctionReturn(0);
243 }
244 
245 static PetscErrorCode KSPComputeExtremeSingularValues_FETIDP(KSP ksp,PetscReal *emax,PetscReal *emin)
246 {
247   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
248 
249   PetscFunctionBegin;
250   PetscCall(KSPComputeExtremeSingularValues(fetidp->innerksp,emax,emin));
251   PetscFunctionReturn(0);
252 }
253 
254 static PetscErrorCode KSPFETIDPCheckOperators(KSP ksp, PetscViewer viewer)
255 {
256   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
257   PC_BDDC        *pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
258   PC_IS          *pcis = (PC_IS*)fetidp->innerbddc->data;
259   Mat_IS         *matis = (Mat_IS*)fetidp->innerbddc->pmat->data;
260   Mat            F;
261   FETIDPMat_ctx  fetidpmat_ctx;
262   Vec            test_vec,test_vec_p = NULL,fetidp_global;
263   IS             dirdofs,isvert;
264   MPI_Comm       comm = PetscObjectComm((PetscObject)ksp);
265   PetscScalar    sval,*array;
266   PetscReal      val,rval;
267   const PetscInt *vertex_indices;
268   PetscInt       i,n_vertices;
269   PetscBool      isascii;
270 
271   PetscFunctionBegin;
272   PetscCheckSameComm(ksp,1,viewer,2);
273   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
274   PetscCheck(isascii,comm,PETSC_ERR_SUP,"Unsupported viewer");
275   PetscCall(PetscViewerASCIIPrintf(viewer,"----------FETI-DP MAT  --------------\n"));
276   PetscCall(PetscViewerASCIIAddTab(viewer,2));
277   PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL));
278   PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO));
279   PetscCall(MatView(F,viewer));
280   PetscCall(PetscViewerPopFormat(viewer));
281   PetscCall(PetscViewerASCIISubtractTab(viewer,2));
282   PetscCall(MatShellGetContext(F,&fetidpmat_ctx));
283   PetscCall(PetscViewerASCIIPrintf(viewer,"----------FETI-DP TESTS--------------\n"));
284   PetscCall(PetscViewerASCIIPrintf(viewer,"All tests should return zero!\n"));
285   PetscCall(PetscViewerASCIIPrintf(viewer,"FETIDP MAT context in the "));
286   if (fetidp->fully_redundant) {
287     PetscCall(PetscViewerASCIIPrintf(viewer,"fully redundant case for lagrange multipliers.\n"));
288   } else {
289     PetscCall(PetscViewerASCIIPrintf(viewer,"Non-fully redundant case for lagrange multiplier.\n"));
290   }
291   PetscCall(PetscViewerFlush(viewer));
292 
293   /* Get Vertices used to define the BDDC */
294   PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&isvert));
295   PetscCall(ISGetLocalSize(isvert,&n_vertices));
296   PetscCall(ISGetIndices(isvert,&vertex_indices));
297 
298   /******************************************************************/
299   /* TEST A/B: Test numbering of global fetidp dofs                 */
300   /******************************************************************/
301   PetscCall(MatCreateVecs(F,&fetidp_global,NULL));
302   PetscCall(VecDuplicate(fetidpmat_ctx->lambda_local,&test_vec));
303   PetscCall(VecSet(fetidp_global,1.0));
304   PetscCall(VecSet(test_vec,1.));
305   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
306   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
307   if (fetidpmat_ctx->l2g_p) {
308     PetscCall(VecDuplicate(fetidpmat_ctx->vP,&test_vec_p));
309     PetscCall(VecSet(test_vec_p,1.));
310     PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidp_global,fetidpmat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE));
311     PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidp_global,fetidpmat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE));
312   }
313   PetscCall(VecAXPY(test_vec,-1.0,fetidpmat_ctx->lambda_local));
314   PetscCall(VecNorm(test_vec,NORM_INFINITY,&val));
315   PetscCall(VecDestroy(&test_vec));
316   PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm));
317   PetscCall(PetscViewerASCIIPrintf(viewer,"A: CHECK glob to loc: % 1.14e\n",(double)rval));
318 
319   if (fetidpmat_ctx->l2g_p) {
320     PetscCall(VecAXPY(test_vec_p,-1.0,fetidpmat_ctx->vP));
321     PetscCall(VecNorm(test_vec_p,NORM_INFINITY,&val));
322     PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm));
323     PetscCall(PetscViewerASCIIPrintf(viewer,"A: CHECK glob to loc (p): % 1.14e\n",(double)rval));
324   }
325 
326   if (fetidp->fully_redundant) {
327     PetscCall(VecSet(fetidp_global,0.0));
328     PetscCall(VecSet(fetidpmat_ctx->lambda_local,0.5));
329     PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
330     PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
331     PetscCall(VecSum(fetidp_global,&sval));
332     val  = PetscRealPart(sval)-fetidpmat_ctx->n_lambda;
333     PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm));
334     PetscCall(PetscViewerASCIIPrintf(viewer,"B: CHECK loc to glob: % 1.14e\n",(double)rval));
335   }
336 
337   if (fetidpmat_ctx->l2g_p) {
338     PetscCall(VecSet(pcis->vec1_N,1.0));
339     PetscCall(VecSet(pcis->vec1_global,0.0));
340     PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
341     PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
342 
343     PetscCall(VecSet(fetidp_global,0.0));
344     PetscCall(VecSet(fetidpmat_ctx->vP,-1.0));
345     PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
346     PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
347     PetscCall(VecScatterBegin(fetidpmat_ctx->g2g_p,fetidp_global,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
348     PetscCall(VecScatterEnd(fetidpmat_ctx->g2g_p,fetidp_global,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
349     PetscCall(VecScatterBegin(fetidpmat_ctx->g2g_p,pcis->vec1_global,fetidp_global,INSERT_VALUES,SCATTER_FORWARD));
350     PetscCall(VecScatterEnd(fetidpmat_ctx->g2g_p,pcis->vec1_global,fetidp_global,INSERT_VALUES,SCATTER_FORWARD));
351     PetscCall(VecSum(fetidp_global,&sval));
352     val  = PetscRealPart(sval);
353     PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm));
354     PetscCall(PetscViewerASCIIPrintf(viewer,"B: CHECK loc to glob (p): % 1.14e\n",(double)rval));
355   }
356 
357   /******************************************************************/
358   /* TEST C: It should hold B_delta*w=0, w\in\widehat{W}            */
359   /* This is the meaning of the B matrix                            */
360   /******************************************************************/
361 
362   PetscCall(VecSetRandom(pcis->vec1_N,NULL));
363   PetscCall(VecSet(pcis->vec1_global,0.0));
364   PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
365   PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE));
366   PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD));
367   PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD));
368   PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
369   PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
370   /* Action of B_delta */
371   PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local));
372   PetscCall(VecSet(fetidp_global,0.0));
373   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
374   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
375   PetscCall(VecNorm(fetidp_global,NORM_INFINITY,&val));
376   PetscCall(PetscViewerASCIIPrintf(viewer,"C: CHECK infty norm of B_delta*w (w continuous): % 1.14e\n",(double)val));
377 
378   /******************************************************************/
379   /* TEST D: It should hold E_Dw = w - P_Dw w\in\widetilde{W}       */
380   /* E_D = R_D^TR                                                   */
381   /* P_D = B_{D,delta}^T B_{delta}                                  */
382   /* eq.44 Mandel Tezaur and Dohrmann 2005                          */
383   /******************************************************************/
384 
385   /* compute a random vector in \widetilde{W} */
386   PetscCall(VecSetRandom(pcis->vec1_N,NULL));
387   /* set zero at vertices and essential dofs */
388   PetscCall(VecGetArray(pcis->vec1_N,&array));
389   for (i=0;i<n_vertices;i++) array[vertex_indices[i]] = 0.0;
390   PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph,&dirdofs));
391   if (dirdofs) {
392     const PetscInt *idxs;
393     PetscInt       ndir;
394 
395     PetscCall(ISGetLocalSize(dirdofs,&ndir));
396     PetscCall(ISGetIndices(dirdofs,&idxs));
397     for (i=0;i<ndir;i++) array[idxs[i]] = 0.0;
398     PetscCall(ISRestoreIndices(dirdofs,&idxs));
399   }
400   PetscCall(VecRestoreArray(pcis->vec1_N,&array));
401   /* store w for final comparison */
402   PetscCall(VecDuplicate(pcis->vec1_B,&test_vec));
403   PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,test_vec,INSERT_VALUES,SCATTER_FORWARD));
404   PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,test_vec,INSERT_VALUES,SCATTER_FORWARD));
405 
406   /* Jump operator P_D : results stored in pcis->vec1_B */
407   /* Action of B_delta */
408   PetscCall(MatMult(fetidpmat_ctx->B_delta,test_vec,fetidpmat_ctx->lambda_local));
409   PetscCall(VecSet(fetidp_global,0.0));
410   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
411   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
412   /* Action of B_Ddelta^T */
413   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
414   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
415   PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B));
416 
417   /* Average operator E_D : results stored in pcis->vec2_B */
418   PetscCall(PCBDDCScalingExtension(fetidpmat_ctx->pc,test_vec,pcis->vec1_global));
419   PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_global,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD));
420   PetscCall(VecScatterEnd(pcis->global_to_B,pcis->vec1_global,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD));
421 
422   /* test E_D=I-P_D */
423   PetscCall(VecAXPY(pcis->vec1_B,1.0,pcis->vec2_B));
424   PetscCall(VecAXPY(pcis->vec1_B,-1.0,test_vec));
425   PetscCall(VecNorm(pcis->vec1_B,NORM_INFINITY,&val));
426   PetscCall(VecDestroy(&test_vec));
427   PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm));
428   PetscCall(PetscViewerASCIIPrintf(viewer,"%d: CHECK infty norm of E_D + P_D - I: %1.14e\n",PetscGlobalRank,(double)val));
429 
430   /******************************************************************/
431   /* TEST E: It should hold R_D^TP_Dw=0 w\in\widetilde{W}           */
432   /* eq.48 Mandel Tezaur and Dohrmann 2005                          */
433   /******************************************************************/
434 
435   PetscCall(VecSetRandom(pcis->vec1_N,NULL));
436   /* set zero at vertices and essential dofs */
437   PetscCall(VecGetArray(pcis->vec1_N,&array));
438   for (i=0;i<n_vertices;i++) array[vertex_indices[i]] = 0.0;
439   if (dirdofs) {
440     const PetscInt *idxs;
441     PetscInt       ndir;
442 
443     PetscCall(ISGetLocalSize(dirdofs,&ndir));
444     PetscCall(ISGetIndices(dirdofs,&idxs));
445     for (i=0;i<ndir;i++) array[idxs[i]] = 0.0;
446     PetscCall(ISRestoreIndices(dirdofs,&idxs));
447   }
448   PetscCall(VecRestoreArray(pcis->vec1_N,&array));
449 
450   /* Jump operator P_D : results stored in pcis->vec1_B */
451 
452   PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
453   PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
454   /* Action of B_delta */
455   PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local));
456   PetscCall(VecSet(fetidp_global,0.0));
457   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
458   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD));
459   /* Action of B_Ddelta^T */
460   PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
461   PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
462   PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B));
463   /* scaling */
464   PetscCall(PCBDDCScalingExtension(fetidpmat_ctx->pc,pcis->vec1_B,pcis->vec1_global));
465   PetscCall(VecNorm(pcis->vec1_global,NORM_INFINITY,&val));
466   PetscCall(PetscViewerASCIIPrintf(viewer,"E: CHECK infty norm of R^T_D P_D: % 1.14e\n",(double)val));
467 
468   if (!fetidp->fully_redundant) {
469     /******************************************************************/
470     /* TEST F: It should holds B_{delta}B^T_{D,delta}=I               */
471     /* Corollary thm 14 Mandel Tezaur and Dohrmann 2005               */
472     /******************************************************************/
473     PetscCall(VecDuplicate(fetidp_global,&test_vec));
474     PetscCall(VecSetRandom(fetidp_global,NULL));
475     if (fetidpmat_ctx->l2g_p) {
476       PetscCall(VecSet(fetidpmat_ctx->vP,0.));
477       PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,INSERT_VALUES,SCATTER_FORWARD));
478       PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,INSERT_VALUES,SCATTER_FORWARD));
479     }
480     /* Action of B_Ddelta^T */
481     PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
482     PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
483     PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B));
484     /* Action of B_delta */
485     PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local));
486     PetscCall(VecSet(test_vec,0.0));
487     PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,test_vec,ADD_VALUES,SCATTER_FORWARD));
488     PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,test_vec,ADD_VALUES,SCATTER_FORWARD));
489     PetscCall(VecAXPY(fetidp_global,-1.,test_vec));
490     PetscCall(VecNorm(fetidp_global,NORM_INFINITY,&val));
491     PetscCall(PetscViewerASCIIPrintf(viewer,"E: CHECK infty norm of P^T_D - I: % 1.14e\n",(double)val));
492     PetscCall(VecDestroy(&test_vec));
493   }
494   PetscCall(PetscViewerASCIIPrintf(viewer,"-------------------------------------\n"));
495   PetscCall(PetscViewerFlush(viewer));
496   PetscCall(VecDestroy(&test_vec_p));
497   PetscCall(ISDestroy(&dirdofs));
498   PetscCall(VecDestroy(&fetidp_global));
499   PetscCall(ISRestoreIndices(isvert,&vertex_indices));
500   PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&isvert));
501   PetscFunctionReturn(0);
502 }
503 
504 static PetscErrorCode KSPFETIDPSetUpOperators(KSP ksp)
505 {
506   KSP_FETIDP       *fetidp = (KSP_FETIDP*)ksp->data;
507   PC_BDDC          *pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
508   Mat              A,Ap;
509   PetscInt         fid = -1;
510   PetscMPIInt      size;
511   PetscBool        ismatis,pisz = PETSC_FALSE,allp = PETSC_FALSE,schp = PETSC_FALSE;
512   PetscBool        flip = PETSC_FALSE; /* Usually, Stokes is written (B = -\int_\Omega \nabla \cdot u q)
513                            | A B'| | v | = | f |
514                            | B 0 | | p | = | g |
515                             If -ksp_fetidp_saddlepoint_flip is true, the code assumes it is written as
516                            | A B'| | v | = | f |
517                            |-B 0 | | p | = |-g |
518                          */
519   PetscObjectState matstate, matnnzstate;
520 
521   PetscFunctionBegin;
522   PetscOptionsBegin(PetscObjectComm((PetscObject)ksp),((PetscObject)ksp)->prefix,"FETI-DP options","PC");
523   PetscCall(PetscOptionsInt("-ksp_fetidp_pressure_field","Field id for pressures for saddle-point problems",NULL,fid,&fid,NULL));
524   PetscCall(PetscOptionsBool("-ksp_fetidp_pressure_all","Use the whole pressure set instead of just that at the interface",NULL,allp,&allp,NULL));
525   PetscCall(PetscOptionsBool("-ksp_fetidp_saddlepoint_flip","Flip the sign of the pressure-velocity (lower-left) block",NULL,flip,&flip,NULL));
526   PetscCall(PetscOptionsBool("-ksp_fetidp_pressure_schur","Use a BDDC solver for pressure",NULL,schp,&schp,NULL));
527   PetscOptionsEnd();
528 
529   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ksp),&size));
530   fetidp->saddlepoint = (fid >= 0 ? PETSC_TRUE : fetidp->saddlepoint);
531   if (size == 1) fetidp->saddlepoint = PETSC_FALSE;
532 
533   PetscCall(KSPGetOperators(ksp,&A,&Ap));
534   PetscCall(PetscObjectTypeCompare((PetscObject)A,MATIS,&ismatis));
535   PetscCheck(ismatis,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Amat should be of type MATIS");
536 
537   /* Quiet return if the matrix states are unchanged.
538      Needed only for the saddle point case since it uses MatZeroRows
539      on a matrix that may not have changed */
540   PetscCall(PetscObjectStateGet((PetscObject)A,&matstate));
541   PetscCall(MatGetNonzeroState(A,&matnnzstate));
542   if (matstate == fetidp->matstate && matnnzstate == fetidp->matnnzstate) PetscFunctionReturn(0);
543   fetidp->matstate     = matstate;
544   fetidp->matnnzstate  = matnnzstate;
545   fetidp->statechanged = fetidp->saddlepoint;
546 
547   /* see if we have some fields attached */
548   if (!pcbddc->n_ISForDofsLocal && !pcbddc->n_ISForDofs) {
549     DM             dm;
550     PetscContainer c;
551 
552     PetscCall(KSPGetDM(ksp,&dm));
553     PetscCall(PetscObjectQuery((PetscObject)A,"_convert_nest_lfields",(PetscObject*)&c));
554     if (dm) {
555       IS      *fields;
556       PetscInt nf,i;
557 
558       PetscCall(DMCreateFieldDecomposition(dm,&nf,NULL,&fields,NULL));
559       PetscCall(PCBDDCSetDofsSplitting(fetidp->innerbddc,nf,fields));
560       for (i=0;i<nf;i++) {
561         PetscCall(ISDestroy(&fields[i]));
562       }
563       PetscCall(PetscFree(fields));
564     } else if (c) {
565       MatISLocalFields lf;
566 
567       PetscCall(PetscContainerGetPointer(c,(void**)&lf));
568       PetscCall(PCBDDCSetDofsSplittingLocal(fetidp->innerbddc,lf->nr,lf->rf));
569     }
570   }
571 
572   if (!fetidp->saddlepoint) {
573     PetscCall(PCSetOperators(fetidp->innerbddc,A,A));
574   } else {
575     Mat          nA,lA,PPmat;
576     MatNullSpace nnsp;
577     IS           pP;
578     PetscInt     totP;
579 
580     PetscCall(MatISGetLocalMat(A,&lA));
581     PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",(PetscObject)lA));
582 
583     pP = fetidp->pP;
584     if (!pP) { /* first time, need to compute pressure dofs */
585       PC_IS                  *pcis = (PC_IS*)fetidp->innerbddc->data;
586       Mat_IS                 *matis = (Mat_IS*)(A->data);
587       ISLocalToGlobalMapping l2g;
588       IS                     lP = NULL,II,pII,lPall,Pall,is1,is2;
589       const PetscInt         *idxs;
590       PetscInt               nl,ni,*widxs;
591       PetscInt               i,j,n_neigh,*neigh,*n_shared,**shared,*count;
592       PetscInt               rst,ren,n;
593       PetscBool              ploc;
594 
595       PetscCall(MatGetLocalSize(A,&nl,NULL));
596       PetscCall(MatGetOwnershipRange(A,&rst,&ren));
597       PetscCall(MatGetLocalSize(lA,&n,NULL));
598       PetscCall(MatISGetLocalToGlobalMapping(A,&l2g,NULL));
599 
600       if (!pcis->is_I_local) { /* need to compute interior dofs */
601         PetscCall(PetscCalloc1(n,&count));
602         PetscCall(ISLocalToGlobalMappingGetInfo(l2g,&n_neigh,&neigh,&n_shared,&shared));
603         for (i=1;i<n_neigh;i++)
604           for (j=0;j<n_shared[i];j++)
605             count[shared[i][j]] += 1;
606         for (i=0,j=0;i<n;i++) if (!count[i]) count[j++] = i;
607         PetscCall(ISLocalToGlobalMappingRestoreInfo(l2g,&n_neigh,&neigh,&n_shared,&shared));
608         PetscCall(ISCreateGeneral(PETSC_COMM_SELF,j,count,PETSC_OWN_POINTER,&II));
609       } else {
610         PetscCall(PetscObjectReference((PetscObject)pcis->is_I_local));
611         II   = pcis->is_I_local;
612       }
613 
614       /* interior dofs in layout */
615       PetscCall(PetscArrayzero(matis->sf_leafdata,n));
616       PetscCall(PetscArrayzero(matis->sf_rootdata,nl));
617       PetscCall(ISGetLocalSize(II,&ni));
618       PetscCall(ISGetIndices(II,&idxs));
619       for (i=0;i<ni;i++) matis->sf_leafdata[idxs[i]] = 1;
620       PetscCall(ISRestoreIndices(II,&idxs));
621       PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
622       PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
623       PetscCall(PetscMalloc1(PetscMax(nl,n),&widxs));
624       for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst;
625       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&pII));
626 
627       /* pressure dofs */
628       Pall  = NULL;
629       lPall = NULL;
630       ploc  = PETSC_FALSE;
631       if (fid < 0) { /* zero pressure block */
632         PetscInt np;
633 
634         PetscCall(MatFindZeroDiagonals(A,&Pall));
635         PetscCall(ISGetSize(Pall,&np));
636         if (!np) { /* zero-block not found, defaults to last field (if set) */
637           fid  = pcbddc->n_ISForDofsLocal ? pcbddc->n_ISForDofsLocal - 1 : pcbddc->n_ISForDofs - 1;
638           PetscCall(ISDestroy(&Pall));
639         } else if (!pcbddc->n_ISForDofsLocal && !pcbddc->n_ISForDofs) {
640           PetscCall(PCBDDCSetDofsSplitting(fetidp->innerbddc,1,&Pall));
641         }
642       }
643       if (!Pall) { /* look for registered fields */
644         if (pcbddc->n_ISForDofsLocal) {
645           PetscInt np;
646 
647           PetscCheck(fid >= 0 && fid < pcbddc->n_ISForDofsLocal,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %" PetscInt_FMT ", max %" PetscInt_FMT,fid,pcbddc->n_ISForDofsLocal);
648           /* need a sequential IS */
649           PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[fid],&np));
650           PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[fid],&idxs));
651           PetscCall(ISCreateGeneral(PETSC_COMM_SELF,np,idxs,PETSC_COPY_VALUES,&lPall));
652           PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[fid],&idxs));
653           ploc = PETSC_TRUE;
654         } else if (pcbddc->n_ISForDofs) {
655           PetscCheck(fid >= 0 && fid < pcbddc->n_ISForDofs,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %" PetscInt_FMT ", max %" PetscInt_FMT,fid,pcbddc->n_ISForDofs);
656           PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofs[fid]));
657           Pall = pcbddc->ISForDofs[fid];
658         } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Cannot detect pressure field! Use KSPFETIDPGetInnerBDDC() + PCBDDCSetDofsSplitting or PCBDDCSetDofsSplittingLocal");
659       }
660 
661       /* if the user requested the entire pressure,
662          remove the interior pressure dofs from II (or pII) */
663       if (allp) {
664         if (ploc) {
665           IS nII;
666           PetscCall(ISDifference(II,lPall,&nII));
667           PetscCall(ISDestroy(&II));
668           II   = nII;
669         } else {
670           IS nII;
671           PetscCall(ISDifference(pII,Pall,&nII));
672           PetscCall(ISDestroy(&pII));
673           pII  = nII;
674         }
675       }
676       if (ploc) {
677         PetscCall(ISDifference(lPall,II,&lP));
678         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lP",(PetscObject)lP));
679       } else {
680         PetscCall(ISDifference(Pall,pII,&pP));
681         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",(PetscObject)pP));
682         /* need all local pressure dofs */
683         PetscCall(PetscArrayzero(matis->sf_leafdata,n));
684         PetscCall(PetscArrayzero(matis->sf_rootdata,nl));
685         PetscCall(ISGetLocalSize(Pall,&ni));
686         PetscCall(ISGetIndices(Pall,&idxs));
687         for (i=0;i<ni;i++) matis->sf_rootdata[idxs[i]-rst] = 1;
688         PetscCall(ISRestoreIndices(Pall,&idxs));
689         PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE));
690         PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE));
691         for (i=0,ni=0;i<n;i++) if (matis->sf_leafdata[i]) widxs[ni++] = i;
692         PetscCall(ISCreateGeneral(PETSC_COMM_SELF,ni,widxs,PETSC_COPY_VALUES,&lPall));
693       }
694 
695       if (!Pall) {
696         PetscCall(PetscArrayzero(matis->sf_leafdata,n));
697         PetscCall(PetscArrayzero(matis->sf_rootdata,nl));
698         PetscCall(ISGetLocalSize(lPall,&ni));
699         PetscCall(ISGetIndices(lPall,&idxs));
700         for (i=0;i<ni;i++) matis->sf_leafdata[idxs[i]] = 1;
701         PetscCall(ISRestoreIndices(lPall,&idxs));
702         PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
703         PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
704         for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst;
705         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&Pall));
706       }
707       PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject)Pall));
708 
709       if (flip) {
710         PetscInt npl;
711         PetscCall(ISGetLocalSize(Pall,&npl));
712         PetscCall(ISGetIndices(Pall,&idxs));
713         PetscCall(MatCreateVecs(A,NULL,&fetidp->rhs_flip));
714         PetscCall(VecSet(fetidp->rhs_flip,1.));
715         PetscCall(VecSetOption(fetidp->rhs_flip,VEC_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE));
716         for (i=0;i<npl;i++) {
717           PetscCall(VecSetValue(fetidp->rhs_flip,idxs[i],-1.,INSERT_VALUES));
718         }
719         PetscCall(VecAssemblyBegin(fetidp->rhs_flip));
720         PetscCall(VecAssemblyEnd(fetidp->rhs_flip));
721         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_flip",(PetscObject)fetidp->rhs_flip));
722         PetscCall(ISRestoreIndices(Pall,&idxs));
723       }
724       PetscCall(ISDestroy(&Pall));
725       PetscCall(ISDestroy(&pII));
726 
727       /* local selected pressures in subdomain-wise and global ordering */
728       PetscCall(PetscArrayzero(matis->sf_leafdata,n));
729       PetscCall(PetscArrayzero(matis->sf_rootdata,nl));
730       if (!ploc) {
731         PetscInt *widxs2;
732 
733         PetscCheck(pP,PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Missing parallel pressure IS");
734         PetscCall(ISGetLocalSize(pP,&ni));
735         PetscCall(ISGetIndices(pP,&idxs));
736         for (i=0;i<ni;i++) matis->sf_rootdata[idxs[i]-rst] = 1;
737         PetscCall(ISRestoreIndices(pP,&idxs));
738         PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE));
739         PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE));
740         for (i=0,ni=0;i<n;i++) if (matis->sf_leafdata[i]) widxs[ni++] = i;
741         PetscCall(PetscMalloc1(ni,&widxs2));
742         PetscCall(ISLocalToGlobalMappingApply(l2g,ni,widxs,widxs2));
743         PetscCall(ISCreateGeneral(PETSC_COMM_SELF,ni,widxs,PETSC_COPY_VALUES,&lP));
744         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lP",(PetscObject)lP));
745         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs2,PETSC_OWN_POINTER,&is1));
746         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_gP",(PetscObject)is1));
747         PetscCall(ISDestroy(&is1));
748       } else {
749         PetscCheck(lP,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing sequential pressure IS");
750         PetscCall(ISGetLocalSize(lP,&ni));
751         PetscCall(ISGetIndices(lP,&idxs));
752         for (i=0;i<ni;i++)
753           if (idxs[i] >=0 && idxs[i] < n)
754             matis->sf_leafdata[idxs[i]] = 1;
755         PetscCall(ISRestoreIndices(lP,&idxs));
756         PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
757         PetscCall(ISLocalToGlobalMappingApply(l2g,ni,idxs,widxs));
758         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&is1));
759         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_gP",(PetscObject)is1));
760         PetscCall(ISDestroy(&is1));
761         PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE));
762         for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst;
763         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&pP));
764         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",(PetscObject)pP));
765       }
766       PetscCall(PetscFree(widxs));
767 
768       /* If there's any "interior pressure",
769          we may want to use a discrete harmonic solver instead
770          of a Stokes harmonic for the Dirichlet preconditioner
771          Need to extract the interior velocity dofs in interior dofs ordering (iV)
772          and interior pressure dofs in local ordering (iP) */
773       if (!allp) {
774         ISLocalToGlobalMapping l2g_t;
775 
776         PetscCall(ISDifference(lPall,lP,&is1));
777         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_iP",(PetscObject)is1));
778         PetscCall(ISDifference(II,is1,&is2));
779         PetscCall(ISDestroy(&is1));
780         PetscCall(ISLocalToGlobalMappingCreateIS(II,&l2g_t));
781         PetscCall(ISGlobalToLocalMappingApplyIS(l2g_t,IS_GTOLM_DROP,is2,&is1));
782         PetscCall(ISGetLocalSize(is1,&i));
783         PetscCall(ISGetLocalSize(is2,&j));
784         PetscCheck(i == j,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent local sizes %" PetscInt_FMT " and %" PetscInt_FMT " for iV",i,j);
785         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_iV",(PetscObject)is1));
786         PetscCall(ISLocalToGlobalMappingDestroy(&l2g_t));
787         PetscCall(ISDestroy(&is1));
788         PetscCall(ISDestroy(&is2));
789       }
790       PetscCall(ISDestroy(&II));
791 
792       /* exclude selected pressures from the inner BDDC */
793       if (pcbddc->DirichletBoundariesLocal) {
794         IS       list[2],plP,isout;
795         PetscInt np;
796 
797         /* need a parallel IS */
798         PetscCall(ISGetLocalSize(lP,&np));
799         PetscCall(ISGetIndices(lP,&idxs));
800         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),np,idxs,PETSC_USE_POINTER,&plP));
801         list[0] = plP;
802         list[1] = pcbddc->DirichletBoundariesLocal;
803         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)ksp),2,list,&isout));
804         PetscCall(ISSortRemoveDups(isout));
805         PetscCall(ISDestroy(&plP));
806         PetscCall(ISRestoreIndices(lP,&idxs));
807         PetscCall(PCBDDCSetDirichletBoundariesLocal(fetidp->innerbddc,isout));
808         PetscCall(ISDestroy(&isout));
809       } else if (pcbddc->DirichletBoundaries) {
810         IS list[2],isout;
811 
812         list[0] = pP;
813         list[1] = pcbddc->DirichletBoundaries;
814         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)ksp),2,list,&isout));
815         PetscCall(ISSortRemoveDups(isout));
816         PetscCall(PCBDDCSetDirichletBoundaries(fetidp->innerbddc,isout));
817         PetscCall(ISDestroy(&isout));
818       } else {
819         IS       plP;
820         PetscInt np;
821 
822         /* need a parallel IS */
823         PetscCall(ISGetLocalSize(lP,&np));
824         PetscCall(ISGetIndices(lP,&idxs));
825         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),np,idxs,PETSC_COPY_VALUES,&plP));
826         PetscCall(PCBDDCSetDirichletBoundariesLocal(fetidp->innerbddc,plP));
827         PetscCall(ISDestroy(&plP));
828         PetscCall(ISRestoreIndices(lP,&idxs));
829       }
830 
831       /* save CSR information for the pressure BDDC solver (if any) */
832       if (schp) {
833         PetscInt np,nt;
834 
835         PetscCall(MatGetSize(matis->A,&nt,NULL));
836         PetscCall(ISGetLocalSize(lP,&np));
837         if (np) {
838           PetscInt *xadj = pcbddc->mat_graph->xadj;
839           PetscInt *adjn = pcbddc->mat_graph->adjncy;
840           PetscInt nv = pcbddc->mat_graph->nvtxs_csr;
841 
842           if (nv && nv == nt) {
843             ISLocalToGlobalMapping pmap;
844             PetscInt               *schp_csr,*schp_xadj,*schp_adjn,p;
845             PetscContainer         c;
846 
847             PetscCall(ISLocalToGlobalMappingCreateIS(lPall,&pmap));
848             PetscCall(ISGetIndices(lPall,&idxs));
849             for (p = 0, nv = 0; p < np; p++) {
850               PetscInt x,n = idxs[p];
851 
852               PetscCall(ISGlobalToLocalMappingApply(pmap,IS_GTOLM_DROP,xadj[n+1]-xadj[n],adjn+xadj[n],&x,NULL));
853               nv  += x;
854             }
855             PetscCall(PetscMalloc1(np + 1 + nv,&schp_csr));
856             schp_xadj = schp_csr;
857             schp_adjn = schp_csr + np + 1;
858             for (p = 0, schp_xadj[0] = 0; p < np; p++) {
859               PetscInt x,n = idxs[p];
860 
861               PetscCall(ISGlobalToLocalMappingApply(pmap,IS_GTOLM_DROP,xadj[n+1]-xadj[n],adjn+xadj[n],&x,schp_adjn + schp_xadj[p]));
862               schp_xadj[p+1] = schp_xadj[p] + x;
863             }
864             PetscCall(ISRestoreIndices(lPall,&idxs));
865             PetscCall(ISLocalToGlobalMappingDestroy(&pmap));
866             PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&c));
867             PetscCall(PetscContainerSetPointer(c,schp_csr));
868             PetscCall(PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault));
869             PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pCSR",(PetscObject)c));
870             PetscCall(PetscContainerDestroy(&c));
871 
872           }
873         }
874       }
875       PetscCall(ISDestroy(&lPall));
876       PetscCall(ISDestroy(&lP));
877       fetidp->pP = pP;
878     }
879 
880     /* total number of selected pressure dofs */
881     PetscCall(ISGetSize(fetidp->pP,&totP));
882 
883     /* Set operator for inner BDDC */
884     if (totP || fetidp->rhs_flip) {
885       PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&nA));
886     } else {
887       PetscCall(PetscObjectReference((PetscObject)A));
888       nA   = A;
889     }
890     if (fetidp->rhs_flip) {
891       PetscCall(MatDiagonalScale(nA,fetidp->rhs_flip,NULL));
892       if (totP) {
893         Mat lA2;
894 
895         PetscCall(MatISGetLocalMat(nA,&lA));
896         PetscCall(MatDuplicate(lA,MAT_COPY_VALUES,&lA2));
897         PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",(PetscObject)lA2));
898         PetscCall(MatDestroy(&lA2));
899       }
900     }
901 
902     if (totP) {
903       PetscCall(MatSetOption(nA,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE));
904       PetscCall(MatZeroRowsColumnsIS(nA,fetidp->pP,1.,NULL,NULL));
905     } else {
906       PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",NULL));
907     }
908     PetscCall(MatGetNearNullSpace(Ap,&nnsp));
909     if (!nnsp) {
910       PetscCall(MatGetNullSpace(Ap,&nnsp));
911     }
912     if (!nnsp) {
913       PetscCall(MatGetNearNullSpace(A,&nnsp));
914     }
915     if (!nnsp) {
916       PetscCall(MatGetNullSpace(A,&nnsp));
917     }
918     PetscCall(MatSetNearNullSpace(nA,nnsp));
919     PetscCall(PCSetOperators(fetidp->innerbddc,nA,nA));
920     PetscCall(MatDestroy(&nA));
921 
922     /* non-zero rhs on interior dofs when applying the preconditioner */
923     if (totP) pcbddc->switch_static = PETSC_TRUE;
924 
925     /* if there are no interface pressures, set inner bddc flag for benign saddle point */
926     if (!totP) {
927       pcbddc->benign_saddle_point = PETSC_TRUE;
928       pcbddc->compute_nonetflux   = PETSC_TRUE;
929     }
930 
931     /* Operators for pressure preconditioner */
932     if (totP) {
933       /* Extract pressure block if needed */
934       if (!pisz) {
935         Mat C;
936         IS  nzrows = NULL;
937 
938         PetscCall(MatCreateSubMatrix(A,fetidp->pP,fetidp->pP,MAT_INITIAL_MATRIX,&C));
939         PetscCall(MatFindNonzeroRows(C,&nzrows));
940         if (nzrows) {
941           PetscInt i;
942 
943           PetscCall(ISGetSize(nzrows,&i));
944           PetscCall(ISDestroy(&nzrows));
945           if (!i) pisz = PETSC_TRUE;
946         }
947         if (!pisz) {
948           PetscCall(MatScale(C,-1.)); /* i.e. Almost Incompressible Elasticity, Stokes discretized with Q1xQ1_stabilized */
949           PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_C",(PetscObject)C));
950         }
951         PetscCall(MatDestroy(&C));
952       }
953       /* Divergence mat */
954       if (!pcbddc->divudotp) {
955         Mat       B;
956         IS        P;
957         IS        l2l = NULL;
958         PetscBool save;
959 
960         PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&P));
961         if (!pisz) {
962           IS       F,V;
963           PetscInt m,M;
964 
965           PetscCall(MatGetOwnershipRange(A,&m,&M));
966           PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),M-m,m,1,&F));
967           PetscCall(ISComplement(P,m,M,&V));
968           PetscCall(MatCreateSubMatrix(A,P,V,MAT_INITIAL_MATRIX,&B));
969           {
970             Mat_IS *Bmatis = (Mat_IS*)B->data;
971             PetscCall(PetscObjectReference((PetscObject)Bmatis->getsub_cis));
972             l2l  = Bmatis->getsub_cis;
973           }
974           PetscCall(ISDestroy(&V));
975           PetscCall(ISDestroy(&F));
976         } else {
977           PetscCall(MatCreateSubMatrix(A,P,NULL,MAT_INITIAL_MATRIX,&B));
978         }
979         save = pcbddc->compute_nonetflux; /* SetDivergenceMat activates nonetflux computation */
980         PetscCall(PCBDDCSetDivergenceMat(fetidp->innerbddc,B,PETSC_FALSE,l2l));
981         pcbddc->compute_nonetflux = save;
982         PetscCall(MatDestroy(&B));
983         PetscCall(ISDestroy(&l2l));
984       }
985       if (A != Ap) { /* user has provided a different Pmat, this always superseeds the setter (TODO: is it OK?) */
986         /* use monolithic operator, we restrict later */
987         PetscCall(KSPFETIDPSetPressureOperator(ksp,Ap));
988       }
989       PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject*)&PPmat));
990 
991       /* PPmat not present, use some default choice */
992       if (!PPmat) {
993         Mat C;
994 
995         PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_C",(PetscObject*)&C));
996         if (!schp && C) { /* non-zero pressure block, most likely Almost Incompressible Elasticity */
997           PetscCall(KSPFETIDPSetPressureOperator(ksp,C));
998         } else if (!pisz && schp) { /* we need the whole pressure mass matrix to define the interface BDDC */
999           IS  P;
1000 
1001           PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&P));
1002           PetscCall(MatCreateSubMatrix(A,P,P,MAT_INITIAL_MATRIX,&C));
1003           PetscCall(MatScale(C,-1.));
1004           PetscCall(KSPFETIDPSetPressureOperator(ksp,C));
1005           PetscCall(MatDestroy(&C));
1006         } else { /* identity (need to be scaled properly by the user using e.g. a Richardson method */
1007           PetscInt nl;
1008 
1009           PetscCall(ISGetLocalSize(fetidp->pP,&nl));
1010           PetscCall(MatCreate(PetscObjectComm((PetscObject)ksp),&C));
1011           PetscCall(MatSetSizes(C,nl,nl,totP,totP));
1012           PetscCall(MatSetType(C,MATAIJ));
1013           PetscCall(MatMPIAIJSetPreallocation(C,1,NULL,0,NULL));
1014           PetscCall(MatSeqAIJSetPreallocation(C,1,NULL));
1015           PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
1016           PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
1017           PetscCall(MatShift(C,1.));
1018           PetscCall(KSPFETIDPSetPressureOperator(ksp,C));
1019           PetscCall(MatDestroy(&C));
1020         }
1021       }
1022 
1023       /* Preconditioned operator for the pressure block */
1024       PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject*)&PPmat));
1025       if (PPmat) {
1026         Mat      C;
1027         IS       Pall;
1028         PetscInt AM,PAM,PAN,pam,pan,am,an,pl,pIl,pAg,pIg;
1029 
1030         PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&Pall));
1031         PetscCall(MatGetSize(A,&AM,NULL));
1032         PetscCall(MatGetSize(PPmat,&PAM,&PAN));
1033         PetscCall(ISGetSize(Pall,&pAg));
1034         PetscCall(ISGetSize(fetidp->pP,&pIg));
1035         PetscCall(MatGetLocalSize(PPmat,&pam,&pan));
1036         PetscCall(MatGetLocalSize(A,&am,&an));
1037         PetscCall(ISGetLocalSize(Pall,&pIl));
1038         PetscCall(ISGetLocalSize(fetidp->pP,&pl));
1039         PetscCheck(PAM == PAN,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Pressure matrix must be square, unsupported %" PetscInt_FMT " x %" PetscInt_FMT,PAM,PAN);
1040         PetscCheck(pam == pan,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Local sizes of pressure matrix must be equal, unsupported %" PetscInt_FMT " x %" PetscInt_FMT,pam,pan);
1041         PetscCheck(pam == am || pam == pl || pam == pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local rows %" PetscInt_FMT " for pressure matrix! Supported are %" PetscInt_FMT ", %" PetscInt_FMT " or %" PetscInt_FMT,pam,am,pl,pIl);
1042         PetscCheck(pan == an || pan == pl || pan == pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local columns %" PetscInt_FMT " for pressure matrix! Supported are %" PetscInt_FMT ", %" PetscInt_FMT " or %" PetscInt_FMT,pan,an,pl,pIl);
1043         if (PAM == AM) { /* monolithic ordering, restrict to pressure */
1044           if (schp) {
1045             PetscCall(MatCreateSubMatrix(PPmat,Pall,Pall,MAT_INITIAL_MATRIX,&C));
1046           } else {
1047             PetscCall(MatCreateSubMatrix(PPmat,fetidp->pP,fetidp->pP,MAT_INITIAL_MATRIX,&C));
1048           }
1049         } else if (pAg == PAM) { /* global ordering for pressure only */
1050           if (!allp && !schp) { /* solving for interface pressure only */
1051             IS restr;
1052 
1053             PetscCall(ISRenumber(fetidp->pP,NULL,NULL,&restr));
1054             PetscCall(MatCreateSubMatrix(PPmat,restr,restr,MAT_INITIAL_MATRIX,&C));
1055             PetscCall(ISDestroy(&restr));
1056           } else {
1057             PetscCall(PetscObjectReference((PetscObject)PPmat));
1058             C    = PPmat;
1059           }
1060         } else if (pIg == PAM) { /* global ordering for selected pressure only */
1061           PetscCheck(!schp,PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Need the entire matrix");
1062           PetscCall(PetscObjectReference((PetscObject)PPmat));
1063           C    = PPmat;
1064         } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Unable to use the pressure matrix");
1065 
1066         PetscCall(KSPFETIDPSetPressureOperator(ksp,C));
1067         PetscCall(MatDestroy(&C));
1068       } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Missing Pmat for pressure block");
1069     } else { /* totP == 0 */
1070       PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",NULL));
1071     }
1072   }
1073   PetscFunctionReturn(0);
1074 }
1075 
1076 static PetscErrorCode KSPSetUp_FETIDP(KSP ksp)
1077 {
1078   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
1079   PC_BDDC        *pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
1080   PetscBool      flg;
1081 
1082   PetscFunctionBegin;
1083   PetscCall(KSPFETIDPSetUpOperators(ksp));
1084   /* set up BDDC */
1085   PetscCall(PCSetErrorIfFailure(fetidp->innerbddc,ksp->errorifnotconverged));
1086   PetscCall(PCSetUp(fetidp->innerbddc));
1087   /* FETI-DP as it is implemented needs an exact coarse solver */
1088   if (pcbddc->coarse_ksp) {
1089     PetscCall(KSPSetTolerances(pcbddc->coarse_ksp,PETSC_SMALL,PETSC_SMALL,PETSC_DEFAULT,1000));
1090     PetscCall(KSPSetNormType(pcbddc->coarse_ksp,KSP_NORM_DEFAULT));
1091   }
1092   /* FETI-DP as it is implemented needs exact local Neumann solvers */
1093   PetscCall(KSPSetTolerances(pcbddc->ksp_R,PETSC_SMALL,PETSC_SMALL,PETSC_DEFAULT,1000));
1094   PetscCall(KSPSetNormType(pcbddc->ksp_R,KSP_NORM_DEFAULT));
1095 
1096   /* setup FETI-DP operators
1097      If fetidp->statechanged is true, we need to update the operators
1098      needed in the saddle-point case. This should be replaced
1099      by a better logic when the FETI-DP matrix and preconditioner will
1100      have their own classes */
1101   if (pcbddc->new_primal_space || fetidp->statechanged) {
1102     Mat F; /* the FETI-DP matrix */
1103     PC  D; /* the FETI-DP preconditioner */
1104     PetscCall(KSPReset(fetidp->innerksp));
1105     PetscCall(PCBDDCCreateFETIDPOperators(fetidp->innerbddc,fetidp->fully_redundant,((PetscObject)ksp)->prefix,&F,&D));
1106     PetscCall(KSPSetOperators(fetidp->innerksp,F,F));
1107     PetscCall(KSPSetTolerances(fetidp->innerksp,ksp->rtol,ksp->abstol,ksp->divtol,ksp->max_it));
1108     PetscCall(KSPSetPC(fetidp->innerksp,D));
1109     PetscCall(PetscObjectIncrementTabLevel((PetscObject)D,(PetscObject)fetidp->innerksp,0));
1110     PetscCall(KSPSetFromOptions(fetidp->innerksp));
1111     PetscCall(MatCreateVecs(F,&(fetidp->innerksp)->vec_rhs,&(fetidp->innerksp)->vec_sol));
1112     PetscCall(MatDestroy(&F));
1113     PetscCall(PCDestroy(&D));
1114     if (fetidp->check) {
1115       PetscViewer viewer;
1116 
1117       if (!pcbddc->dbg_viewer) {
1118         viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)ksp));
1119       } else {
1120         viewer = pcbddc->dbg_viewer;
1121       }
1122       PetscCall(KSPFETIDPCheckOperators(ksp,viewer));
1123     }
1124   }
1125   fetidp->statechanged     = PETSC_FALSE;
1126   pcbddc->new_primal_space = PETSC_FALSE;
1127 
1128   /* propagate settings to the inner solve */
1129   PetscCall(KSPGetComputeSingularValues(ksp,&flg));
1130   PetscCall(KSPSetComputeSingularValues(fetidp->innerksp,flg));
1131   if (ksp->res_hist) {
1132     PetscCall(KSPSetResidualHistory(fetidp->innerksp,ksp->res_hist,ksp->res_hist_max,ksp->res_hist_reset));
1133   }
1134   PetscCall(KSPSetErrorIfNotConverged(fetidp->innerksp,ksp->errorifnotconverged));
1135   PetscCall(KSPSetUp(fetidp->innerksp));
1136   PetscFunctionReturn(0);
1137 }
1138 
1139 static PetscErrorCode KSPSolve_FETIDP(KSP ksp)
1140 {
1141   Mat                F,A;
1142   MatNullSpace       nsp;
1143   Vec                X,B,Xl,Bl;
1144   KSP_FETIDP         *fetidp = (KSP_FETIDP*)ksp->data;
1145   PC_BDDC            *pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
1146   KSPConvergedReason reason;
1147   PC                 pc;
1148   PCFailedReason     pcreason;
1149   PetscInt           hist_len;
1150 
1151   PetscFunctionBegin;
1152   PetscCall(PetscCitationsRegister(citation,&cited));
1153   if (fetidp->saddlepoint) {
1154     PetscCall(PetscCitationsRegister(citation2,&cited2));
1155   }
1156   PetscCall(KSPGetOperators(ksp,&A,NULL));
1157   PetscCall(KSPGetRhs(ksp,&B));
1158   PetscCall(KSPGetSolution(ksp,&X));
1159   PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL));
1160   PetscCall(KSPGetRhs(fetidp->innerksp,&Bl));
1161   PetscCall(KSPGetSolution(fetidp->innerksp,&Xl));
1162   PetscCall(PCBDDCMatFETIDPGetRHS(F,B,Bl));
1163   if (ksp->transpose_solve) {
1164     PetscCall(KSPSolveTranspose(fetidp->innerksp,Bl,Xl));
1165   } else {
1166     PetscCall(KSPSolve(fetidp->innerksp,Bl,Xl));
1167   }
1168   PetscCall(KSPGetConvergedReason(fetidp->innerksp,&reason));
1169   PetscCall(KSPGetPC(fetidp->innerksp,&pc));
1170   PetscCall(PCGetFailedReason(pc,&pcreason));
1171   if ((reason < 0 && reason != KSP_DIVERGED_ITS) || pcreason) {
1172     PetscInt its;
1173     PetscCall(KSPGetIterationNumber(fetidp->innerksp,&its));
1174     ksp->reason = KSP_DIVERGED_PC_FAILED;
1175     PetscCall(VecSetInf(Xl));
1176     PetscCall(PetscInfo(ksp,"Inner KSP solve failed: %s %s at iteration %" PetscInt_FMT,KSPConvergedReasons[reason],PCFailedReasons[pcreason],its));
1177   }
1178   PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,X));
1179   PetscCall(MatGetNullSpace(A,&nsp));
1180   if (nsp) {
1181     PetscCall(MatNullSpaceRemove(nsp,X));
1182   }
1183   /* update ksp with stats from inner ksp */
1184   PetscCall(KSPGetConvergedReason(fetidp->innerksp,&ksp->reason));
1185   PetscCall(KSPGetIterationNumber(fetidp->innerksp,&ksp->its));
1186   ksp->totalits += ksp->its;
1187   PetscCall(KSPGetResidualHistory(fetidp->innerksp,NULL,&hist_len));
1188   ksp->res_hist_len = (size_t) hist_len;
1189   /* restore defaults for inner BDDC (Pre/PostSolve flags) */
1190   pcbddc->temp_solution_used        = PETSC_FALSE;
1191   pcbddc->rhs_change                = PETSC_FALSE;
1192   pcbddc->exact_dirichlet_trick_app = PETSC_FALSE;
1193   PetscFunctionReturn(0);
1194 }
1195 
1196 static PetscErrorCode KSPReset_FETIDP(KSP ksp)
1197 {
1198   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
1199   PC_BDDC        *pcbddc;
1200 
1201   PetscFunctionBegin;
1202   PetscCall(ISDestroy(&fetidp->pP));
1203   PetscCall(VecDestroy(&fetidp->rhs_flip));
1204   /* avoid PCReset that does not take into account ref counting */
1205   PetscCall(PCDestroy(&fetidp->innerbddc));
1206   PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc));
1207   PetscCall(PCSetType(fetidp->innerbddc,PCBDDC));
1208   pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
1209   pcbddc->symmetric_primal = PETSC_FALSE;
1210   PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc));
1211   PetscCall(KSPDestroy(&fetidp->innerksp));
1212   fetidp->saddlepoint  = PETSC_FALSE;
1213   fetidp->matstate     = -1;
1214   fetidp->matnnzstate  = -1;
1215   fetidp->statechanged = PETSC_TRUE;
1216   PetscFunctionReturn(0);
1217 }
1218 
1219 static PetscErrorCode KSPDestroy_FETIDP(KSP ksp)
1220 {
1221   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
1222 
1223   PetscFunctionBegin;
1224   PetscCall(KSPReset_FETIDP(ksp));
1225   PetscCall(PCDestroy(&fetidp->innerbddc));
1226   PetscCall(KSPDestroy(&fetidp->innerksp));
1227   PetscCall(PetscFree(fetidp->monctx));
1228   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",NULL));
1229   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",NULL));
1230   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",NULL));
1231   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",NULL));
1232   PetscCall(PetscFree(ksp->data));
1233   PetscFunctionReturn(0);
1234 }
1235 
1236 static PetscErrorCode KSPView_FETIDP(KSP ksp,PetscViewer viewer)
1237 {
1238   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
1239   PetscBool      iascii;
1240 
1241   PetscFunctionBegin;
1242   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1243   if (iascii) {
1244     PetscCall(PetscViewerASCIIPrintf(viewer,"  fully redundant: %d\n",fetidp->fully_redundant));
1245     PetscCall(PetscViewerASCIIPrintf(viewer,"  saddle point:    %d\n",fetidp->saddlepoint));
1246     PetscCall(PetscViewerASCIIPrintf(viewer,"Inner KSP solver details\n"));
1247   }
1248   PetscCall(PetscViewerASCIIPushTab(viewer));
1249   PetscCall(KSPView(fetidp->innerksp,viewer));
1250   PetscCall(PetscViewerASCIIPopTab(viewer));
1251   if (iascii) {
1252     PetscCall(PetscViewerASCIIPrintf(viewer,"Inner BDDC solver details\n"));
1253   }
1254   PetscCall(PetscViewerASCIIPushTab(viewer));
1255   PetscCall(PCView(fetidp->innerbddc,viewer));
1256   PetscCall(PetscViewerASCIIPopTab(viewer));
1257   PetscFunctionReturn(0);
1258 }
1259 
1260 static PetscErrorCode KSPSetFromOptions_FETIDP(PetscOptionItems *PetscOptionsObject,KSP ksp)
1261 {
1262   KSP_FETIDP     *fetidp = (KSP_FETIDP*)ksp->data;
1263 
1264   PetscFunctionBegin;
1265   /* set options prefixes for the inner objects, since the parent prefix will be valid at this point */
1266   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerksp,((PetscObject)ksp)->prefix));
1267   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerksp,"fetidp_"));
1268   if (!fetidp->userbddc) {
1269     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerbddc,((PetscObject)ksp)->prefix));
1270     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerbddc,"fetidp_bddc_"));
1271   }
1272   PetscOptionsHeadBegin(PetscOptionsObject,"KSP FETIDP options");
1273   PetscCall(PetscOptionsBool("-ksp_fetidp_fullyredundant","Use fully redundant multipliers","none",fetidp->fully_redundant,&fetidp->fully_redundant,NULL));
1274   PetscCall(PetscOptionsBool("-ksp_fetidp_saddlepoint","Activates support for saddle-point problems",NULL,fetidp->saddlepoint,&fetidp->saddlepoint,NULL));
1275   PetscCall(PetscOptionsBool("-ksp_fetidp_check","Activates verbose debugging output FETI-DP operators",NULL,fetidp->check,&fetidp->check,NULL));
1276   PetscOptionsHeadEnd();
1277   PetscCall(PCSetFromOptions(fetidp->innerbddc));
1278   PetscFunctionReturn(0);
1279 }
1280 
1281 /*MC
1282      KSPFETIDP - The FETI-DP method
1283 
1284    This class implements the FETI-DP method [1].
1285    The matrix for the KSP must be of type MATIS.
1286    The FETI-DP linear system (automatically generated constructing an internal PCBDDC object) is solved using an internal KSP object.
1287 
1288    Options Database Keys:
1289 +   -ksp_fetidp_fullyredundant <false>   - use a fully redundant set of Lagrange multipliers
1290 .   -ksp_fetidp_saddlepoint <false>      - activates support for saddle point problems, see [2]
1291 .   -ksp_fetidp_saddlepoint_flip <false> - usually, an incompressible Stokes problem is written as
1292                                            | A B^T | | v | = | f |
1293                                            | B 0   | | p | = | g |
1294                                            with B representing -\int_\Omega \nabla \cdot u q.
1295                                            If -ksp_fetidp_saddlepoint_flip is true, the code assumes that the user provides it as
1296                                            | A B^T | | v | = | f |
1297                                            |-B 0   | | p | = |-g |
1298 .   -ksp_fetidp_pressure_field <-1>      - activates support for saddle point problems, and identifies the pressure field id.
1299                                            If this information is not provided, the pressure field is detected by using MatFindZeroDiagonals().
1300 -   -ksp_fetidp_pressure_all <false>     - if false, uses the interface pressures, as described in [2]. If true, uses the entire pressure field.
1301 
1302    Level: Advanced
1303 
1304    Notes:
1305     Options for the inner KSP and for the customization of the PCBDDC object can be specified at command line by using the prefixes -fetidp_ and -fetidp_bddc_. E.g.,
1306 .vb
1307       -fetidp_ksp_type gmres -fetidp_bddc_pc_bddc_symmetric false
1308 .ve
1309    will use GMRES for the solution of the linear system on the Lagrange multipliers, generated using a non-symmetric PCBDDC.
1310 
1311    For saddle point problems with continuous pressures, the preconditioned operator for the pressure solver can be specified with KSPFETIDPSetPressureOperator().
1312    Alternatively, the pressure operator is extracted from the precondioned matrix (if it is different from the linear solver matrix).
1313    If none of the above, an identity matrix will be created; the user then needs to scale it through a Richardson solver.
1314    Options for the pressure solver can be prefixed with -fetidp_fielsplit_p_, E.g.
1315 .vb
1316       -fetidp_fielsplit_p_ksp_type preonly -fetidp_fielsplit_p_pc_type lu -fetidp_fielsplit_p_pc_factor_mat_solver_type mumps
1317 .ve
1318    In order to use the deluxe version of FETI-DP, you must customize the inner BDDC operator with -fetidp_bddc_pc_bddc_use_deluxe_scaling -fetidp_bddc_pc_bddc_deluxe_singlemat and use
1319    non-redundant multipliers, i.e. -ksp_fetidp_fullyredundant false. Options for the scaling solver are prefixed by -fetidp_bddelta_, E.g.
1320 .vb
1321       -fetidp_bddelta_pc_factor_mat_solver_type mumps -fetidp_bddelta_pc_type lu
1322 .ve
1323 
1324    Some of the basic options such as the maximum number of iterations and tolerances are automatically passed from this KSP to the inner KSP that actually performs the iterations.
1325 
1326    The converged reason and number of iterations computed are passed from the inner KSP to this KSP at the end of the solution.
1327 
1328    Developer Notes:
1329     Even though this method does not directly use any norms, the user is allowed to set the KSPNormType to any value.
1330     This is so users do not have to change KSPNormType options when they switch from other KSP methods to this one.
1331 
1332    References:
1333 +  * - C. Farhat, M. Lesoinne, P. LeTallec, K. Pierson, and D. Rixen, FETI-DP: a dual-primal unified FETI method. I. A faster alternative to the two-level FETI method, Internat. J. Numer. Methods Engrg., 50 (2001), pp. 1523--1544
1334 -  * - X. Tu, J. Li, A FETI-DP type domain decomposition algorithm for three-dimensional incompressible Stokes equations, SIAM J. Numer. Anal., 53 (2015), pp. 720-742
1335 
1336 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC()`, `KSPFETIDPGetInnerBDDC()`, `KSPFETIDPGetInnerKSP()`
1337 M*/
1338 PETSC_EXTERN PetscErrorCode KSPCreate_FETIDP(KSP ksp)
1339 {
1340   KSP_FETIDP     *fetidp;
1341   KSP_FETIDPMon  *monctx;
1342   PC_BDDC        *pcbddc;
1343   PC             pc;
1344 
1345   PetscFunctionBegin;
1346   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,3));
1347   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_RIGHT,2));
1348   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2));
1349   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_RIGHT,2));
1350   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,2));
1351   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_RIGHT,2));
1352   PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,2));
1353 
1354   PetscCall(PetscNewLog(ksp,&fetidp));
1355   fetidp->matstate     = -1;
1356   fetidp->matnnzstate  = -1;
1357   fetidp->statechanged = PETSC_TRUE;
1358 
1359   ksp->data = (void*)fetidp;
1360   ksp->ops->setup                        = KSPSetUp_FETIDP;
1361   ksp->ops->solve                        = KSPSolve_FETIDP;
1362   ksp->ops->destroy                      = KSPDestroy_FETIDP;
1363   ksp->ops->computeeigenvalues           = KSPComputeEigenvalues_FETIDP;
1364   ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_FETIDP;
1365   ksp->ops->view                         = KSPView_FETIDP;
1366   ksp->ops->setfromoptions               = KSPSetFromOptions_FETIDP;
1367   ksp->ops->buildsolution                = KSPBuildSolution_FETIDP;
1368   ksp->ops->buildresidual                = KSPBuildResidualDefault;
1369   PetscCall(KSPGetPC(ksp,&pc));
1370   PetscCall(PCSetType(pc,PCNONE));
1371   /* create the inner KSP for the Lagrange multipliers */
1372   PetscCall(KSPCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerksp));
1373   PetscCall(KSPGetPC(fetidp->innerksp,&pc));
1374   PetscCall(PCSetType(pc,PCNONE));
1375   PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerksp));
1376   /* monitor */
1377   PetscCall(PetscNew(&monctx));
1378   monctx->parentksp = ksp;
1379   fetidp->monctx = monctx;
1380   PetscCall(KSPMonitorSet(fetidp->innerksp,KSPMonitor_FETIDP,fetidp->monctx,NULL));
1381   /* create the inner BDDC */
1382   PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc));
1383   PetscCall(PCSetType(fetidp->innerbddc,PCBDDC));
1384   /* make sure we always obtain a consistent FETI-DP matrix
1385      for symmetric problems, the user can always customize it through the command line */
1386   pcbddc = (PC_BDDC*)fetidp->innerbddc->data;
1387   pcbddc->symmetric_primal = PETSC_FALSE;
1388   PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc));
1389   /* composed functions */
1390   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",KSPFETIDPSetInnerBDDC_FETIDP));
1391   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",KSPFETIDPGetInnerBDDC_FETIDP));
1392   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",KSPFETIDPGetInnerKSP_FETIDP));
1393   PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",KSPFETIDPSetPressureOperator_FETIDP));
1394   /* need to call KSPSetUp_FETIDP even with KSP_SETUP_NEWMATRIX */
1395   ksp->setupnewmatrix = PETSC_TRUE;
1396   PetscFunctionReturn(0);
1397 }
1398