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