xref: /petsc/src/ksp/pc/impls/bddc/bddc.c (revision 7c8652dd9fb051dfaf30896d504f41ba028df3ea)
1 /* TODOLIST
2 
3    ConstraintsSetup
4    - tolerances for constraints as an option (take care of single precision!)
5    - Can MAT_IGNORE_ZERO_ENTRIES be used for Constraints Matrix?
6 
7    Solvers
8    - Add support for reuse fill and cholecky factor for coarse solver (similar to local solvers)
9    - Propagate ksp prefixes for solvers to mat objects?
10    - Propagate nearnullspace info among levels
11 
12    User interface
13    - Change SetNeumannBoundaries to SetNeumannBoundariesLocal and provide new SetNeumannBoundaries (same Dirichlet)
14    - Negative indices in dirichlet and Neumann ISs should be skipped (now they cause out-of-bounds access)
15    - Provide PCApplyTranpose_BDDC
16    - DofSplitting and DM attached to pc?
17 
18    Debugging output
19    - Better management of verbosity levels of debugging output
20 
21    Build
22    - make runexe59
23 
24    Extra
25    - Is it possible to work with PCBDDCGraph on boundary indices only (less memory consumed)?
26    - Why options for "pc_bddc_coarse" solver gets propagated to "pc_bddc_coarse_1" solver?
27    - add support for computing h,H and related using coordinates?
28    - Change of basis approach does not work with my nonlinear mechanics example. why? (seems not an issue with l2gmap)
29    - Better management in PCIS code
30    - BDDC with MG framework?
31 
32    FETIDP
33    - Move FETIDP code to its own classes
34 
35    MATIS related operations contained in BDDC code
36    - Provide general case for subassembling
37    - Preallocation routines in MatISGetMPIAXAIJ
38 
39 */
40 
41 /* ----------------------------------------------------------------------------------------------------------------------------------------------
42    Implementation of BDDC preconditioner based on:
43    C. Dohrmann "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149-168, March 2007
44    ---------------------------------------------------------------------------------------------------------------------------------------------- */
45 
46 #include "bddc.h" /*I "petscpc.h" I*/  /* includes for fortran wrappers */
47 #include "bddcprivate.h"
48 #include <petscblaslapack.h>
49 
50 /* -------------------------------------------------------------------------- */
51 #undef __FUNCT__
52 #define __FUNCT__ "PCSetFromOptions_BDDC"
53 PetscErrorCode PCSetFromOptions_BDDC(PC pc)
54 {
55   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
56   PetscErrorCode ierr;
57 
58   PetscFunctionBegin;
59   ierr = PetscOptionsHead("BDDC options");CHKERRQ(ierr);
60   /* Verbose debugging */
61   ierr = PetscOptionsInt("-pc_bddc_check_level","Verbose output for PCBDDC (intended for debug)","none",pcbddc->dbg_flag,&pcbddc->dbg_flag,NULL);CHKERRQ(ierr);
62   /* Primal space cumstomization */
63   ierr = PetscOptionsBool("-pc_bddc_use_vertices","Use or not corner dofs in coarse space","none",pcbddc->use_vertices,&pcbddc->use_vertices,NULL);CHKERRQ(ierr);
64   ierr = PetscOptionsBool("-pc_bddc_use_edges","Use or not edge constraints in coarse space","none",pcbddc->use_edges,&pcbddc->use_edges,NULL);CHKERRQ(ierr);
65   ierr = PetscOptionsBool("-pc_bddc_use_faces","Use or not face constraints in coarse space","none",pcbddc->use_faces,&pcbddc->use_faces,NULL);CHKERRQ(ierr);
66   /* Change of basis */
67   ierr = PetscOptionsBool("-pc_bddc_use_change_of_basis","Use or not change of basis on local edge nodes","none",pcbddc->use_change_of_basis,&pcbddc->use_change_of_basis,NULL);CHKERRQ(ierr);
68   ierr = PetscOptionsBool("-pc_bddc_use_change_on_faces","Use or not change of basis on local face nodes","none",pcbddc->use_change_on_faces,&pcbddc->use_change_on_faces,NULL);CHKERRQ(ierr);
69   if (!pcbddc->use_change_of_basis) {
70     pcbddc->use_change_on_faces = PETSC_FALSE;
71   }
72   /* Switch between M_2 (default) and M_3 preconditioners (as defined by C. Dohrmann in the ref. article) */
73   ierr = PetscOptionsBool("-pc_bddc_switch_static","Switch on static condensation ops around the interface preconditioner","none",pcbddc->switch_static,&pcbddc->switch_static,NULL);CHKERRQ(ierr);
74   ierr = PetscOptionsInt("-pc_bddc_coarsening_ratio","Set coarsening ratio used in multilevel coarsening","none",pcbddc->coarsening_ratio,&pcbddc->coarsening_ratio,NULL);CHKERRQ(ierr);
75   ierr = PetscOptionsInt("-pc_bddc_levels","Set maximum number of levels for multilevel","none",pcbddc->max_levels,&pcbddc->max_levels,NULL);CHKERRQ(ierr);
76   ierr = PetscOptionsBool("-pc_bddc_use_deluxe_scaling","Use deluxe scaling for BDDC","none",pcbddc->use_deluxe_scaling,&pcbddc->use_deluxe_scaling,NULL);CHKERRQ(ierr);
77   ierr = PetscOptionsTail();CHKERRQ(ierr);
78   PetscFunctionReturn(0);
79 }
80 /* -------------------------------------------------------------------------- */
81 #undef __FUNCT__
82 #define __FUNCT__ "PCBDDCSetPrimalVerticesLocalIS_BDDC"
83 static PetscErrorCode PCBDDCSetPrimalVerticesLocalIS_BDDC(PC pc, IS PrimalVertices)
84 {
85   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
86   PetscErrorCode ierr;
87 
88   PetscFunctionBegin;
89   ierr = ISDestroy(&pcbddc->user_primal_vertices);CHKERRQ(ierr);
90   ierr = PetscObjectReference((PetscObject)PrimalVertices);CHKERRQ(ierr);
91   pcbddc->user_primal_vertices = PrimalVertices;
92   PetscFunctionReturn(0);
93 }
94 #undef __FUNCT__
95 #define __FUNCT__ "PCBDDCSetPrimalVerticesLocalIS"
96 /*@
97  PCBDDCSetPrimalVerticesLocalIS - Set additional user defined primal vertices in PCBDDC
98 
99    Not collective
100 
101    Input Parameters:
102 +  pc - the preconditioning context
103 -  PrimalVertices - index set of primal vertices in local numbering
104 
105    Level: intermediate
106 
107    Notes:
108 
109 .seealso: PCBDDC
110 @*/
111 PetscErrorCode PCBDDCSetPrimalVerticesLocalIS(PC pc, IS PrimalVertices)
112 {
113   PetscErrorCode ierr;
114 
115   PetscFunctionBegin;
116   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
117   PetscValidHeaderSpecific(PrimalVertices,IS_CLASSID,2);
118   ierr = PetscTryMethod(pc,"PCBDDCSetPrimalVerticesLocalIS_C",(PC,IS),(pc,PrimalVertices));CHKERRQ(ierr);
119   PetscFunctionReturn(0);
120 }
121 /* -------------------------------------------------------------------------- */
122 #undef __FUNCT__
123 #define __FUNCT__ "PCBDDCSetCoarseningRatio_BDDC"
124 static PetscErrorCode PCBDDCSetCoarseningRatio_BDDC(PC pc,PetscInt k)
125 {
126   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
127 
128   PetscFunctionBegin;
129   pcbddc->coarsening_ratio = k;
130   PetscFunctionReturn(0);
131 }
132 
133 #undef __FUNCT__
134 #define __FUNCT__ "PCBDDCSetCoarseningRatio"
135 /*@
136  PCBDDCSetCoarseningRatio - Set coarsening ratio used in multilevel
137 
138    Logically collective on PC
139 
140    Input Parameters:
141 +  pc - the preconditioning context
142 -  k - coarsening ratio (H/h at the coarser level)
143 
144    Approximatively k subdomains at the finer level will be aggregated into a single subdomain at the coarser level
145 
146    Level: intermediate
147 
148    Notes:
149 
150 .seealso: PCBDDC
151 @*/
152 PetscErrorCode PCBDDCSetCoarseningRatio(PC pc,PetscInt k)
153 {
154   PetscErrorCode ierr;
155 
156   PetscFunctionBegin;
157   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
158   PetscValidLogicalCollectiveInt(pc,k,2);
159   ierr = PetscTryMethod(pc,"PCBDDCSetCoarseningRatio_C",(PC,PetscInt),(pc,k));CHKERRQ(ierr);
160   PetscFunctionReturn(0);
161 }
162 
163 /* The following functions (PCBDDCSetUseExactDirichlet PCBDDCSetLevel) are not public */
164 #undef __FUNCT__
165 #define __FUNCT__ "PCBDDCSetUseExactDirichlet_BDDC"
166 static PetscErrorCode PCBDDCSetUseExactDirichlet_BDDC(PC pc,PetscBool flg)
167 {
168   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
169 
170   PetscFunctionBegin;
171   pcbddc->use_exact_dirichlet_trick = flg;
172   PetscFunctionReturn(0);
173 }
174 
175 #undef __FUNCT__
176 #define __FUNCT__ "PCBDDCSetUseExactDirichlet"
177 PetscErrorCode PCBDDCSetUseExactDirichlet(PC pc,PetscBool flg)
178 {
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
183   PetscValidLogicalCollectiveBool(pc,flg,2);
184   ierr = PetscTryMethod(pc,"PCBDDCSetUseExactDirichlet_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr);
185   PetscFunctionReturn(0);
186 }
187 
188 #undef __FUNCT__
189 #define __FUNCT__ "PCBDDCSetLevel_BDDC"
190 static PetscErrorCode PCBDDCSetLevel_BDDC(PC pc,PetscInt level)
191 {
192   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
193 
194   PetscFunctionBegin;
195   pcbddc->current_level = level;
196   PetscFunctionReturn(0);
197 }
198 
199 #undef __FUNCT__
200 #define __FUNCT__ "PCBDDCSetLevel"
201 PetscErrorCode PCBDDCSetLevel(PC pc,PetscInt level)
202 {
203   PetscErrorCode ierr;
204 
205   PetscFunctionBegin;
206   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
207   PetscValidLogicalCollectiveInt(pc,level,2);
208   ierr = PetscTryMethod(pc,"PCBDDCSetLevel_C",(PC,PetscInt),(pc,level));CHKERRQ(ierr);
209   PetscFunctionReturn(0);
210 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "PCBDDCSetLevels_BDDC"
214 static PetscErrorCode PCBDDCSetLevels_BDDC(PC pc,PetscInt levels)
215 {
216   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
217 
218   PetscFunctionBegin;
219   pcbddc->max_levels = levels;
220   PetscFunctionReturn(0);
221 }
222 
223 #undef __FUNCT__
224 #define __FUNCT__ "PCBDDCSetLevels"
225 /*@
226  PCBDDCSetLevels - Sets the maximum number of levels for multilevel
227 
228    Logically collective on PC
229 
230    Input Parameters:
231 +  pc - the preconditioning context
232 -  levels - the maximum number of levels (max 9)
233 
234    Default value is 0, i.e. traditional one-level BDDC
235 
236    Level: intermediate
237 
238    Notes:
239 
240 .seealso: PCBDDC
241 @*/
242 PetscErrorCode PCBDDCSetLevels(PC pc,PetscInt levels)
243 {
244   PetscErrorCode ierr;
245 
246   PetscFunctionBegin;
247   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
248   PetscValidLogicalCollectiveInt(pc,levels,2);
249   ierr = PetscTryMethod(pc,"PCBDDCSetLevels_C",(PC,PetscInt),(pc,levels));CHKERRQ(ierr);
250   PetscFunctionReturn(0);
251 }
252 /* -------------------------------------------------------------------------- */
253 
254 #undef __FUNCT__
255 #define __FUNCT__ "PCBDDCSetNullSpace_BDDC"
256 static PetscErrorCode PCBDDCSetNullSpace_BDDC(PC pc,MatNullSpace NullSpace)
257 {
258   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
259   PetscErrorCode ierr;
260 
261   PetscFunctionBegin;
262   ierr = PetscObjectReference((PetscObject)NullSpace);CHKERRQ(ierr);
263   ierr = MatNullSpaceDestroy(&pcbddc->NullSpace);CHKERRQ(ierr);
264   pcbddc->NullSpace = NullSpace;
265   PetscFunctionReturn(0);
266 }
267 
268 #undef __FUNCT__
269 #define __FUNCT__ "PCBDDCSetNullSpace"
270 /*@
271  PCBDDCSetNullSpace - Set nullspace for BDDC operator
272 
273    Logically collective on PC and MatNullSpace
274 
275    Input Parameters:
276 +  pc - the preconditioning context
277 -  NullSpace - Null space of the linear operator to be preconditioned (Pmat)
278 
279    Level: intermediate
280 
281    Notes:
282 
283 .seealso: PCBDDC
284 @*/
285 PetscErrorCode PCBDDCSetNullSpace(PC pc,MatNullSpace NullSpace)
286 {
287   PetscErrorCode ierr;
288 
289   PetscFunctionBegin;
290   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
291   PetscValidHeaderSpecific(NullSpace,MAT_NULLSPACE_CLASSID,2);
292   PetscCheckSameComm(pc,1,NullSpace,2);
293   ierr = PetscTryMethod(pc,"PCBDDCSetNullSpace_C",(PC,MatNullSpace),(pc,NullSpace));CHKERRQ(ierr);
294   PetscFunctionReturn(0);
295 }
296 /* -------------------------------------------------------------------------- */
297 
298 #undef __FUNCT__
299 #define __FUNCT__ "PCBDDCSetDirichletBoundaries_BDDC"
300 static PetscErrorCode PCBDDCSetDirichletBoundaries_BDDC(PC pc,IS DirichletBoundaries)
301 {
302   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   ierr = ISDestroy(&pcbddc->DirichletBoundaries);CHKERRQ(ierr);
307   ierr = PetscObjectReference((PetscObject)DirichletBoundaries);CHKERRQ(ierr);
308   pcbddc->DirichletBoundaries=DirichletBoundaries;
309   pcbddc->recompute_topography = PETSC_TRUE;
310   PetscFunctionReturn(0);
311 }
312 
313 #undef __FUNCT__
314 #define __FUNCT__ "PCBDDCSetDirichletBoundaries"
315 /*@
316  PCBDDCSetDirichletBoundaries - Set IS defining Dirichlet boundaries for the global problem.
317 
318    Not collective
319 
320    Input Parameters:
321 +  pc - the preconditioning context
322 -  DirichletBoundaries - sequential IS defining the subdomain part of Dirichlet boundaries (in local ordering)
323 
324    Level: intermediate
325 
326    Notes:
327 
328 .seealso: PCBDDC
329 @*/
330 PetscErrorCode PCBDDCSetDirichletBoundaries(PC pc,IS DirichletBoundaries)
331 {
332   PetscErrorCode ierr;
333 
334   PetscFunctionBegin;
335   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
336   PetscValidHeaderSpecific(DirichletBoundaries,IS_CLASSID,2);
337   ierr = PetscTryMethod(pc,"PCBDDCSetDirichletBoundaries_C",(PC,IS),(pc,DirichletBoundaries));CHKERRQ(ierr);
338   PetscFunctionReturn(0);
339 }
340 /* -------------------------------------------------------------------------- */
341 
342 #undef __FUNCT__
343 #define __FUNCT__ "PCBDDCSetNeumannBoundaries_BDDC"
344 static PetscErrorCode PCBDDCSetNeumannBoundaries_BDDC(PC pc,IS NeumannBoundaries)
345 {
346   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
347   PetscErrorCode ierr;
348 
349   PetscFunctionBegin;
350   ierr = ISDestroy(&pcbddc->NeumannBoundaries);CHKERRQ(ierr);
351   ierr = PetscObjectReference((PetscObject)NeumannBoundaries);CHKERRQ(ierr);
352   pcbddc->NeumannBoundaries=NeumannBoundaries;
353   pcbddc->recompute_topography = PETSC_TRUE;
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "PCBDDCSetNeumannBoundaries"
359 /*@
360  PCBDDCSetNeumannBoundaries - Set IS defining Neumann boundaries for the global problem.
361 
362    Not collective
363 
364    Input Parameters:
365 +  pc - the preconditioning context
366 -  NeumannBoundaries - sequential IS defining the subdomain part of Neumann boundaries (in local ordering)
367 
368    Level: intermediate
369 
370    Notes:
371 
372 .seealso: PCBDDC
373 @*/
374 PetscErrorCode PCBDDCSetNeumannBoundaries(PC pc,IS NeumannBoundaries)
375 {
376   PetscErrorCode ierr;
377 
378   PetscFunctionBegin;
379   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
380   PetscValidHeaderSpecific(NeumannBoundaries,IS_CLASSID,2);
381   ierr = PetscTryMethod(pc,"PCBDDCSetNeumannBoundaries_C",(PC,IS),(pc,NeumannBoundaries));CHKERRQ(ierr);
382   PetscFunctionReturn(0);
383 }
384 /* -------------------------------------------------------------------------- */
385 
386 #undef __FUNCT__
387 #define __FUNCT__ "PCBDDCGetDirichletBoundaries_BDDC"
388 static PetscErrorCode PCBDDCGetDirichletBoundaries_BDDC(PC pc,IS *DirichletBoundaries)
389 {
390   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
391 
392   PetscFunctionBegin;
393   *DirichletBoundaries = pcbddc->DirichletBoundaries;
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "PCBDDCGetDirichletBoundaries"
399 /*@
400  PCBDDCGetDirichletBoundaries - Get IS for local Dirichlet boundaries
401 
402    Not collective
403 
404    Input Parameters:
405 .  pc - the preconditioning context
406 
407    Output Parameters:
408 .  DirichletBoundaries - index set defining the subdomain part of Dirichlet boundaries
409 
410    Level: intermediate
411 
412    Notes:
413 
414 .seealso: PCBDDC
415 @*/
416 PetscErrorCode PCBDDCGetDirichletBoundaries(PC pc,IS *DirichletBoundaries)
417 {
418   PetscErrorCode ierr;
419 
420   PetscFunctionBegin;
421   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
422   ierr = PetscUseMethod(pc,"PCBDDCGetDirichletBoundaries_C",(PC,IS*),(pc,DirichletBoundaries));CHKERRQ(ierr);
423   PetscFunctionReturn(0);
424 }
425 /* -------------------------------------------------------------------------- */
426 
427 #undef __FUNCT__
428 #define __FUNCT__ "PCBDDCGetNeumannBoundaries_BDDC"
429 static PetscErrorCode PCBDDCGetNeumannBoundaries_BDDC(PC pc,IS *NeumannBoundaries)
430 {
431   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
432 
433   PetscFunctionBegin;
434   *NeumannBoundaries = pcbddc->NeumannBoundaries;
435   PetscFunctionReturn(0);
436 }
437 
438 #undef __FUNCT__
439 #define __FUNCT__ "PCBDDCGetNeumannBoundaries"
440 /*@
441  PCBDDCGetNeumannBoundaries - Get IS for local Neumann boundaries
442 
443    Not collective
444 
445    Input Parameters:
446 .  pc - the preconditioning context
447 
448    Output Parameters:
449 .  NeumannBoundaries - index set defining the subdomain part of Neumann boundaries
450 
451    Level: intermediate
452 
453    Notes:
454 
455 .seealso: PCBDDC
456 @*/
457 PetscErrorCode PCBDDCGetNeumannBoundaries(PC pc,IS *NeumannBoundaries)
458 {
459   PetscErrorCode ierr;
460 
461   PetscFunctionBegin;
462   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
463   ierr = PetscUseMethod(pc,"PCBDDCGetNeumannBoundaries_C",(PC,IS*),(pc,NeumannBoundaries));CHKERRQ(ierr);
464   PetscFunctionReturn(0);
465 }
466 /* -------------------------------------------------------------------------- */
467 
468 #undef __FUNCT__
469 #define __FUNCT__ "PCBDDCSetLocalAdjacencyGraph_BDDC"
470 static PetscErrorCode PCBDDCSetLocalAdjacencyGraph_BDDC(PC pc, PetscInt nvtxs,const PetscInt xadj[],const PetscInt adjncy[], PetscCopyMode copymode)
471 {
472   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
473   PCBDDCGraph    mat_graph = pcbddc->mat_graph;
474   PetscErrorCode ierr;
475 
476   PetscFunctionBegin;
477   /* free old CSR */
478   ierr = PCBDDCGraphResetCSR(mat_graph);CHKERRQ(ierr);
479   /* TODO: PCBDDCGraphSetAdjacency */
480   /* get CSR into graph structure */
481   if (copymode == PETSC_COPY_VALUES) {
482     ierr = PetscMalloc1((nvtxs+1),&mat_graph->xadj);CHKERRQ(ierr);
483     ierr = PetscMalloc1(xadj[nvtxs],&mat_graph->adjncy);CHKERRQ(ierr);
484     ierr = PetscMemcpy(mat_graph->xadj,xadj,(nvtxs+1)*sizeof(PetscInt));CHKERRQ(ierr);
485     ierr = PetscMemcpy(mat_graph->adjncy,adjncy,xadj[nvtxs]*sizeof(PetscInt));CHKERRQ(ierr);
486   } else if (copymode == PETSC_OWN_POINTER) {
487     mat_graph->xadj = (PetscInt*)xadj;
488     mat_graph->adjncy = (PetscInt*)adjncy;
489   }
490   mat_graph->nvtxs_csr = nvtxs;
491   PetscFunctionReturn(0);
492 }
493 
494 #undef __FUNCT__
495 #define __FUNCT__ "PCBDDCSetLocalAdjacencyGraph"
496 /*@
497  PCBDDCSetLocalAdjacencyGraph - Set adjacency structure (CSR graph) of the local Neumann matrix
498 
499    Not collective
500 
501    Input Parameters:
502 +  pc - the preconditioning context
503 .  nvtxs - number of local vertices of the graph (i.e., the local size of your problem)
504 .  xadj, adjncy - the CSR graph
505 -  copymode - either PETSC_COPY_VALUES or PETSC_OWN_POINTER.
506 
507    Level: intermediate
508 
509    Notes:
510 
511 .seealso: PCBDDC,PetscCopyMode
512 @*/
513 PetscErrorCode PCBDDCSetLocalAdjacencyGraph(PC pc,PetscInt nvtxs,const PetscInt xadj[],const PetscInt adjncy[], PetscCopyMode copymode)
514 {
515   void (*f)(void) = 0;
516   PetscErrorCode ierr;
517 
518   PetscFunctionBegin;
519   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
520   PetscValidIntPointer(xadj,3);
521   PetscValidIntPointer(xadj,4);
522   if (copymode != PETSC_COPY_VALUES && copymode != PETSC_OWN_POINTER) {
523     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported copy mode %d in %s\n",copymode,__FUNCT__);
524   }
525   ierr = PetscTryMethod(pc,"PCBDDCSetLocalAdjacencyGraph_C",(PC,PetscInt,const PetscInt[],const PetscInt[],PetscCopyMode),(pc,nvtxs,xadj,adjncy,copymode));CHKERRQ(ierr);
526   /* free arrays if PCBDDC is not the PC type */
527   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",&f);CHKERRQ(ierr);
528   if (!f && copymode == PETSC_OWN_POINTER) {
529     ierr = PetscFree(xadj);CHKERRQ(ierr);
530     ierr = PetscFree(adjncy);CHKERRQ(ierr);
531   }
532   PetscFunctionReturn(0);
533 }
534 /* -------------------------------------------------------------------------- */
535 
536 #undef __FUNCT__
537 #define __FUNCT__ "PCBDDCSetDofsSplitting_BDDC"
538 static PetscErrorCode PCBDDCSetDofsSplitting_BDDC(PC pc,PetscInt n_is, IS ISForDofs[])
539 {
540   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
541   PetscInt i;
542   PetscErrorCode ierr;
543 
544   PetscFunctionBegin;
545   /* Destroy ISes if they were already set */
546   for (i=0;i<pcbddc->n_ISForDofs;i++) {
547     ierr = ISDestroy(&pcbddc->ISForDofs[i]);CHKERRQ(ierr);
548   }
549   ierr = PetscFree(pcbddc->ISForDofs);CHKERRQ(ierr);
550   /* allocate space then set */
551   ierr = PetscMalloc1(n_is,&pcbddc->ISForDofs);CHKERRQ(ierr);
552   for (i=0;i<n_is;i++) {
553     ierr = PetscObjectReference((PetscObject)ISForDofs[i]);CHKERRQ(ierr);
554     pcbddc->ISForDofs[i]=ISForDofs[i];
555   }
556   pcbddc->n_ISForDofs=n_is;
557   pcbddc->user_provided_isfordofs = PETSC_TRUE;
558   PetscFunctionReturn(0);
559 }
560 
561 #undef __FUNCT__
562 #define __FUNCT__ "PCBDDCSetDofsSplitting"
563 /*@
564  PCBDDCSetDofsSplitting - Set index sets defining fields of the local Neumann matrix
565 
566    Not collective
567 
568    Input Parameters:
569 +  pc - the preconditioning context
570 -  n_is - number of index sets defining the fields
571 .  ISForDofs - array of IS describing the fields
572 
573    Level: intermediate
574 
575    Notes:
576 
577 .seealso: PCBDDC
578 @*/
579 PetscErrorCode PCBDDCSetDofsSplitting(PC pc,PetscInt n_is, IS ISForDofs[])
580 {
581   PetscInt       i;
582   PetscErrorCode ierr;
583 
584   PetscFunctionBegin;
585   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
586   for (i=0;i<n_is;i++) {
587     PetscValidHeaderSpecific(ISForDofs[i],IS_CLASSID,2);
588   }
589   ierr = PetscTryMethod(pc,"PCBDDCSetDofsSplitting_C",(PC,PetscInt,IS[]),(pc,n_is,ISForDofs));CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 }
592 /* -------------------------------------------------------------------------- */
593 #undef __FUNCT__
594 #define __FUNCT__ "PCPreSolve_BDDC"
595 /* -------------------------------------------------------------------------- */
596 /*
597    PCPreSolve_BDDC - Changes the right hand side and (if necessary) the initial
598                      guess if a transformation of basis approach has been selected.
599 
600    Input Parameter:
601 +  pc - the preconditioner contex
602 
603    Application Interface Routine: PCPreSolve()
604 
605    Notes:
606    The interface routine PCPreSolve() is not usually called directly by
607    the user, but instead is called by KSPSolve().
608 */
609 static PetscErrorCode PCPreSolve_BDDC(PC pc, KSP ksp, Vec rhs, Vec x)
610 {
611   PetscErrorCode ierr;
612   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
613   PC_IS          *pcis = (PC_IS*)(pc->data);
614   Mat_IS         *matis = (Mat_IS*)pc->pmat->data;
615   Mat            temp_mat;
616   IS             dirIS;
617   PetscInt       dirsize,i,*is_indices;
618   PetscScalar    *array_x,*array_diagonal;
619   Vec            used_vec;
620   PetscBool      guess_nonzero,flg,bddc_has_dirichlet_boundaries;
621 
622   PetscFunctionBegin;
623   /* if we are working with cg, one dirichlet solve can be avoided during Krylov iterations */
624   if (ksp) {
625     PetscBool iscg;
626     ierr = PetscObjectTypeCompare((PetscObject)ksp,KSPCG,&iscg);CHKERRQ(ierr);
627     if (!iscg) {
628       ierr = PCBDDCSetUseExactDirichlet(pc,PETSC_FALSE);CHKERRQ(ierr);
629     }
630   }
631   /* Creates parallel work vectors used in presolve */
632   if (!pcbddc->original_rhs) {
633     ierr = VecDuplicate(pcis->vec1_global,&pcbddc->original_rhs);CHKERRQ(ierr);
634   }
635   if (!pcbddc->temp_solution) {
636     ierr = VecDuplicate(pcis->vec1_global,&pcbddc->temp_solution);CHKERRQ(ierr);
637   }
638   if (x) {
639     ierr = PetscObjectReference((PetscObject)x);CHKERRQ(ierr);
640     used_vec = x;
641   } else {
642     ierr = PetscObjectReference((PetscObject)pcbddc->temp_solution);CHKERRQ(ierr);
643     used_vec = pcbddc->temp_solution;
644     ierr = VecSet(used_vec,0.0);CHKERRQ(ierr);
645   }
646   /* hack into ksp data structure PCPreSolve comes earlier in src/ksp/ksp/interface/itfunc.c */
647   if (ksp) {
648     ierr = KSPGetInitialGuessNonzero(ksp,&guess_nonzero);CHKERRQ(ierr);
649     if (!guess_nonzero) {
650       ierr = VecSet(used_vec,0.0);CHKERRQ(ierr);
651     }
652   }
653 
654   /* TODO: remove when Dirichlet boundaries will be shared */
655   ierr = PCBDDCGetDirichletBoundaries(pc,&dirIS);CHKERRQ(ierr);
656   flg = PETSC_FALSE;
657   if (dirIS) flg = PETSC_TRUE;
658   ierr = MPI_Allreduce(&flg,&bddc_has_dirichlet_boundaries,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc));CHKERRQ(ierr);
659 
660   /* store the original rhs */
661   ierr = VecCopy(rhs,pcbddc->original_rhs);CHKERRQ(ierr);
662 
663   /* Take into account zeroed rows -> change rhs and store solution removed */
664   if (rhs && bddc_has_dirichlet_boundaries) {
665     ierr = MatGetDiagonal(pc->pmat,pcis->vec1_global);CHKERRQ(ierr);
666     ierr = VecPointwiseDivide(pcis->vec1_global,rhs,pcis->vec1_global);CHKERRQ(ierr);
667     ierr = VecScatterBegin(matis->ctx,pcis->vec1_global,pcis->vec2_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
668     ierr = VecScatterEnd(matis->ctx,pcis->vec1_global,pcis->vec2_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
669     ierr = VecScatterBegin(matis->ctx,used_vec,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
670     ierr = VecScatterEnd(matis->ctx,used_vec,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
671     if (dirIS) {
672       ierr = ISGetSize(dirIS,&dirsize);CHKERRQ(ierr);
673       ierr = VecGetArray(pcis->vec1_N,&array_x);CHKERRQ(ierr);
674       ierr = VecGetArray(pcis->vec2_N,&array_diagonal);CHKERRQ(ierr);
675       ierr = ISGetIndices(dirIS,(const PetscInt**)&is_indices);CHKERRQ(ierr);
676       for (i=0; i<dirsize; i++) array_x[is_indices[i]] = array_diagonal[is_indices[i]];
677       ierr = ISRestoreIndices(dirIS,(const PetscInt**)&is_indices);CHKERRQ(ierr);
678       ierr = VecRestoreArray(pcis->vec2_N,&array_diagonal);CHKERRQ(ierr);
679       ierr = VecRestoreArray(pcis->vec1_N,&array_x);CHKERRQ(ierr);
680     }
681     ierr = VecScatterBegin(matis->ctx,pcis->vec1_N,used_vec,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
682     ierr = VecScatterEnd(matis->ctx,pcis->vec1_N,used_vec,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
683 
684     /* remove the computed solution from the rhs */
685     ierr = VecScale(used_vec,-1.0);CHKERRQ(ierr);
686     ierr = MatMultAdd(pc->pmat,used_vec,rhs,rhs);CHKERRQ(ierr);
687     ierr = VecScale(used_vec,-1.0);CHKERRQ(ierr);
688   }
689 
690   /* store partially computed solution and set initial guess */
691   if (x) {
692     ierr = VecCopy(used_vec,pcbddc->temp_solution);CHKERRQ(ierr);
693     ierr = VecSet(used_vec,0.0);CHKERRQ(ierr);
694     if (pcbddc->use_exact_dirichlet_trick) {
695       ierr = VecScatterBegin(pcis->global_to_D,rhs,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
696       ierr = VecScatterEnd  (pcis->global_to_D,rhs,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
697       ierr = KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
698       ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,used_vec,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
699       ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec2_D,used_vec,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
700       if (ksp) {
701         ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr);
702       }
703     }
704   }
705 
706   /* prepare MatMult and rhs for solver */
707   if (pcbddc->use_change_of_basis) {
708     /* swap pointers for local matrices */
709     temp_mat = matis->A;
710     matis->A = pcbddc->local_mat;
711     pcbddc->local_mat = temp_mat;
712     if (rhs) {
713       /* Get local rhs and apply transformation of basis */
714       ierr = VecScatterBegin(pcis->global_to_B,rhs,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
715       ierr = VecScatterEnd  (pcis->global_to_B,rhs,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
716       /* from original basis to modified basis */
717       ierr = MatMultTranspose(pcbddc->ChangeOfBasisMatrix,pcis->vec1_B,pcis->vec2_B);CHKERRQ(ierr);
718       /* put back modified values into the global vec using INSERT_VALUES copy mode */
719       ierr = VecScatterBegin(pcis->global_to_B,pcis->vec2_B,rhs,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
720       ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec2_B,rhs,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
721     }
722   }
723 
724   /* remove nullspace if present */
725   if (ksp && pcbddc->NullSpace) {
726     ierr = MatNullSpaceRemove(pcbddc->NullSpace,used_vec);CHKERRQ(ierr);
727     ierr = MatNullSpaceRemove(pcbddc->NullSpace,rhs);CHKERRQ(ierr);
728   }
729   ierr = VecDestroy(&used_vec);CHKERRQ(ierr);
730   PetscFunctionReturn(0);
731 }
732 /* -------------------------------------------------------------------------- */
733 #undef __FUNCT__
734 #define __FUNCT__ "PCPostSolve_BDDC"
735 /* -------------------------------------------------------------------------- */
736 /*
737    PCPostSolve_BDDC - Changes the computed solution if a transformation of basis
738                      approach has been selected. Also, restores rhs to its original state.
739 
740    Input Parameter:
741 +  pc - the preconditioner contex
742 
743    Application Interface Routine: PCPostSolve()
744 
745    Notes:
746    The interface routine PCPostSolve() is not usually called directly by
747    the user, but instead is called by KSPSolve().
748 */
749 static PetscErrorCode PCPostSolve_BDDC(PC pc, KSP ksp, Vec rhs, Vec x)
750 {
751   PetscErrorCode ierr;
752   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
753   PC_IS          *pcis   = (PC_IS*)(pc->data);
754   Mat_IS         *matis = (Mat_IS*)pc->pmat->data;
755   Mat            temp_mat;
756 
757   PetscFunctionBegin;
758   if (pcbddc->use_change_of_basis) {
759     /* swap pointers for local matrices */
760     temp_mat = matis->A;
761     matis->A = pcbddc->local_mat;
762     pcbddc->local_mat = temp_mat;
763   }
764   if (pcbddc->use_change_of_basis && x) {
765     /* Get Local boundary and apply transformation of basis to solution vector */
766     ierr = VecScatterBegin(pcis->global_to_B,x,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
767     ierr = VecScatterEnd  (pcis->global_to_B,x,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
768     /* from modified basis to original basis */
769     ierr = MatMult(pcbddc->ChangeOfBasisMatrix,pcis->vec1_B,pcis->vec2_B);CHKERRQ(ierr);
770     /* put back modified values into the global vec using INSERT_VALUES copy mode */
771     ierr = VecScatterBegin(pcis->global_to_B,pcis->vec2_B,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
772     ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec2_B,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
773   }
774   /* add solution removed in presolve */
775   if (x) {
776     ierr = VecAXPY(x,1.0,pcbddc->temp_solution);CHKERRQ(ierr);
777   }
778   /* restore rhs to its original state */
779   if (rhs) {
780     ierr = VecCopy(pcbddc->original_rhs,rhs);CHKERRQ(ierr);
781   }
782   PetscFunctionReturn(0);
783 }
784 /* -------------------------------------------------------------------------- */
785 #undef __FUNCT__
786 #define __FUNCT__ "PCSetUp_BDDC"
787 /* -------------------------------------------------------------------------- */
788 /*
789    PCSetUp_BDDC - Prepares for the use of the BDDC preconditioner
790                   by setting data structures and options.
791 
792    Input Parameter:
793 +  pc - the preconditioner context
794 
795    Application Interface Routine: PCSetUp()
796 
797    Notes:
798    The interface routine PCSetUp() is not usually called directly by
799    the user, but instead is called by PCApply() if necessary.
800 */
801 PetscErrorCode PCSetUp_BDDC(PC pc)
802 {
803   PetscErrorCode   ierr;
804   PC_BDDC*         pcbddc = (PC_BDDC*)pc->data;
805   MatNullSpace     nearnullspace;
806   MatStructure     flag;
807   PetscBool        computeis,computetopography,computesolvers;
808   PetscBool        new_nearnullspace_provided;
809 
810   PetscFunctionBegin;
811   /* the following lines of code should be replaced by a better logic between PCIS, PCNN, PCBDDC and other future nonoverlapping preconditioners */
812   /* PCIS does not support MatStructure flags different from SAME_PRECONDITIONER */
813   /* For BDDC we need to define a local "Neumann" problem different to that defined in PCISSetup
814      Also, BDDC directly build the Dirichlet problem */
815 
816   /* split work */
817   if (pc->setupcalled) {
818     computeis = PETSC_FALSE;
819     ierr = PCGetOperators(pc,NULL,NULL,&flag);CHKERRQ(ierr);
820     if (flag == SAME_PRECONDITIONER) {
821       PetscFunctionReturn(0);
822     } else if (flag == SAME_NONZERO_PATTERN) {
823       computetopography = PETSC_FALSE;
824       computesolvers = PETSC_TRUE;
825     } else { /* DIFFERENT_NONZERO_PATTERN */
826       computetopography = PETSC_TRUE;
827       computesolvers = PETSC_TRUE;
828     }
829   } else {
830     computeis = PETSC_TRUE;
831     computetopography = PETSC_TRUE;
832     computesolvers = PETSC_TRUE;
833   }
834   if (pcbddc->recompute_topography) {
835     computetopography = PETSC_TRUE;
836   }
837 
838   /* Get stdout for dbg */
839   if (pcbddc->dbg_flag && !pcbddc->dbg_viewer) {
840     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)pc),&pcbddc->dbg_viewer);CHKERRQ(ierr);
841     ierr = PetscViewerASCIISynchronizedAllow(pcbddc->dbg_viewer,PETSC_TRUE);CHKERRQ(ierr);
842     if (pcbddc->current_level) {
843       ierr = PetscViewerASCIIAddTab(pcbddc->dbg_viewer,2);CHKERRQ(ierr);
844     }
845   }
846 
847   /* Set up all the "iterative substructuring" common block without computing solvers */
848   if (computeis) {
849     /* HACK INTO PCIS */
850     PC_IS* pcis = (PC_IS*)pc->data;
851     pcis->computesolvers = PETSC_FALSE;
852     ierr = PCISSetUp(pc);CHKERRQ(ierr);
853     ierr = ISLocalToGlobalMappingCreateIS(pcis->is_B_local,&pcbddc->BtoNmap);CHKERRQ(ierr);
854   }
855 
856   /* Analyze interface */
857   if (computetopography) {
858     ierr = PCBDDCAnalyzeInterface(pc);CHKERRQ(ierr);
859   }
860 
861   /* infer if NullSpace object attached to Mat via MatSetNearNullSpace has changed */
862   new_nearnullspace_provided = PETSC_FALSE;
863   ierr = MatGetNearNullSpace(pc->pmat,&nearnullspace);CHKERRQ(ierr);
864   if (pcbddc->onearnullspace) { /* already used nearnullspace */
865     if (!nearnullspace) { /* near null space attached to mat has been destroyed */
866       new_nearnullspace_provided = PETSC_TRUE;
867     } else {
868       /* determine if the two nullspaces are different (should be lightweight) */
869       if (nearnullspace != pcbddc->onearnullspace) {
870         new_nearnullspace_provided = PETSC_TRUE;
871       } else { /* maybe the user has changed the content of the nearnullspace so check vectors ObjectStateId */
872         PetscInt         i;
873         const Vec        *nearnullvecs;
874         PetscObjectState state;
875         PetscInt         nnsp_size;
876         ierr = MatNullSpaceGetVecs(nearnullspace,NULL,&nnsp_size,&nearnullvecs);CHKERRQ(ierr);
877         for (i=0;i<nnsp_size;i++) {
878           ierr = PetscObjectStateGet((PetscObject)nearnullvecs[i],&state);CHKERRQ(ierr);
879           if (pcbddc->onearnullvecs_state[i] != state) {
880             new_nearnullspace_provided = PETSC_TRUE;
881             break;
882           }
883         }
884       }
885     }
886   } else {
887     if (!nearnullspace) { /* both nearnullspaces are null */
888       new_nearnullspace_provided = PETSC_FALSE;
889     } else { /* nearnullspace attached later */
890       new_nearnullspace_provided = PETSC_TRUE;
891     }
892   }
893 
894   /* Setup constraints and related work vectors */
895   /* reset primal space flags */
896   pcbddc->new_primal_space = PETSC_FALSE;
897   pcbddc->new_primal_space_local = PETSC_FALSE;
898   if (computetopography || new_nearnullspace_provided) {
899     /* It also sets the primal space flags */
900     ierr = PCBDDCConstraintsSetUp(pc);CHKERRQ(ierr);
901     /* Allocate needed local vectors (which depends on quantities defined during ConstraintsSetUp) */
902     ierr = PCBDDCSetUpLocalWorkVectors(pc);CHKERRQ(ierr);
903   }
904 
905   if (computesolvers || pcbddc->new_primal_space) {
906     /* reset data */
907     ierr = PCBDDCScalingDestroy(pc);CHKERRQ(ierr);
908     /* Create coarse and local stuffs */
909     ierr = PCBDDCSetUpSolvers(pc);CHKERRQ(ierr);
910     ierr = PCBDDCScalingSetUp(pc);CHKERRQ(ierr);
911   }
912   if (pcbddc->dbg_flag && pcbddc->current_level) {
913     ierr = PetscViewerASCIISubtractTab(pcbddc->dbg_viewer,2);CHKERRQ(ierr);
914   }
915   PetscFunctionReturn(0);
916 }
917 
918 /* -------------------------------------------------------------------------- */
919 /*
920    PCApply_BDDC - Applies the BDDC preconditioner to a vector.
921 
922    Input Parameters:
923 .  pc - the preconditioner context
924 .  r - input vector (global)
925 
926    Output Parameter:
927 .  z - output vector (global)
928 
929    Application Interface Routine: PCApply()
930  */
931 #undef __FUNCT__
932 #define __FUNCT__ "PCApply_BDDC"
933 PetscErrorCode PCApply_BDDC(PC pc,Vec r,Vec z)
934 {
935   PC_IS             *pcis = (PC_IS*)(pc->data);
936   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
937   PetscErrorCode    ierr;
938   const PetscScalar one = 1.0;
939   const PetscScalar m_one = -1.0;
940   const PetscScalar zero = 0.0;
941 
942 /* This code is similar to that provided in nn.c for PCNN
943    NN interface preconditioner changed to BDDC
944    Added support for M_3 preconditioner in the reference article (code is active if pcbddc->switch_static = PETSC_TRUE) */
945 
946   PetscFunctionBegin;
947   if (!pcbddc->use_exact_dirichlet_trick) {
948     /* First Dirichlet solve */
949     ierr = VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
950     ierr = VecScatterEnd  (pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
951     ierr = KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
952     /*
953       Assembling right hand side for BDDC operator
954       - pcis->vec1_D for the Dirichlet part (if needed, i.e. prec_flag=PETSC_TRUE)
955       - pcis->vec1_B the interface part of the global vector z
956     */
957     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
958     ierr = MatMult(pcis->A_BI,pcis->vec2_D,pcis->vec1_B);CHKERRQ(ierr);
959     if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec2_D,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
960     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
961     ierr = VecCopy(r,z);CHKERRQ(ierr);
962     ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
963     ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
964     ierr = PCBDDCScalingRestriction(pc,z,pcis->vec1_B);CHKERRQ(ierr);
965   } else {
966     ierr = VecSet(pcis->vec1_D,zero);CHKERRQ(ierr);
967     ierr = VecSet(pcis->vec2_D,zero);CHKERRQ(ierr);
968     ierr = PCBDDCScalingRestriction(pc,r,pcis->vec1_B);CHKERRQ(ierr);
969   }
970 
971   /* Apply interface preconditioner
972      input/output vecs: pcis->vec1_B and pcis->vec1_D */
973   ierr = PCBDDCApplyInterfacePreconditioner(pc);CHKERRQ(ierr);
974 
975   /* Apply transpose of partition of unity operator */
976   ierr = PCBDDCScalingExtension(pc,pcis->vec1_B,z);CHKERRQ(ierr);
977 
978   /* Second Dirichlet solve and assembling of output */
979   ierr = VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
980   ierr = VecScatterEnd  (pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
981   ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec3_D);CHKERRQ(ierr);
982   if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec1_D,pcis->vec3_D,pcis->vec3_D);CHKERRQ(ierr); }
983   ierr = KSPSolve(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D);CHKERRQ(ierr);
984   ierr = VecScale(pcis->vec4_D,m_one);CHKERRQ(ierr);
985   if (pcbddc->switch_static) { ierr = VecAXPY (pcis->vec4_D,one,pcis->vec1_D);CHKERRQ(ierr); }
986   ierr = VecAXPY (pcis->vec2_D,one,pcis->vec4_D);CHKERRQ(ierr);
987   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
988   ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
989   PetscFunctionReturn(0);
990 }
991 /* -------------------------------------------------------------------------- */
992 
993 #undef __FUNCT__
994 #define __FUNCT__ "PCDestroy_BDDC"
995 PetscErrorCode PCDestroy_BDDC(PC pc)
996 {
997   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
998   PetscErrorCode ierr;
999 
1000   PetscFunctionBegin;
1001   /* free data created by PCIS */
1002   ierr = PCISDestroy(pc);CHKERRQ(ierr);
1003   /* free BDDC custom data  */
1004   ierr = PCBDDCResetCustomization(pc);CHKERRQ(ierr);
1005   /* destroy objects related to topography */
1006   ierr = PCBDDCResetTopography(pc);CHKERRQ(ierr);
1007   /* free allocated graph structure */
1008   ierr = PetscFree(pcbddc->mat_graph);CHKERRQ(ierr);
1009   /* free data for scaling operator */
1010   ierr = PCBDDCScalingDestroy(pc);CHKERRQ(ierr);
1011   /* free solvers stuff */
1012   ierr = PCBDDCResetSolvers(pc);CHKERRQ(ierr);
1013   /* free global vectors needed in presolve */
1014   ierr = VecDestroy(&pcbddc->temp_solution);CHKERRQ(ierr);
1015   ierr = VecDestroy(&pcbddc->original_rhs);CHKERRQ(ierr);
1016   ierr = ISLocalToGlobalMappingDestroy(&pcbddc->BtoNmap);CHKERRQ(ierr);
1017   /* remove functions */
1018   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",NULL);CHKERRQ(ierr);
1019   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",NULL);CHKERRQ(ierr);
1020   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",NULL);CHKERRQ(ierr);
1021   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",NULL);CHKERRQ(ierr);
1022   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",NULL);CHKERRQ(ierr);
1023   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",NULL);CHKERRQ(ierr);
1024   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1025   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1026   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1027   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1028   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",NULL);CHKERRQ(ierr);
1029   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",NULL);CHKERRQ(ierr);
1030   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",NULL);CHKERRQ(ierr);
1031   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",NULL);CHKERRQ(ierr);
1032   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",NULL);CHKERRQ(ierr);
1033   /* Free the private data structure */
1034   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1035   PetscFunctionReturn(0);
1036 }
1037 /* -------------------------------------------------------------------------- */
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS_BDDC"
1041 static PetscErrorCode PCBDDCMatFETIDPGetRHS_BDDC(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1042 {
1043   FETIDPMat_ctx  mat_ctx;
1044   PC_IS*         pcis;
1045   PC_BDDC*       pcbddc;
1046   PetscErrorCode ierr;
1047 
1048   PetscFunctionBegin;
1049   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1050   pcis = (PC_IS*)mat_ctx->pc->data;
1051   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1052 
1053   /* change of basis for physical rhs if needed
1054      It also changes the rhs in case of dirichlet boundaries */
1055   ierr = PCPreSolve_BDDC(mat_ctx->pc,NULL,standard_rhs,NULL);CHKERRQ(ierr);
1056   /* store vectors for computation of fetidp final solution */
1057   ierr = VecScatterBegin(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1058   ierr = VecScatterEnd(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1059   /* scale rhs since it should be unassembled */
1060   /* TODO use counter scaling? (also below) */
1061   ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1062   ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1063   /* Apply partition of unity */
1064   ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1065   /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1066   if (!pcbddc->switch_static) {
1067     /* compute partially subassembled Schur complement right-hand side */
1068     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1069     ierr = MatMult(pcis->A_BI,pcis->vec1_D,pcis->vec1_B);CHKERRQ(ierr);
1070     ierr = VecAXPY(mat_ctx->temp_solution_B,-1.0,pcis->vec1_B);CHKERRQ(ierr);
1071     ierr = VecSet(standard_rhs,0.0);CHKERRQ(ierr);
1072     ierr = VecScatterBegin(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1073     ierr = VecScatterEnd(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1074     /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1075     ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1076     ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1077     ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1078   }
1079   /* BDDC rhs */
1080   ierr = VecCopy(mat_ctx->temp_solution_B,pcis->vec1_B);CHKERRQ(ierr);
1081   if (pcbddc->switch_static) {
1082     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1083   }
1084   /* apply BDDC */
1085   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc);CHKERRQ(ierr);
1086   /* Application of B_delta and assembling of rhs for fetidp fluxes */
1087   ierr = VecSet(fetidp_flux_rhs,0.0);CHKERRQ(ierr);
1088   ierr = MatMult(mat_ctx->B_delta,pcis->vec1_B,mat_ctx->lambda_local);CHKERRQ(ierr);
1089   ierr = VecScatterBegin(mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1090   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1091   /* restore original rhs */
1092   ierr = VecCopy(pcbddc->original_rhs,standard_rhs);CHKERRQ(ierr);
1093   PetscFunctionReturn(0);
1094 }
1095 
1096 #undef __FUNCT__
1097 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS"
1098 /*@
1099  PCBDDCMatFETIDPGetRHS - Compute the right-hand side for FETIDP linear system
1100 
1101    Collective
1102 
1103    Input Parameters:
1104 +  fetidp_mat   - the FETIDP matrix object obtained by calling PCBDDCCreateFETIDPOperators
1105 .  standard_rhs - the right-hand side for your linear system
1106 
1107    Output Parameters:
1108 -  fetidp_flux_rhs   - the right-hand side for the FETIDP linear system
1109 
1110    Level: developer
1111 
1112    Notes:
1113 
1114 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1115 @*/
1116 PetscErrorCode PCBDDCMatFETIDPGetRHS(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1117 {
1118   FETIDPMat_ctx  mat_ctx;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1123   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetRHS_C",(Mat,Vec,Vec),(fetidp_mat,standard_rhs,fetidp_flux_rhs));CHKERRQ(ierr);
1124   PetscFunctionReturn(0);
1125 }
1126 /* -------------------------------------------------------------------------- */
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution_BDDC"
1130 static PetscErrorCode PCBDDCMatFETIDPGetSolution_BDDC(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1131 {
1132   FETIDPMat_ctx  mat_ctx;
1133   PC_IS*         pcis;
1134   PC_BDDC*       pcbddc;
1135   PetscErrorCode ierr;
1136 
1137   PetscFunctionBegin;
1138   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1139   pcis = (PC_IS*)mat_ctx->pc->data;
1140   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1141 
1142   /* apply B_delta^T */
1143   ierr = VecScatterBegin(mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1144   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1145   ierr = MatMultTranspose(mat_ctx->B_delta,mat_ctx->lambda_local,pcis->vec1_B);CHKERRQ(ierr);
1146   /* compute rhs for BDDC application */
1147   ierr = VecAYPX(pcis->vec1_B,-1.0,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1148   if (pcbddc->switch_static) {
1149     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1150   }
1151   /* apply BDDC */
1152   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc);CHKERRQ(ierr);
1153   /* put values into standard global vector */
1154   ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1155   ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1156   if (!pcbddc->switch_static) {
1157     /* compute values into the interior if solved for the partially subassembled Schur complement */
1158     ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec1_D);CHKERRQ(ierr);
1159     ierr = VecAXPY(mat_ctx->temp_solution_D,-1.0,pcis->vec1_D);CHKERRQ(ierr);
1160     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1161   }
1162   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1163   ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1164   /* final change of basis if needed
1165      Is also sums the dirichlet part removed during RHS assembling */
1166   ierr = PCPostSolve_BDDC(mat_ctx->pc,NULL,NULL,standard_sol);CHKERRQ(ierr);
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 #undef __FUNCT__
1171 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution"
1172 /*@
1173  PCBDDCMatFETIDPGetSolution - Compute the physical solution from the solution of the FETIDP linear system
1174 
1175    Collective
1176 
1177    Input Parameters:
1178 +  fetidp_mat        - the FETIDP matrix obtained by calling PCBDDCCreateFETIDPOperators
1179 .  fetidp_flux_sol - the solution of the FETIDP linear system
1180 
1181    Output Parameters:
1182 -  standard_sol      - the solution defined on the physical domain
1183 
1184    Level: developer
1185 
1186    Notes:
1187 
1188 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1189 @*/
1190 PetscErrorCode PCBDDCMatFETIDPGetSolution(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1191 {
1192   FETIDPMat_ctx  mat_ctx;
1193   PetscErrorCode ierr;
1194 
1195   PetscFunctionBegin;
1196   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1197   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetSolution_C",(Mat,Vec,Vec),(fetidp_mat,fetidp_flux_sol,standard_sol));CHKERRQ(ierr);
1198   PetscFunctionReturn(0);
1199 }
1200 /* -------------------------------------------------------------------------- */
1201 
1202 extern PetscErrorCode FETIDPMatMult(Mat,Vec,Vec);
1203 extern PetscErrorCode PCBDDCDestroyFETIDPMat(Mat);
1204 extern PetscErrorCode FETIDPPCApply(PC,Vec,Vec);
1205 extern PetscErrorCode PCBDDCDestroyFETIDPPC(PC);
1206 
1207 #undef __FUNCT__
1208 #define __FUNCT__ "PCBDDCCreateFETIDPOperators_BDDC"
1209 static PetscErrorCode PCBDDCCreateFETIDPOperators_BDDC(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1210 {
1211 
1212   FETIDPMat_ctx  fetidpmat_ctx;
1213   Mat            newmat;
1214   FETIDPPC_ctx   fetidppc_ctx;
1215   PC             newpc;
1216   MPI_Comm       comm;
1217   PetscErrorCode ierr;
1218 
1219   PetscFunctionBegin;
1220   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
1221   /* FETIDP linear matrix */
1222   ierr = PCBDDCCreateFETIDPMatContext(pc,&fetidpmat_ctx);CHKERRQ(ierr);
1223   ierr = PCBDDCSetupFETIDPMatContext(fetidpmat_ctx);CHKERRQ(ierr);
1224   ierr = MatCreateShell(comm,PETSC_DECIDE,PETSC_DECIDE,fetidpmat_ctx->n_lambda,fetidpmat_ctx->n_lambda,fetidpmat_ctx,&newmat);CHKERRQ(ierr);
1225   ierr = MatShellSetOperation(newmat,MATOP_MULT,(void (*)(void))FETIDPMatMult);CHKERRQ(ierr);
1226   ierr = MatShellSetOperation(newmat,MATOP_DESTROY,(void (*)(void))PCBDDCDestroyFETIDPMat);CHKERRQ(ierr);
1227   ierr = MatSetUp(newmat);CHKERRQ(ierr);
1228   /* FETIDP preconditioner */
1229   ierr = PCBDDCCreateFETIDPPCContext(pc,&fetidppc_ctx);CHKERRQ(ierr);
1230   ierr = PCBDDCSetupFETIDPPCContext(newmat,fetidppc_ctx);CHKERRQ(ierr);
1231   ierr = PCCreate(comm,&newpc);CHKERRQ(ierr);
1232   ierr = PCSetType(newpc,PCSHELL);CHKERRQ(ierr);
1233   ierr = PCShellSetContext(newpc,fetidppc_ctx);CHKERRQ(ierr);
1234   ierr = PCShellSetApply(newpc,FETIDPPCApply);CHKERRQ(ierr);
1235   ierr = PCShellSetDestroy(newpc,PCBDDCDestroyFETIDPPC);CHKERRQ(ierr);
1236   ierr = PCSetOperators(newpc,newmat,newmat,SAME_PRECONDITIONER);CHKERRQ(ierr);
1237   ierr = PCSetUp(newpc);CHKERRQ(ierr);
1238   /* return pointers for objects created */
1239   *fetidp_mat=newmat;
1240   *fetidp_pc=newpc;
1241   PetscFunctionReturn(0);
1242 }
1243 
1244 #undef __FUNCT__
1245 #define __FUNCT__ "PCBDDCCreateFETIDPOperators"
1246 /*@
1247  PCBDDCCreateFETIDPOperators - Create operators for FETIDP
1248 
1249    Collective
1250 
1251    Input Parameters:
1252 +  pc - the BDDC preconditioning context already setup
1253 
1254    Output Parameters:
1255 .  fetidp_mat - shell FETIDP matrix object
1256 .  fetidp_pc  - shell Dirichlet preconditioner for FETIDP matrix
1257 
1258    Options Database Keys:
1259 -    -fetidp_fullyredundant: use or not a fully redundant set of Lagrange multipliers
1260 
1261    Level: developer
1262 
1263    Notes:
1264      Currently the only operation provided for FETIDP matrix is MatMult
1265 
1266 .seealso: PCBDDC
1267 @*/
1268 PetscErrorCode PCBDDCCreateFETIDPOperators(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1269 {
1270   PetscErrorCode ierr;
1271 
1272   PetscFunctionBegin;
1273   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1274   if (pc->setupcalled) {
1275     ierr = PetscUseMethod(pc,"PCBDDCCreateFETIDPOperators_C",(PC,Mat*,PC*),(pc,fetidp_mat,fetidp_pc));CHKERRQ(ierr);
1276   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"You must call PCSetup_BDDC() first \n");
1277   PetscFunctionReturn(0);
1278 }
1279 /* -------------------------------------------------------------------------- */
1280 /*MC
1281    PCBDDC - Balancing Domain Decomposition by Constraints.
1282 
1283    An implementation of the BDDC preconditioner based on
1284 
1285 .vb
1286    [1] C. R. Dohrmann. "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149-168, March 2007
1287    [2] A. Klawonn and O. B. Widlund. "Dual-Primal FETI Methods for Linear Elasticity", http://cs.nyu.edu/csweb/Research/TechReports/TR2004-855/TR2004-855.pdf
1288    [3] J. Mandel, B. Sousedik, C. R. Dohrmann. "Multispace and Multilevel BDDC", http://arxiv.org/abs/0712.3977
1289 .ve
1290 
1291    The matrix to be preconditioned (Pmat) must be of type MATIS.
1292 
1293    Currently works with MATIS matrices with local Neumann matrices of type MATSEQAIJ, MATSEQBAIJ or MATSEQSBAIJ, either with real or complex numbers.
1294 
1295    It also works with unsymmetric and indefinite problems.
1296 
1297    Unlike 'conventional' interface preconditioners, PCBDDC iterates over all degrees of freedom, not just those on the interface. This allows the use of approximate solvers on the subdomains.
1298 
1299    Approximate local solvers are automatically adapted for singular linear problems (see [1]) if the user has provided the nullspace using PCBDDCSetNullSpace
1300 
1301    Boundary nodes are split in vertices, edges and faces using information from the local to global mapping of dofs and the local connectivity graph of nodes. The latter can be customized by using PCBDDCSetLocalAdjacencyGraph
1302 
1303    Constraints can be customized by attaching a MatNullSpace object to the MATIS matrix via MatSetNearNullSpace.
1304 
1305    Change of basis is performed similarly to [2] when requested. When more the one constraint is present on a single connected component (i.e. an edge or a face), a robust method based on local QR factorizations is used.
1306 
1307    The PETSc implementation also supports multilevel BDDC [3]. Coarse grids are partitioned using MatPartitioning object.
1308 
1309    Options Database Keys:
1310 
1311 .    -pc_bddc_use_vertices <1> - use or not vertices in primal space
1312 .    -pc_bddc_use_edges <1> - use or not edges in primal space
1313 .    -pc_bddc_use_faces <0> - use or not faces in primal space
1314 .    -pc_bddc_use_change_of_basis <0> - use change of basis approach (on edges only)
1315 .    -pc_bddc_use_change_on_faces <0> - use change of basis approach on faces if change of basis has been requested
1316 .    -pc_bddc_switch_static <0> - switches from M_2 to M_3 operator (see reference article [1])
1317 .    -pc_bddc_levels <0> - maximum number of levels for multilevel
1318 .    -pc_bddc_coarsening_ratio - H/h ratio at the coarser level
1319 -    -pc_bddc_check_level <0> - set verbosity level of debugging output
1320 
1321    Options for Dirichlet, Neumann or coarse solver can be set with
1322 .vb
1323       -pc_bddc_dirichlet_
1324       -pc_bddc_neumann_
1325       -pc_bddc_coarse_
1326 .ve
1327    e.g -pc_bddc_dirichlet_ksp_type richardson -pc_bddc_dirichlet_pc_type gamg
1328 
1329    When using a multilevel approach, solvers' options at the N-th level can be specified as
1330 .vb
1331       -pc_bddc_dirichlet_N_
1332       -pc_bddc_neumann_N_
1333       -pc_bddc_coarse_N_
1334 .ve
1335    Note that level number ranges from the finest 0 to the coarsest N
1336 
1337    Level: intermediate
1338 
1339    Developer notes:
1340      Currently does not work with KSPBCGS and other KSPs requiring the specialization of PCApplyTranspose
1341 
1342      New deluxe scaling operator will be available soon.
1343 
1344    Contributed by Stefano Zampini
1345 
1346 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,  MATIS
1347 M*/
1348 
1349 #undef __FUNCT__
1350 #define __FUNCT__ "PCCreate_BDDC"
1351 PETSC_EXTERN PetscErrorCode PCCreate_BDDC(PC pc)
1352 {
1353   PetscErrorCode      ierr;
1354   PC_BDDC             *pcbddc;
1355 
1356   PetscFunctionBegin;
1357   /* Creates the private data structure for this preconditioner and attach it to the PC object. */
1358   ierr      = PetscNewLog(pc,&pcbddc);CHKERRQ(ierr);
1359   pc->data  = (void*)pcbddc;
1360 
1361   /* create PCIS data structure */
1362   ierr = PCISCreate(pc);CHKERRQ(ierr);
1363 
1364   /* BDDC customization */
1365   pcbddc->use_vertices        = PETSC_TRUE;
1366   pcbddc->use_edges           = PETSC_TRUE;
1367   pcbddc->use_faces           = PETSC_FALSE;
1368   pcbddc->use_change_of_basis = PETSC_FALSE;
1369   pcbddc->use_change_on_faces = PETSC_FALSE;
1370   pcbddc->switch_static       = PETSC_FALSE;
1371   pcbddc->use_nnsp_true       = PETSC_FALSE; /* not yet exposed */
1372   pcbddc->dbg_flag            = 0;
1373 
1374   pcbddc->BtoNmap                    = 0;
1375   pcbddc->local_primal_size          = 0;
1376   pcbddc->n_vertices                 = 0;
1377   pcbddc->n_actual_vertices          = 0;
1378   pcbddc->n_constraints              = 0;
1379   pcbddc->primal_indices_local_idxs  = 0;
1380   pcbddc->recompute_topography       = PETSC_FALSE;
1381   pcbddc->coarse_size                = 0;
1382   pcbddc->new_primal_space           = PETSC_FALSE;
1383   pcbddc->new_primal_space_local     = PETSC_FALSE;
1384   pcbddc->global_primal_indices      = 0;
1385   pcbddc->onearnullspace             = 0;
1386   pcbddc->onearnullvecs_state        = 0;
1387   pcbddc->user_primal_vertices       = 0;
1388   pcbddc->NullSpace                  = 0;
1389   pcbddc->temp_solution              = 0;
1390   pcbddc->original_rhs               = 0;
1391   pcbddc->local_mat                  = 0;
1392   pcbddc->ChangeOfBasisMatrix        = 0;
1393   pcbddc->coarse_vec                 = 0;
1394   pcbddc->coarse_rhs                 = 0;
1395   pcbddc->coarse_ksp                 = 0;
1396   pcbddc->coarse_phi_B               = 0;
1397   pcbddc->coarse_phi_D               = 0;
1398   pcbddc->coarse_psi_B               = 0;
1399   pcbddc->coarse_psi_D               = 0;
1400   pcbddc->vec1_P                     = 0;
1401   pcbddc->vec1_R                     = 0;
1402   pcbddc->vec2_R                     = 0;
1403   pcbddc->local_auxmat1              = 0;
1404   pcbddc->local_auxmat2              = 0;
1405   pcbddc->R_to_B                     = 0;
1406   pcbddc->R_to_D                     = 0;
1407   pcbddc->ksp_D                      = 0;
1408   pcbddc->ksp_R                      = 0;
1409   pcbddc->NeumannBoundaries          = 0;
1410   pcbddc->user_provided_isfordofs    = PETSC_FALSE;
1411   pcbddc->n_ISForDofs                = 0;
1412   pcbddc->ISForDofs                  = 0;
1413   pcbddc->ConstraintMatrix           = 0;
1414   pcbddc->use_exact_dirichlet_trick  = PETSC_TRUE;
1415   pcbddc->coarse_loc_to_glob         = 0;
1416   pcbddc->coarsening_ratio           = 8;
1417   pcbddc->current_level              = 0;
1418   pcbddc->max_levels                 = 0;
1419 
1420   /* create local graph structure */
1421   ierr = PCBDDCGraphCreate(&pcbddc->mat_graph);CHKERRQ(ierr);
1422 
1423   /* scaling */
1424   pcbddc->use_deluxe_scaling         = PETSC_FALSE;
1425   pcbddc->work_scaling               = 0;
1426 
1427   /* function pointers */
1428   pc->ops->apply               = PCApply_BDDC;
1429   pc->ops->applytranspose      = 0;
1430   pc->ops->setup               = PCSetUp_BDDC;
1431   pc->ops->destroy             = PCDestroy_BDDC;
1432   pc->ops->setfromoptions      = PCSetFromOptions_BDDC;
1433   pc->ops->view                = 0;
1434   pc->ops->applyrichardson     = 0;
1435   pc->ops->applysymmetricleft  = 0;
1436   pc->ops->applysymmetricright = 0;
1437   pc->ops->presolve            = PCPreSolve_BDDC;
1438   pc->ops->postsolve           = PCPostSolve_BDDC;
1439 
1440   /* composing function */
1441   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",PCBDDCSetPrimalVerticesLocalIS_BDDC);CHKERRQ(ierr);
1442   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",PCBDDCSetCoarseningRatio_BDDC);CHKERRQ(ierr);
1443   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",PCBDDCSetLevel_BDDC);CHKERRQ(ierr);
1444   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",PCBDDCSetUseExactDirichlet_BDDC);CHKERRQ(ierr);
1445   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",PCBDDCSetLevels_BDDC);CHKERRQ(ierr);
1446   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",PCBDDCSetNullSpace_BDDC);CHKERRQ(ierr);
1447   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",PCBDDCSetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1448   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",PCBDDCSetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1449   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",PCBDDCGetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1450   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",PCBDDCGetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1451   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",PCBDDCSetDofsSplitting_BDDC);CHKERRQ(ierr);
1452   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",PCBDDCSetLocalAdjacencyGraph_BDDC);CHKERRQ(ierr);
1453   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",PCBDDCCreateFETIDPOperators_BDDC);CHKERRQ(ierr);
1454   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",PCBDDCMatFETIDPGetRHS_BDDC);CHKERRQ(ierr);
1455   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",PCBDDCMatFETIDPGetSolution_BDDC);CHKERRQ(ierr);
1456   PetscFunctionReturn(0);
1457 }
1458 
1459