xref: /petsc/src/ksp/pc/impls/bddc/bddc.c (revision 1a8a16d1105e2584542a2e805272f3902b1b4046)
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 && !pcbddc->dbg_viewer) {
1092     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)pc),&pcbddc->dbg_viewer);CHKERRQ(ierr);
1093     ierr = PetscViewerASCIISynchronizedAllow(pcbddc->dbg_viewer,PETSC_TRUE);CHKERRQ(ierr);
1094     if (pcbddc->current_level) {
1095       ierr = PetscViewerASCIIAddTab(pcbddc->dbg_viewer,2);CHKERRQ(ierr);
1096     }
1097   }
1098 
1099   /* Set up all the "iterative substructuring" common block without computing solvers */
1100   if (computeis) {
1101     /* HACK INTO PCIS */
1102     PC_IS* pcis = (PC_IS*)pc->data;
1103     pcis->computesolvers = PETSC_FALSE;
1104     ierr = PCISSetUp(pc);CHKERRQ(ierr);
1105     ierr = ISLocalToGlobalMappingCreateIS(pcis->is_B_local,&pcbddc->BtoNmap);CHKERRQ(ierr);
1106   }
1107 
1108   /* Analyze interface */
1109   if (computetopography) {
1110     ierr = PCBDDCAnalyzeInterface(pc);CHKERRQ(ierr);
1111   }
1112 
1113   /* infer if NullSpace object attached to Mat via MatSetNearNullSpace has changed */
1114   new_nearnullspace_provided = PETSC_FALSE;
1115   ierr = MatGetNearNullSpace(pc->pmat,&nearnullspace);CHKERRQ(ierr);
1116   if (pcbddc->onearnullspace) { /* already used nearnullspace */
1117     if (!nearnullspace) { /* near null space attached to mat has been destroyed */
1118       new_nearnullspace_provided = PETSC_TRUE;
1119     } else {
1120       /* determine if the two nullspaces are different (should be lightweight) */
1121       if (nearnullspace != pcbddc->onearnullspace) {
1122         new_nearnullspace_provided = PETSC_TRUE;
1123       } else { /* maybe the user has changed the content of the nearnullspace so check vectors ObjectStateId */
1124         PetscInt         i;
1125         const Vec        *nearnullvecs;
1126         PetscObjectState state;
1127         PetscInt         nnsp_size;
1128         ierr = MatNullSpaceGetVecs(nearnullspace,NULL,&nnsp_size,&nearnullvecs);CHKERRQ(ierr);
1129         for (i=0;i<nnsp_size;i++) {
1130           ierr = PetscObjectStateGet((PetscObject)nearnullvecs[i],&state);CHKERRQ(ierr);
1131           if (pcbddc->onearnullvecs_state[i] != state) {
1132             new_nearnullspace_provided = PETSC_TRUE;
1133             break;
1134           }
1135         }
1136       }
1137     }
1138   } else {
1139     if (!nearnullspace) { /* both nearnullspaces are null */
1140       new_nearnullspace_provided = PETSC_FALSE;
1141     } else { /* nearnullspace attached later */
1142       new_nearnullspace_provided = PETSC_TRUE;
1143     }
1144   }
1145 
1146   /* Setup constraints and related work vectors */
1147   /* reset primal space flags */
1148   pcbddc->new_primal_space = PETSC_FALSE;
1149   pcbddc->new_primal_space_local = PETSC_FALSE;
1150   if (computetopography || new_nearnullspace_provided) {
1151     /* It also sets the primal space flags */
1152     ierr = PCBDDCConstraintsSetUp(pc);CHKERRQ(ierr);
1153     /* Allocate needed local vectors (which depends on quantities defined during ConstraintsSetUp) */
1154     ierr = PCBDDCSetUpLocalWorkVectors(pc);CHKERRQ(ierr);
1155   }
1156 
1157   if (computesolvers || pcbddc->new_primal_space) {
1158     /* reset data */
1159     ierr = PCBDDCScalingDestroy(pc);CHKERRQ(ierr);
1160     /* Create coarse and local stuffs */
1161     ierr = PCBDDCSetUpSolvers(pc);CHKERRQ(ierr);
1162     ierr = PCBDDCScalingSetUp(pc);CHKERRQ(ierr);
1163   }
1164   if (pcbddc->dbg_flag && pcbddc->current_level) {
1165     ierr = PetscViewerASCIISubtractTab(pcbddc->dbg_viewer,2);CHKERRQ(ierr);
1166   }
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 /* -------------------------------------------------------------------------- */
1171 /*
1172    PCApply_BDDC - Applies the BDDC preconditioner to a vector.
1173 
1174    Input Parameters:
1175 .  pc - the preconditioner context
1176 .  r - input vector (global)
1177 
1178    Output Parameter:
1179 .  z - output vector (global)
1180 
1181    Application Interface Routine: PCApply()
1182  */
1183 #undef __FUNCT__
1184 #define __FUNCT__ "PCApply_BDDC"
1185 PetscErrorCode PCApply_BDDC(PC pc,Vec r,Vec z)
1186 {
1187   PC_IS             *pcis = (PC_IS*)(pc->data);
1188   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
1189   PetscErrorCode    ierr;
1190   const PetscScalar one = 1.0;
1191   const PetscScalar m_one = -1.0;
1192   const PetscScalar zero = 0.0;
1193 
1194 /* This code is similar to that provided in nn.c for PCNN
1195    NN interface preconditioner changed to BDDC
1196    Added support for M_3 preconditioner in the reference article (code is active if pcbddc->switch_static = PETSC_TRUE) */
1197 
1198   PetscFunctionBegin;
1199   if (!pcbddc->use_exact_dirichlet_trick) {
1200     /* First Dirichlet solve */
1201     ierr = VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1202     ierr = VecScatterEnd  (pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1203     ierr = KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
1204     /*
1205       Assembling right hand side for BDDC operator
1206       - pcis->vec1_D for the Dirichlet part (if needed, i.e. prec_flag=PETSC_TRUE)
1207       - pcis->vec1_B the interface part of the global vector z
1208     */
1209     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1210     ierr = MatMult(pcis->A_BI,pcis->vec2_D,pcis->vec1_B);CHKERRQ(ierr);
1211     if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec2_D,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
1212     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1213     ierr = VecCopy(r,z);CHKERRQ(ierr);
1214     ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1215     ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1216     ierr = PCBDDCScalingRestriction(pc,z,pcis->vec1_B);CHKERRQ(ierr);
1217   } else {
1218     ierr = VecSet(pcis->vec1_D,zero);CHKERRQ(ierr);
1219     ierr = VecSet(pcis->vec2_D,zero);CHKERRQ(ierr);
1220     ierr = PCBDDCScalingRestriction(pc,r,pcis->vec1_B);CHKERRQ(ierr);
1221   }
1222 
1223   /* Apply interface preconditioner
1224      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1225   ierr = PCBDDCApplyInterfacePreconditioner(pc);CHKERRQ(ierr);
1226 
1227   /* Apply transpose of partition of unity operator */
1228   ierr = PCBDDCScalingExtension(pc,pcis->vec1_B,z);CHKERRQ(ierr);
1229 
1230   /* Second Dirichlet solve and assembling of output */
1231   ierr = VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1232   ierr = VecScatterEnd  (pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1233   ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec3_D);CHKERRQ(ierr);
1234   if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec1_D,pcis->vec3_D,pcis->vec3_D);CHKERRQ(ierr); }
1235   ierr = KSPSolve(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D);CHKERRQ(ierr);
1236   ierr = VecScale(pcis->vec4_D,m_one);CHKERRQ(ierr);
1237   if (pcbddc->switch_static) { ierr = VecAXPY (pcis->vec4_D,one,pcis->vec1_D);CHKERRQ(ierr); }
1238   ierr = VecAXPY (pcis->vec2_D,one,pcis->vec4_D);CHKERRQ(ierr);
1239   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1240   ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1241   PetscFunctionReturn(0);
1242 }
1243 /* -------------------------------------------------------------------------- */
1244 
1245 #undef __FUNCT__
1246 #define __FUNCT__ "PCDestroy_BDDC"
1247 PetscErrorCode PCDestroy_BDDC(PC pc)
1248 {
1249   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
1250   PetscErrorCode ierr;
1251 
1252   PetscFunctionBegin;
1253   /* free data created by PCIS */
1254   ierr = PCISDestroy(pc);CHKERRQ(ierr);
1255   /* free BDDC custom data  */
1256   ierr = PCBDDCResetCustomization(pc);CHKERRQ(ierr);
1257   /* destroy objects related to topography */
1258   ierr = PCBDDCResetTopography(pc);CHKERRQ(ierr);
1259   /* free allocated graph structure */
1260   ierr = PetscFree(pcbddc->mat_graph);CHKERRQ(ierr);
1261   /* free data for scaling operator */
1262   ierr = PCBDDCScalingDestroy(pc);CHKERRQ(ierr);
1263   /* free solvers stuff */
1264   ierr = PCBDDCResetSolvers(pc);CHKERRQ(ierr);
1265   /* free global vectors needed in presolve */
1266   ierr = VecDestroy(&pcbddc->temp_solution);CHKERRQ(ierr);
1267   ierr = VecDestroy(&pcbddc->original_rhs);CHKERRQ(ierr);
1268   ierr = ISLocalToGlobalMappingDestroy(&pcbddc->BtoNmap);CHKERRQ(ierr);
1269   /* remove functions */
1270   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",NULL);CHKERRQ(ierr);
1271   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",NULL);CHKERRQ(ierr);
1272   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",NULL);CHKERRQ(ierr);
1273   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",NULL);CHKERRQ(ierr);
1274   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",NULL);CHKERRQ(ierr);
1275   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",NULL);CHKERRQ(ierr);
1276   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1277   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",NULL);CHKERRQ(ierr);
1278   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1279   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",NULL);CHKERRQ(ierr);
1280   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1281   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",NULL);CHKERRQ(ierr);
1282   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1283   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",NULL);CHKERRQ(ierr);
1284   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",NULL);CHKERRQ(ierr);
1285   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",NULL);CHKERRQ(ierr);
1286   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",NULL);CHKERRQ(ierr);
1287   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",NULL);CHKERRQ(ierr);
1288   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",NULL);CHKERRQ(ierr);
1289   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",NULL);CHKERRQ(ierr);
1290   /* Free the private data structure */
1291   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1292   PetscFunctionReturn(0);
1293 }
1294 /* -------------------------------------------------------------------------- */
1295 
1296 #undef __FUNCT__
1297 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS_BDDC"
1298 static PetscErrorCode PCBDDCMatFETIDPGetRHS_BDDC(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1299 {
1300   FETIDPMat_ctx  mat_ctx;
1301   PC_IS*         pcis;
1302   PC_BDDC*       pcbddc;
1303   PetscErrorCode ierr;
1304 
1305   PetscFunctionBegin;
1306   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1307   pcis = (PC_IS*)mat_ctx->pc->data;
1308   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1309 
1310   /* change of basis for physical rhs if needed
1311      It also changes the rhs in case of dirichlet boundaries */
1312   ierr = PCPreSolve_BDDC(mat_ctx->pc,NULL,standard_rhs,NULL);CHKERRQ(ierr);
1313   /* store vectors for computation of fetidp final solution */
1314   ierr = VecScatterBegin(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1315   ierr = VecScatterEnd(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1316   /* scale rhs since it should be unassembled */
1317   /* TODO use counter scaling? (also below) */
1318   ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1319   ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1320   /* Apply partition of unity */
1321   ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1322   /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1323   if (!pcbddc->switch_static) {
1324     /* compute partially subassembled Schur complement right-hand side */
1325     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1326     ierr = MatMult(pcis->A_BI,pcis->vec1_D,pcis->vec1_B);CHKERRQ(ierr);
1327     ierr = VecAXPY(mat_ctx->temp_solution_B,-1.0,pcis->vec1_B);CHKERRQ(ierr);
1328     ierr = VecSet(standard_rhs,0.0);CHKERRQ(ierr);
1329     ierr = VecScatterBegin(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1330     ierr = VecScatterEnd(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1331     /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1332     ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1333     ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1334     ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1335   }
1336   /* BDDC rhs */
1337   ierr = VecCopy(mat_ctx->temp_solution_B,pcis->vec1_B);CHKERRQ(ierr);
1338   if (pcbddc->switch_static) {
1339     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1340   }
1341   /* apply BDDC */
1342   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc);CHKERRQ(ierr);
1343   /* Application of B_delta and assembling of rhs for fetidp fluxes */
1344   ierr = VecSet(fetidp_flux_rhs,0.0);CHKERRQ(ierr);
1345   ierr = MatMult(mat_ctx->B_delta,pcis->vec1_B,mat_ctx->lambda_local);CHKERRQ(ierr);
1346   ierr = VecScatterBegin(mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1347   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1348   /* restore original rhs */
1349   ierr = VecCopy(pcbddc->original_rhs,standard_rhs);CHKERRQ(ierr);
1350   PetscFunctionReturn(0);
1351 }
1352 
1353 #undef __FUNCT__
1354 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS"
1355 /*@
1356  PCBDDCMatFETIDPGetRHS - Compute the right-hand side for FETIDP linear system
1357 
1358    Collective
1359 
1360    Input Parameters:
1361 +  fetidp_mat   - the FETIDP matrix object obtained by calling PCBDDCCreateFETIDPOperators
1362 .  standard_rhs - the right-hand side for your linear system
1363 
1364    Output Parameters:
1365 -  fetidp_flux_rhs   - the right-hand side for the FETIDP linear system
1366 
1367    Level: developer
1368 
1369    Notes:
1370 
1371 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1372 @*/
1373 PetscErrorCode PCBDDCMatFETIDPGetRHS(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1374 {
1375   FETIDPMat_ctx  mat_ctx;
1376   PetscErrorCode ierr;
1377 
1378   PetscFunctionBegin;
1379   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1380   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetRHS_C",(Mat,Vec,Vec),(fetidp_mat,standard_rhs,fetidp_flux_rhs));CHKERRQ(ierr);
1381   PetscFunctionReturn(0);
1382 }
1383 /* -------------------------------------------------------------------------- */
1384 
1385 #undef __FUNCT__
1386 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution_BDDC"
1387 static PetscErrorCode PCBDDCMatFETIDPGetSolution_BDDC(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1388 {
1389   FETIDPMat_ctx  mat_ctx;
1390   PC_IS*         pcis;
1391   PC_BDDC*       pcbddc;
1392   PetscErrorCode ierr;
1393 
1394   PetscFunctionBegin;
1395   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1396   pcis = (PC_IS*)mat_ctx->pc->data;
1397   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1398 
1399   /* apply B_delta^T */
1400   ierr = VecScatterBegin(mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1401   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1402   ierr = MatMultTranspose(mat_ctx->B_delta,mat_ctx->lambda_local,pcis->vec1_B);CHKERRQ(ierr);
1403   /* compute rhs for BDDC application */
1404   ierr = VecAYPX(pcis->vec1_B,-1.0,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1405   if (pcbddc->switch_static) {
1406     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1407   }
1408   /* apply BDDC */
1409   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc);CHKERRQ(ierr);
1410   /* put values into standard global vector */
1411   ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1412   ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1413   if (!pcbddc->switch_static) {
1414     /* compute values into the interior if solved for the partially subassembled Schur complement */
1415     ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec1_D);CHKERRQ(ierr);
1416     ierr = VecAXPY(mat_ctx->temp_solution_D,-1.0,pcis->vec1_D);CHKERRQ(ierr);
1417     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1418   }
1419   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1420   ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1421   /* final change of basis if needed
1422      Is also sums the dirichlet part removed during RHS assembling */
1423   ierr = PCPostSolve_BDDC(mat_ctx->pc,NULL,NULL,standard_sol);CHKERRQ(ierr);
1424   PetscFunctionReturn(0);
1425 }
1426 
1427 #undef __FUNCT__
1428 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution"
1429 /*@
1430  PCBDDCMatFETIDPGetSolution - Compute the physical solution from the solution of the FETIDP linear system
1431 
1432    Collective
1433 
1434    Input Parameters:
1435 +  fetidp_mat        - the FETIDP matrix obtained by calling PCBDDCCreateFETIDPOperators
1436 .  fetidp_flux_sol - the solution of the FETIDP linear system
1437 
1438    Output Parameters:
1439 -  standard_sol      - the solution defined on the physical domain
1440 
1441    Level: developer
1442 
1443    Notes:
1444 
1445 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1446 @*/
1447 PetscErrorCode PCBDDCMatFETIDPGetSolution(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1448 {
1449   FETIDPMat_ctx  mat_ctx;
1450   PetscErrorCode ierr;
1451 
1452   PetscFunctionBegin;
1453   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1454   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetSolution_C",(Mat,Vec,Vec),(fetidp_mat,fetidp_flux_sol,standard_sol));CHKERRQ(ierr);
1455   PetscFunctionReturn(0);
1456 }
1457 /* -------------------------------------------------------------------------- */
1458 
1459 extern PetscErrorCode FETIDPMatMult(Mat,Vec,Vec);
1460 extern PetscErrorCode PCBDDCDestroyFETIDPMat(Mat);
1461 extern PetscErrorCode FETIDPPCApply(PC,Vec,Vec);
1462 extern PetscErrorCode PCBDDCDestroyFETIDPPC(PC);
1463 
1464 #undef __FUNCT__
1465 #define __FUNCT__ "PCBDDCCreateFETIDPOperators_BDDC"
1466 static PetscErrorCode PCBDDCCreateFETIDPOperators_BDDC(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1467 {
1468 
1469   FETIDPMat_ctx  fetidpmat_ctx;
1470   Mat            newmat;
1471   FETIDPPC_ctx   fetidppc_ctx;
1472   PC             newpc;
1473   MPI_Comm       comm;
1474   PetscErrorCode ierr;
1475 
1476   PetscFunctionBegin;
1477   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
1478   /* FETIDP linear matrix */
1479   ierr = PCBDDCCreateFETIDPMatContext(pc,&fetidpmat_ctx);CHKERRQ(ierr);
1480   ierr = PCBDDCSetupFETIDPMatContext(fetidpmat_ctx);CHKERRQ(ierr);
1481   ierr = MatCreateShell(comm,PETSC_DECIDE,PETSC_DECIDE,fetidpmat_ctx->n_lambda,fetidpmat_ctx->n_lambda,fetidpmat_ctx,&newmat);CHKERRQ(ierr);
1482   ierr = MatShellSetOperation(newmat,MATOP_MULT,(void (*)(void))FETIDPMatMult);CHKERRQ(ierr);
1483   ierr = MatShellSetOperation(newmat,MATOP_DESTROY,(void (*)(void))PCBDDCDestroyFETIDPMat);CHKERRQ(ierr);
1484   ierr = MatSetUp(newmat);CHKERRQ(ierr);
1485   /* FETIDP preconditioner */
1486   ierr = PCBDDCCreateFETIDPPCContext(pc,&fetidppc_ctx);CHKERRQ(ierr);
1487   ierr = PCBDDCSetupFETIDPPCContext(newmat,fetidppc_ctx);CHKERRQ(ierr);
1488   ierr = PCCreate(comm,&newpc);CHKERRQ(ierr);
1489   ierr = PCSetType(newpc,PCSHELL);CHKERRQ(ierr);
1490   ierr = PCShellSetContext(newpc,fetidppc_ctx);CHKERRQ(ierr);
1491   ierr = PCShellSetApply(newpc,FETIDPPCApply);CHKERRQ(ierr);
1492   ierr = PCShellSetDestroy(newpc,PCBDDCDestroyFETIDPPC);CHKERRQ(ierr);
1493   ierr = PCSetOperators(newpc,newmat,newmat,SAME_PRECONDITIONER);CHKERRQ(ierr);
1494   ierr = PCSetUp(newpc);CHKERRQ(ierr);
1495   /* return pointers for objects created */
1496   *fetidp_mat=newmat;
1497   *fetidp_pc=newpc;
1498   PetscFunctionReturn(0);
1499 }
1500 
1501 #undef __FUNCT__
1502 #define __FUNCT__ "PCBDDCCreateFETIDPOperators"
1503 /*@
1504  PCBDDCCreateFETIDPOperators - Create operators for FETIDP
1505 
1506    Collective
1507 
1508    Input Parameters:
1509 +  pc - the BDDC preconditioning context already setup
1510 
1511    Output Parameters:
1512 .  fetidp_mat - shell FETIDP matrix object
1513 .  fetidp_pc  - shell Dirichlet preconditioner for FETIDP matrix
1514 
1515    Options Database Keys:
1516 -    -fetidp_fullyredundant: use or not a fully redundant set of Lagrange multipliers
1517 
1518    Level: developer
1519 
1520    Notes:
1521      Currently the only operation provided for FETIDP matrix is MatMult
1522 
1523 .seealso: PCBDDC
1524 @*/
1525 PetscErrorCode PCBDDCCreateFETIDPOperators(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1526 {
1527   PetscErrorCode ierr;
1528 
1529   PetscFunctionBegin;
1530   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1531   if (pc->setupcalled) {
1532     ierr = PetscUseMethod(pc,"PCBDDCCreateFETIDPOperators_C",(PC,Mat*,PC*),(pc,fetidp_mat,fetidp_pc));CHKERRQ(ierr);
1533   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"You must call PCSetup_BDDC() first \n");
1534   PetscFunctionReturn(0);
1535 }
1536 /* -------------------------------------------------------------------------- */
1537 /*MC
1538    PCBDDC - Balancing Domain Decomposition by Constraints.
1539 
1540    An implementation of the BDDC preconditioner based on
1541 
1542 .vb
1543    [1] C. R. Dohrmann. "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149-168, March 2007
1544    [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
1545    [3] J. Mandel, B. Sousedik, C. R. Dohrmann. "Multispace and Multilevel BDDC", http://arxiv.org/abs/0712.3977
1546 .ve
1547 
1548    The matrix to be preconditioned (Pmat) must be of type MATIS.
1549 
1550    Currently works with MATIS matrices with local Neumann matrices of type MATSEQAIJ, MATSEQBAIJ or MATSEQSBAIJ, either with real or complex numbers.
1551 
1552    It also works with unsymmetric and indefinite problems.
1553 
1554    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.
1555 
1556    Approximate local solvers are automatically adapted for singular linear problems (see [1]) if the user has provided the nullspace using PCBDDCSetNullSpace
1557 
1558    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
1559 
1560    Constraints can be customized by attaching a MatNullSpace object to the MATIS matrix via MatSetNearNullSpace.
1561 
1562    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.
1563 
1564    The PETSc implementation also supports multilevel BDDC [3]. Coarse grids are partitioned using MatPartitioning object.
1565 
1566    Options Database Keys:
1567 
1568 .    -pc_bddc_use_vertices <1> - use or not vertices in primal space
1569 .    -pc_bddc_use_edges <1> - use or not edges in primal space
1570 .    -pc_bddc_use_faces <0> - use or not faces in primal space
1571 .    -pc_bddc_use_change_of_basis <0> - use change of basis approach (on edges only)
1572 .    -pc_bddc_use_change_on_faces <0> - use change of basis approach on faces if change of basis has been requested
1573 .    -pc_bddc_switch_static <0> - switches from M_2 to M_3 operator (see reference article [1])
1574 .    -pc_bddc_levels <0> - maximum number of levels for multilevel
1575 .    -pc_bddc_coarsening_ratio - H/h ratio at the coarser level
1576 -    -pc_bddc_check_level <0> - set verbosity level of debugging output
1577 
1578    Options for Dirichlet, Neumann or coarse solver can be set with
1579 .vb
1580       -pc_bddc_dirichlet_
1581       -pc_bddc_neumann_
1582       -pc_bddc_coarse_
1583 .ve
1584    e.g -pc_bddc_dirichlet_ksp_type richardson -pc_bddc_dirichlet_pc_type gamg
1585 
1586    When using a multilevel approach, solvers' options at the N-th level can be specified as
1587 .vb
1588       -pc_bddc_dirichlet_N_
1589       -pc_bddc_neumann_N_
1590       -pc_bddc_coarse_N_
1591 .ve
1592    Note that level number ranges from the finest 0 to the coarsest N
1593 
1594    Level: intermediate
1595 
1596    Developer notes:
1597      Currently does not work with KSPBCGS and other KSPs requiring the specialization of PCApplyTranspose
1598 
1599      New deluxe scaling operator will be available soon.
1600 
1601    Contributed by Stefano Zampini
1602 
1603 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,  MATIS
1604 M*/
1605 
1606 #undef __FUNCT__
1607 #define __FUNCT__ "PCCreate_BDDC"
1608 PETSC_EXTERN PetscErrorCode PCCreate_BDDC(PC pc)
1609 {
1610   PetscErrorCode      ierr;
1611   PC_BDDC             *pcbddc;
1612 
1613   PetscFunctionBegin;
1614   /* Creates the private data structure for this preconditioner and attach it to the PC object. */
1615   ierr      = PetscNewLog(pc,PC_BDDC,&pcbddc);CHKERRQ(ierr);
1616   pc->data  = (void*)pcbddc;
1617 
1618   /* create PCIS data structure */
1619   ierr = PCISCreate(pc);CHKERRQ(ierr);
1620 
1621   /* BDDC customization */
1622   pcbddc->use_vertices        = PETSC_TRUE;
1623   pcbddc->use_edges           = PETSC_TRUE;
1624   pcbddc->use_faces           = PETSC_FALSE;
1625   pcbddc->use_change_of_basis = PETSC_FALSE;
1626   pcbddc->use_change_on_faces = PETSC_FALSE;
1627   pcbddc->switch_static       = PETSC_FALSE;
1628   pcbddc->use_nnsp_true       = PETSC_FALSE; /* not yet exposed */
1629   pcbddc->dbg_flag            = 0;
1630 
1631   pcbddc->BtoNmap                    = 0;
1632   pcbddc->local_primal_size          = 0;
1633   pcbddc->n_vertices                 = 0;
1634   pcbddc->n_actual_vertices          = 0;
1635   pcbddc->n_constraints              = 0;
1636   pcbddc->primal_indices_local_idxs  = 0;
1637   pcbddc->recompute_topography       = PETSC_FALSE;
1638   pcbddc->coarse_size                = 0;
1639   pcbddc->new_primal_space           = PETSC_FALSE;
1640   pcbddc->new_primal_space_local     = PETSC_FALSE;
1641   pcbddc->global_primal_indices      = 0;
1642   pcbddc->onearnullspace             = 0;
1643   pcbddc->onearnullvecs_state        = 0;
1644   pcbddc->user_primal_vertices       = 0;
1645   pcbddc->NullSpace                  = 0;
1646   pcbddc->temp_solution              = 0;
1647   pcbddc->original_rhs               = 0;
1648   pcbddc->local_mat                  = 0;
1649   pcbddc->ChangeOfBasisMatrix        = 0;
1650   pcbddc->coarse_vec                 = 0;
1651   pcbddc->coarse_rhs                 = 0;
1652   pcbddc->coarse_ksp                 = 0;
1653   pcbddc->coarse_phi_B               = 0;
1654   pcbddc->coarse_phi_D               = 0;
1655   pcbddc->coarse_psi_B               = 0;
1656   pcbddc->coarse_psi_D               = 0;
1657   pcbddc->vec1_P                     = 0;
1658   pcbddc->vec1_R                     = 0;
1659   pcbddc->vec2_R                     = 0;
1660   pcbddc->local_auxmat1              = 0;
1661   pcbddc->local_auxmat2              = 0;
1662   pcbddc->R_to_B                     = 0;
1663   pcbddc->R_to_D                     = 0;
1664   pcbddc->ksp_D                      = 0;
1665   pcbddc->ksp_R                      = 0;
1666   pcbddc->NeumannBoundaries          = 0;
1667   pcbddc->NeumannBoundariesLocal     = 0;
1668   pcbddc->DirichletBoundaries        = 0;
1669   pcbddc->DirichletBoundariesLocal   = 0;
1670   pcbddc->user_provided_isfordofs    = PETSC_FALSE;
1671   pcbddc->n_ISForDofs                = 0;
1672   pcbddc->n_ISForDofsLocal           = 0;
1673   pcbddc->ISForDofs                  = 0;
1674   pcbddc->ISForDofsLocal             = 0;
1675   pcbddc->ConstraintMatrix           = 0;
1676   pcbddc->use_exact_dirichlet_trick  = PETSC_TRUE;
1677   pcbddc->coarse_loc_to_glob         = 0;
1678   pcbddc->coarsening_ratio           = 8;
1679   pcbddc->current_level              = 0;
1680   pcbddc->max_levels                 = 0;
1681 
1682   /* create local graph structure */
1683   ierr = PCBDDCGraphCreate(&pcbddc->mat_graph);CHKERRQ(ierr);
1684 
1685   /* scaling */
1686   pcbddc->use_deluxe_scaling         = PETSC_FALSE;
1687   pcbddc->work_scaling               = 0;
1688 
1689   /* function pointers */
1690   pc->ops->apply               = PCApply_BDDC;
1691   pc->ops->applytranspose      = 0;
1692   pc->ops->setup               = PCSetUp_BDDC;
1693   pc->ops->destroy             = PCDestroy_BDDC;
1694   pc->ops->setfromoptions      = PCSetFromOptions_BDDC;
1695   pc->ops->view                = 0;
1696   pc->ops->applyrichardson     = 0;
1697   pc->ops->applysymmetricleft  = 0;
1698   pc->ops->applysymmetricright = 0;
1699   pc->ops->presolve            = PCPreSolve_BDDC;
1700   pc->ops->postsolve           = PCPostSolve_BDDC;
1701 
1702   /* composing function */
1703   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",PCBDDCSetPrimalVerticesLocalIS_BDDC);CHKERRQ(ierr);
1704   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",PCBDDCSetCoarseningRatio_BDDC);CHKERRQ(ierr);
1705   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",PCBDDCSetLevel_BDDC);CHKERRQ(ierr);
1706   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",PCBDDCSetUseExactDirichlet_BDDC);CHKERRQ(ierr);
1707   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",PCBDDCSetLevels_BDDC);CHKERRQ(ierr);
1708   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",PCBDDCSetNullSpace_BDDC);CHKERRQ(ierr);
1709   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",PCBDDCSetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1710   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",PCBDDCSetDirichletBoundariesLocal_BDDC);CHKERRQ(ierr);
1711   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",PCBDDCSetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1712   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",PCBDDCSetNeumannBoundariesLocal_BDDC);CHKERRQ(ierr);
1713   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",PCBDDCGetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1714   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",PCBDDCGetDirichletBoundariesLocal_BDDC);CHKERRQ(ierr);
1715   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",PCBDDCGetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1716   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",PCBDDCGetNeumannBoundariesLocal_BDDC);CHKERRQ(ierr);
1717   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",PCBDDCSetDofsSplitting_BDDC);CHKERRQ(ierr);
1718   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",PCBDDCSetDofsSplittingLocal_BDDC);CHKERRQ(ierr);
1719   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",PCBDDCSetLocalAdjacencyGraph_BDDC);CHKERRQ(ierr);
1720   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",PCBDDCCreateFETIDPOperators_BDDC);CHKERRQ(ierr);
1721   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",PCBDDCMatFETIDPGetRHS_BDDC);CHKERRQ(ierr);
1722   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",PCBDDCMatFETIDPGetSolution_BDDC);CHKERRQ(ierr);
1723   PetscFunctionReturn(0);
1724 }
1725 
1726