xref: /petsc/src/ksp/pc/impls/bddc/bddc.c (revision 68457ee5e567a733bb3ba02714aa90a4591afcc7)
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    - DofSplitting and DM attached to pc?
15 
16    Debugging output
17    - Better management of verbosity levels of debugging output
18 
19    Build
20    - make runexe59
21 
22    Extra
23    - Is it possible to work with PCBDDCGraph on boundary indices only (less memory consumed)?
24    - add support for computing h,H and related using coordinates?
25    - Change of basis approach does not work with my nonlinear mechanics example. why? (seems not an issue with l2gmap)
26    - Better management in PCIS code
27    - BDDC with MG framework?
28 
29    FETIDP
30    - Move FETIDP code to its own classes
31 
32    MATIS related operations contained in BDDC code
33    - Provide general case for subassembling
34    - Preallocation routines in MatISGetMPIAXAIJ
35 
36 */
37 
38 /* ----------------------------------------------------------------------------------------------------------------------------------------------
39    Implementation of BDDC preconditioner based on:
40    C. Dohrmann "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149-168, March 2007
41    ---------------------------------------------------------------------------------------------------------------------------------------------- */
42 
43 #include "bddc.h" /*I "petscpc.h" I*/  /* includes for fortran wrappers */
44 #include "bddcprivate.h"
45 #include <petscblaslapack.h>
46 
47 /* -------------------------------------------------------------------------- */
48 #undef __FUNCT__
49 #define __FUNCT__ "PCSetFromOptions_BDDC"
50 PetscErrorCode PCSetFromOptions_BDDC(PC pc)
51 {
52   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
53   PetscErrorCode ierr;
54 
55   PetscFunctionBegin;
56   ierr = PetscOptionsHead("BDDC options");CHKERRQ(ierr);
57   /* Verbose debugging */
58   ierr = PetscOptionsInt("-pc_bddc_check_level","Verbose output for PCBDDC (intended for debug)","none",pcbddc->dbg_flag,&pcbddc->dbg_flag,NULL);CHKERRQ(ierr);
59   /* Primal space cumstomization */
60   ierr = PetscOptionsBool("-pc_bddc_use_vertices","Use or not corner dofs in coarse space","none",pcbddc->use_vertices,&pcbddc->use_vertices,NULL);CHKERRQ(ierr);
61   ierr = PetscOptionsBool("-pc_bddc_use_edges","Use or not edge constraints in coarse space","none",pcbddc->use_edges,&pcbddc->use_edges,NULL);CHKERRQ(ierr);
62   ierr = PetscOptionsBool("-pc_bddc_use_faces","Use or not face constraints in coarse space","none",pcbddc->use_faces,&pcbddc->use_faces,NULL);CHKERRQ(ierr);
63   /* Change of basis */
64   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);
65   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);
66   if (!pcbddc->use_change_of_basis) {
67     pcbddc->use_change_on_faces = PETSC_FALSE;
68   }
69   /* Switch between M_2 (default) and M_3 preconditioners (as defined by C. Dohrmann in the ref. article) */
70   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);
71   ierr = PetscOptionsInt("-pc_bddc_coarsening_ratio","Set coarsening ratio used in multilevel coarsening","none",pcbddc->coarsening_ratio,&pcbddc->coarsening_ratio,NULL);CHKERRQ(ierr);
72   ierr = PetscOptionsInt("-pc_bddc_levels","Set maximum number of levels for multilevel","none",pcbddc->max_levels,&pcbddc->max_levels,NULL);CHKERRQ(ierr);
73   ierr = PetscOptionsBool("-pc_bddc_use_coarse_estimates","Use estimated eigenvalues for coarse problem","none",pcbddc->use_coarse_estimates,&pcbddc->use_coarse_estimates,NULL);CHKERRQ(ierr);
74   ierr = PetscOptionsBool("-pc_bddc_use_deluxe_scaling","Use deluxe scaling for BDDC","none",pcbddc->use_deluxe_scaling,&pcbddc->use_deluxe_scaling,NULL);CHKERRQ(ierr);
75   ierr = PetscOptionsTail();CHKERRQ(ierr);
76   PetscFunctionReturn(0);
77 }
78 /* -------------------------------------------------------------------------- */
79 #undef __FUNCT__
80 #define __FUNCT__ "PCBDDCSetPrimalVerticesLocalIS_BDDC"
81 static PetscErrorCode PCBDDCSetPrimalVerticesLocalIS_BDDC(PC pc, IS PrimalVertices)
82 {
83   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
84   PetscErrorCode ierr;
85 
86   PetscFunctionBegin;
87   ierr = ISDestroy(&pcbddc->user_primal_vertices);CHKERRQ(ierr);
88   ierr = PetscObjectReference((PetscObject)PrimalVertices);CHKERRQ(ierr);
89   pcbddc->user_primal_vertices = PrimalVertices;
90   PetscFunctionReturn(0);
91 }
92 #undef __FUNCT__
93 #define __FUNCT__ "PCBDDCSetPrimalVerticesLocalIS"
94 /*@
95  PCBDDCSetPrimalVerticesLocalIS - Set additional user defined primal vertices in PCBDDC
96 
97    Not collective
98 
99    Input Parameters:
100 +  pc - the preconditioning context
101 -  PrimalVertices - index set of primal vertices in local numbering
102 
103    Level: intermediate
104 
105    Notes:
106 
107 .seealso: PCBDDC
108 @*/
109 PetscErrorCode PCBDDCSetPrimalVerticesLocalIS(PC pc, IS PrimalVertices)
110 {
111   PetscErrorCode ierr;
112 
113   PetscFunctionBegin;
114   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
115   PetscValidHeaderSpecific(PrimalVertices,IS_CLASSID,2);
116   ierr = PetscTryMethod(pc,"PCBDDCSetPrimalVerticesLocalIS_C",(PC,IS),(pc,PrimalVertices));CHKERRQ(ierr);
117   PetscFunctionReturn(0);
118 }
119 /* -------------------------------------------------------------------------- */
120 #undef __FUNCT__
121 #define __FUNCT__ "PCBDDCSetCoarseningRatio_BDDC"
122 static PetscErrorCode PCBDDCSetCoarseningRatio_BDDC(PC pc,PetscInt k)
123 {
124   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
125 
126   PetscFunctionBegin;
127   pcbddc->coarsening_ratio = k;
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "PCBDDCSetCoarseningRatio"
133 /*@
134  PCBDDCSetCoarseningRatio - Set coarsening ratio used in multilevel
135 
136    Logically collective on PC
137 
138    Input Parameters:
139 +  pc - the preconditioning context
140 -  k - coarsening ratio (H/h at the coarser level)
141 
142    Approximatively k subdomains at the finer level will be aggregated into a single subdomain at the coarser level
143 
144    Level: intermediate
145 
146    Notes:
147 
148 .seealso: PCBDDC
149 @*/
150 PetscErrorCode PCBDDCSetCoarseningRatio(PC pc,PetscInt k)
151 {
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
156   PetscValidLogicalCollectiveInt(pc,k,2);
157   ierr = PetscTryMethod(pc,"PCBDDCSetCoarseningRatio_C",(PC,PetscInt),(pc,k));CHKERRQ(ierr);
158   PetscFunctionReturn(0);
159 }
160 
161 /* The following functions (PCBDDCSetUseExactDirichlet PCBDDCSetLevel) are not public */
162 #undef __FUNCT__
163 #define __FUNCT__ "PCBDDCSetUseExactDirichlet_BDDC"
164 static PetscErrorCode PCBDDCSetUseExactDirichlet_BDDC(PC pc,PetscBool flg)
165 {
166   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
167 
168   PetscFunctionBegin;
169   pcbddc->use_exact_dirichlet_trick = flg;
170   PetscFunctionReturn(0);
171 }
172 
173 #undef __FUNCT__
174 #define __FUNCT__ "PCBDDCSetUseExactDirichlet"
175 PetscErrorCode PCBDDCSetUseExactDirichlet(PC pc,PetscBool flg)
176 {
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
181   PetscValidLogicalCollectiveBool(pc,flg,2);
182   ierr = PetscTryMethod(pc,"PCBDDCSetUseExactDirichlet_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr);
183   PetscFunctionReturn(0);
184 }
185 
186 #undef __FUNCT__
187 #define __FUNCT__ "PCBDDCSetLevel_BDDC"
188 static PetscErrorCode PCBDDCSetLevel_BDDC(PC pc,PetscInt level)
189 {
190   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
191 
192   PetscFunctionBegin;
193   pcbddc->current_level = level;
194   PetscFunctionReturn(0);
195 }
196 
197 #undef __FUNCT__
198 #define __FUNCT__ "PCBDDCSetLevel"
199 PetscErrorCode PCBDDCSetLevel(PC pc,PetscInt level)
200 {
201   PetscErrorCode ierr;
202 
203   PetscFunctionBegin;
204   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
205   PetscValidLogicalCollectiveInt(pc,level,2);
206   ierr = PetscTryMethod(pc,"PCBDDCSetLevel_C",(PC,PetscInt),(pc,level));CHKERRQ(ierr);
207   PetscFunctionReturn(0);
208 }
209 
210 #undef __FUNCT__
211 #define __FUNCT__ "PCBDDCSetLevels_BDDC"
212 static PetscErrorCode PCBDDCSetLevels_BDDC(PC pc,PetscInt levels)
213 {
214   PC_BDDC  *pcbddc = (PC_BDDC*)pc->data;
215 
216   PetscFunctionBegin;
217   pcbddc->max_levels = levels;
218   PetscFunctionReturn(0);
219 }
220 
221 #undef __FUNCT__
222 #define __FUNCT__ "PCBDDCSetLevels"
223 /*@
224  PCBDDCSetLevels - Sets the maximum number of levels for multilevel
225 
226    Logically collective on PC
227 
228    Input Parameters:
229 +  pc - the preconditioning context
230 -  levels - the maximum number of levels (max 9)
231 
232    Default value is 0, i.e. traditional one-level BDDC
233 
234    Level: intermediate
235 
236    Notes:
237 
238 .seealso: PCBDDC
239 @*/
240 PetscErrorCode PCBDDCSetLevels(PC pc,PetscInt levels)
241 {
242   PetscErrorCode ierr;
243 
244   PetscFunctionBegin;
245   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
246   PetscValidLogicalCollectiveInt(pc,levels,2);
247   if (levels > 99) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Maximum number of levels for bddc is 99\n");
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       pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
1094       ierr = PetscViewerASCIISynchronizedAllow(pcbddc->dbg_viewer,PETSC_TRUE);CHKERRQ(ierr);
1095     }
1096     ierr = PetscViewerASCIIAddTab(pcbddc->dbg_viewer,2*pcbddc->current_level);CHKERRQ(ierr);
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 
1165   if (pcbddc->dbg_flag) {
1166     ierr = PetscViewerASCIISubtractTab(pcbddc->dbg_viewer,2*pcbddc->current_level);CHKERRQ(ierr);
1167   }
1168   PetscFunctionReturn(0);
1169 }
1170 
1171 /* -------------------------------------------------------------------------- */
1172 /*
1173    PCApply_BDDC - Applies the BDDC operator to a vector.
1174 
1175    Input Parameters:
1176 .  pc - the preconditioner context
1177 .  r - input vector (global)
1178 
1179    Output Parameter:
1180 .  z - output vector (global)
1181 
1182    Application Interface Routine: PCApply()
1183  */
1184 #undef __FUNCT__
1185 #define __FUNCT__ "PCApply_BDDC"
1186 PetscErrorCode PCApply_BDDC(PC pc,Vec r,Vec z)
1187 {
1188   PC_IS             *pcis = (PC_IS*)(pc->data);
1189   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
1190   PetscErrorCode    ierr;
1191   const PetscScalar one = 1.0;
1192   const PetscScalar m_one = -1.0;
1193   const PetscScalar zero = 0.0;
1194 
1195 /* This code is similar to that provided in nn.c for PCNN
1196    NN interface preconditioner changed to BDDC
1197    Added support for M_3 preconditioner in the reference article (code is active if pcbddc->switch_static = PETSC_TRUE) */
1198 
1199   PetscFunctionBegin;
1200   if (!pcbddc->use_exact_dirichlet_trick) {
1201     /* First Dirichlet solve */
1202     ierr = VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1203     ierr = VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1204     ierr = KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
1205     /*
1206       Assembling right hand side for BDDC operator
1207       - pcis->vec1_D for the Dirichlet part (if needed, i.e. prec_flag=PETSC_TRUE)
1208       - pcis->vec1_B the interface part of the global vector z
1209     */
1210     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1211     ierr = MatMult(pcis->A_BI,pcis->vec2_D,pcis->vec1_B);CHKERRQ(ierr);
1212     if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec2_D,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
1213     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1214     ierr = VecCopy(r,z);CHKERRQ(ierr);
1215     ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1216     ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1217     ierr = PCBDDCScalingRestriction(pc,z,pcis->vec1_B);CHKERRQ(ierr);
1218   } else {
1219     ierr = VecSet(pcis->vec1_D,zero);CHKERRQ(ierr);
1220     ierr = VecSet(pcis->vec2_D,zero);CHKERRQ(ierr);
1221     ierr = PCBDDCScalingRestriction(pc,r,pcis->vec1_B);CHKERRQ(ierr);
1222   }
1223 
1224   /* Apply interface preconditioner
1225      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1226   ierr = PCBDDCApplyInterfacePreconditioner(pc,PETSC_FALSE);CHKERRQ(ierr);
1227 
1228   /* Apply transpose of partition of unity operator */
1229   ierr = PCBDDCScalingExtension(pc,pcis->vec1_B,z);CHKERRQ(ierr);
1230 
1231   /* Second Dirichlet solve and assembling of output */
1232   ierr = VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1233   ierr = VecScatterEnd(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1234   ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec3_D);CHKERRQ(ierr);
1235   if (pcbddc->switch_static) { ierr = MatMultAdd(pcis->A_II,pcis->vec1_D,pcis->vec3_D,pcis->vec3_D);CHKERRQ(ierr); }
1236   ierr = KSPSolve(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D);CHKERRQ(ierr);
1237   ierr = VecScale(pcis->vec4_D,m_one);CHKERRQ(ierr);
1238   if (pcbddc->switch_static) { ierr = VecAXPY(pcis->vec4_D,one,pcis->vec1_D);CHKERRQ(ierr); }
1239   ierr = VecAXPY(pcis->vec2_D,one,pcis->vec4_D);CHKERRQ(ierr);
1240   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1241   ierr = VecScatterEnd(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1242   PetscFunctionReturn(0);
1243 }
1244 
1245 /* -------------------------------------------------------------------------- */
1246 /*
1247    PCApplyTranspose_BDDC - Applies the transpose of the BDDC operator to a vector.
1248 
1249    Input Parameters:
1250 .  pc - the preconditioner context
1251 .  r - input vector (global)
1252 
1253    Output Parameter:
1254 .  z - output vector (global)
1255 
1256    Application Interface Routine: PCApplyTranspose()
1257  */
1258 #undef __FUNCT__
1259 #define __FUNCT__ "PCApplyTranspose_BDDC"
1260 PetscErrorCode PCApplyTranspose_BDDC(PC pc,Vec r,Vec z)
1261 {
1262   PC_IS             *pcis = (PC_IS*)(pc->data);
1263   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
1264   PetscErrorCode    ierr;
1265   const PetscScalar one = 1.0;
1266   const PetscScalar m_one = -1.0;
1267   const PetscScalar zero = 0.0;
1268 
1269   PetscFunctionBegin;
1270   if (!pcbddc->use_exact_dirichlet_trick) {
1271     /* First Dirichlet solve */
1272     ierr = VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1273     ierr = VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1274     ierr = KSPSolveTranspose(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D);CHKERRQ(ierr);
1275     /*
1276       Assembling right hand side for BDDC operator
1277       - pcis->vec1_D for the Dirichlet part (if needed, i.e. prec_flag=PETSC_TRUE)
1278       - pcis->vec1_B the interface part of the global vector z
1279     */
1280     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1281     ierr = MatMultTranspose(pcis->A_IB,pcis->vec2_D,pcis->vec1_B);CHKERRQ(ierr);
1282     if (pcbddc->switch_static) { ierr = MatMultTransposeAdd(pcis->A_II,pcis->vec2_D,pcis->vec1_D,pcis->vec1_D);CHKERRQ(ierr); }
1283     ierr = VecScale(pcis->vec2_D,m_one);CHKERRQ(ierr);
1284     ierr = VecCopy(r,z);CHKERRQ(ierr);
1285     ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1286     ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1287     ierr = PCBDDCScalingRestriction(pc,z,pcis->vec1_B);CHKERRQ(ierr);
1288   } else {
1289     ierr = VecSet(pcis->vec1_D,zero);CHKERRQ(ierr);
1290     ierr = VecSet(pcis->vec2_D,zero);CHKERRQ(ierr);
1291     ierr = PCBDDCScalingRestriction(pc,r,pcis->vec1_B);CHKERRQ(ierr);
1292   }
1293 
1294   /* Apply interface preconditioner
1295      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1296   ierr = PCBDDCApplyInterfacePreconditioner(pc,PETSC_TRUE);CHKERRQ(ierr);
1297 
1298   /* Apply transpose of partition of unity operator */
1299   ierr = PCBDDCScalingExtension(pc,pcis->vec1_B,z);CHKERRQ(ierr);
1300 
1301   /* Second Dirichlet solve and assembling of output */
1302   ierr = VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1303   ierr = VecScatterEnd(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1304   ierr = MatMultTranspose(pcis->A_BI,pcis->vec1_B,pcis->vec3_D);CHKERRQ(ierr);
1305   if (pcbddc->switch_static) { ierr = MatMultTransposeAdd(pcis->A_II,pcis->vec1_D,pcis->vec3_D,pcis->vec3_D);CHKERRQ(ierr); }
1306   ierr = KSPSolveTranspose(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D);CHKERRQ(ierr);
1307   ierr = VecScale(pcis->vec4_D,m_one);CHKERRQ(ierr);
1308   if (pcbddc->switch_static) { ierr = VecAXPY(pcis->vec4_D,one,pcis->vec1_D);CHKERRQ(ierr); }
1309   ierr = VecAXPY(pcis->vec2_D,one,pcis->vec4_D);CHKERRQ(ierr);
1310   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1311   ierr = VecScatterEnd(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1312   PetscFunctionReturn(0);
1313 }
1314 /* -------------------------------------------------------------------------- */
1315 
1316 #undef __FUNCT__
1317 #define __FUNCT__ "PCDestroy_BDDC"
1318 PetscErrorCode PCDestroy_BDDC(PC pc)
1319 {
1320   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
1321   PetscErrorCode ierr;
1322 
1323   PetscFunctionBegin;
1324   /* free data created by PCIS */
1325   ierr = PCISDestroy(pc);CHKERRQ(ierr);
1326   /* free BDDC custom data  */
1327   ierr = PCBDDCResetCustomization(pc);CHKERRQ(ierr);
1328   /* destroy objects related to topography */
1329   ierr = PCBDDCResetTopography(pc);CHKERRQ(ierr);
1330   /* free allocated graph structure */
1331   ierr = PetscFree(pcbddc->mat_graph);CHKERRQ(ierr);
1332   /* free data for scaling operator */
1333   ierr = PCBDDCScalingDestroy(pc);CHKERRQ(ierr);
1334   /* free solvers stuff */
1335   ierr = PCBDDCResetSolvers(pc);CHKERRQ(ierr);
1336   /* free global vectors needed in presolve */
1337   ierr = VecDestroy(&pcbddc->temp_solution);CHKERRQ(ierr);
1338   ierr = VecDestroy(&pcbddc->original_rhs);CHKERRQ(ierr);
1339   ierr = ISLocalToGlobalMappingDestroy(&pcbddc->BtoNmap);CHKERRQ(ierr);
1340   /* remove functions */
1341   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",NULL);CHKERRQ(ierr);
1342   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",NULL);CHKERRQ(ierr);
1343   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",NULL);CHKERRQ(ierr);
1344   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",NULL);CHKERRQ(ierr);
1345   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",NULL);CHKERRQ(ierr);
1346   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",NULL);CHKERRQ(ierr);
1347   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1348   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",NULL);CHKERRQ(ierr);
1349   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1350   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",NULL);CHKERRQ(ierr);
1351   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",NULL);CHKERRQ(ierr);
1352   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",NULL);CHKERRQ(ierr);
1353   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",NULL);CHKERRQ(ierr);
1354   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",NULL);CHKERRQ(ierr);
1355   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",NULL);CHKERRQ(ierr);
1356   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",NULL);CHKERRQ(ierr);
1357   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",NULL);CHKERRQ(ierr);
1358   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",NULL);CHKERRQ(ierr);
1359   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",NULL);CHKERRQ(ierr);
1360   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",NULL);CHKERRQ(ierr);
1361   /* Free the private data structure */
1362   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1363   PetscFunctionReturn(0);
1364 }
1365 /* -------------------------------------------------------------------------- */
1366 
1367 #undef __FUNCT__
1368 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS_BDDC"
1369 static PetscErrorCode PCBDDCMatFETIDPGetRHS_BDDC(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1370 {
1371   FETIDPMat_ctx  mat_ctx;
1372   PC_IS*         pcis;
1373   PC_BDDC*       pcbddc;
1374   PetscErrorCode ierr;
1375 
1376   PetscFunctionBegin;
1377   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1378   pcis = (PC_IS*)mat_ctx->pc->data;
1379   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1380 
1381   /* change of basis for physical rhs if needed
1382      It also changes the rhs in case of dirichlet boundaries */
1383   ierr = PCPreSolve_BDDC(mat_ctx->pc,NULL,standard_rhs,NULL);CHKERRQ(ierr);
1384   /* store vectors for computation of fetidp final solution */
1385   ierr = VecScatterBegin(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1386   ierr = VecScatterEnd(pcis->global_to_D,standard_rhs,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1387   /* scale rhs since it should be unassembled */
1388   /* TODO use counter scaling? (also below) */
1389   ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1390   ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1391   /* Apply partition of unity */
1392   ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1393   /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1394   if (!pcbddc->switch_static) {
1395     /* compute partially subassembled Schur complement right-hand side */
1396     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1397     ierr = MatMult(pcis->A_BI,pcis->vec1_D,pcis->vec1_B);CHKERRQ(ierr);
1398     ierr = VecAXPY(mat_ctx->temp_solution_B,-1.0,pcis->vec1_B);CHKERRQ(ierr);
1399     ierr = VecSet(standard_rhs,0.0);CHKERRQ(ierr);
1400     ierr = VecScatterBegin(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1401     ierr = VecScatterEnd(pcis->global_to_B,mat_ctx->temp_solution_B,standard_rhs,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1402     /* ierr = PCBDDCScalingRestriction(mat_ctx->pc,standard_rhs,mat_ctx->temp_solution_B);CHKERRQ(ierr); */
1403     ierr = VecScatterBegin(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1404     ierr = VecScatterEnd(pcis->global_to_B,standard_rhs,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1405     ierr = VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1406   }
1407   /* BDDC rhs */
1408   ierr = VecCopy(mat_ctx->temp_solution_B,pcis->vec1_B);CHKERRQ(ierr);
1409   if (pcbddc->switch_static) {
1410     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1411   }
1412   /* apply BDDC */
1413   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc,PETSC_FALSE);CHKERRQ(ierr);
1414   /* Application of B_delta and assembling of rhs for fetidp fluxes */
1415   ierr = VecSet(fetidp_flux_rhs,0.0);CHKERRQ(ierr);
1416   ierr = MatMult(mat_ctx->B_delta,pcis->vec1_B,mat_ctx->lambda_local);CHKERRQ(ierr);
1417   ierr = VecScatterBegin(mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1418   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1419   /* restore original rhs */
1420   ierr = VecCopy(pcbddc->original_rhs,standard_rhs);CHKERRQ(ierr);
1421   PetscFunctionReturn(0);
1422 }
1423 
1424 #undef __FUNCT__
1425 #define __FUNCT__ "PCBDDCMatFETIDPGetRHS"
1426 /*@
1427  PCBDDCMatFETIDPGetRHS - Compute the right-hand side for FETIDP linear system
1428 
1429    Collective
1430 
1431    Input Parameters:
1432 +  fetidp_mat   - the FETIDP matrix object obtained by calling PCBDDCCreateFETIDPOperators
1433 .  standard_rhs - the right-hand side for your linear system
1434 
1435    Output Parameters:
1436 -  fetidp_flux_rhs   - the right-hand side for the FETIDP linear system
1437 
1438    Level: developer
1439 
1440    Notes:
1441 
1442 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1443 @*/
1444 PetscErrorCode PCBDDCMatFETIDPGetRHS(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
1445 {
1446   FETIDPMat_ctx  mat_ctx;
1447   PetscErrorCode ierr;
1448 
1449   PetscFunctionBegin;
1450   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1451   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetRHS_C",(Mat,Vec,Vec),(fetidp_mat,standard_rhs,fetidp_flux_rhs));CHKERRQ(ierr);
1452   PetscFunctionReturn(0);
1453 }
1454 /* -------------------------------------------------------------------------- */
1455 
1456 #undef __FUNCT__
1457 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution_BDDC"
1458 static PetscErrorCode PCBDDCMatFETIDPGetSolution_BDDC(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1459 {
1460   FETIDPMat_ctx  mat_ctx;
1461   PC_IS*         pcis;
1462   PC_BDDC*       pcbddc;
1463   PetscErrorCode ierr;
1464 
1465   PetscFunctionBegin;
1466   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1467   pcis = (PC_IS*)mat_ctx->pc->data;
1468   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
1469 
1470   /* apply B_delta^T */
1471   ierr = VecScatterBegin(mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1472   ierr = VecScatterEnd  (mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1473   ierr = MatMultTranspose(mat_ctx->B_delta,mat_ctx->lambda_local,pcis->vec1_B);CHKERRQ(ierr);
1474   /* compute rhs for BDDC application */
1475   ierr = VecAYPX(pcis->vec1_B,-1.0,mat_ctx->temp_solution_B);CHKERRQ(ierr);
1476   if (pcbddc->switch_static) {
1477     ierr = VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1478   }
1479   /* apply BDDC */
1480   ierr = PCBDDCApplyInterfacePreconditioner(mat_ctx->pc,PETSC_FALSE);CHKERRQ(ierr);
1481   /* put values into standard global vector */
1482   ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1483   ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1484   if (!pcbddc->switch_static) {
1485     /* compute values into the interior if solved for the partially subassembled Schur complement */
1486     ierr = MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec1_D);CHKERRQ(ierr);
1487     ierr = VecAXPY(mat_ctx->temp_solution_D,-1.0,pcis->vec1_D);CHKERRQ(ierr);
1488     ierr = KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D);CHKERRQ(ierr);
1489   }
1490   ierr = VecScatterBegin(pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1491   ierr = VecScatterEnd  (pcis->global_to_D,pcis->vec1_D,standard_sol,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1492   /* final change of basis if needed
1493      Is also sums the dirichlet part removed during RHS assembling */
1494   ierr = PCPostSolve_BDDC(mat_ctx->pc,NULL,NULL,standard_sol);CHKERRQ(ierr);
1495   PetscFunctionReturn(0);
1496 }
1497 
1498 #undef __FUNCT__
1499 #define __FUNCT__ "PCBDDCMatFETIDPGetSolution"
1500 /*@
1501  PCBDDCMatFETIDPGetSolution - Compute the physical solution from the solution of the FETIDP linear system
1502 
1503    Collective
1504 
1505    Input Parameters:
1506 +  fetidp_mat        - the FETIDP matrix obtained by calling PCBDDCCreateFETIDPOperators
1507 .  fetidp_flux_sol - the solution of the FETIDP linear system
1508 
1509    Output Parameters:
1510 -  standard_sol      - the solution defined on the physical domain
1511 
1512    Level: developer
1513 
1514    Notes:
1515 
1516 .seealso: PCBDDC,PCBDDCCreateFETIDPOperators
1517 @*/
1518 PetscErrorCode PCBDDCMatFETIDPGetSolution(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
1519 {
1520   FETIDPMat_ctx  mat_ctx;
1521   PetscErrorCode ierr;
1522 
1523   PetscFunctionBegin;
1524   ierr = MatShellGetContext(fetidp_mat,&mat_ctx);CHKERRQ(ierr);
1525   ierr = PetscTryMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetSolution_C",(Mat,Vec,Vec),(fetidp_mat,fetidp_flux_sol,standard_sol));CHKERRQ(ierr);
1526   PetscFunctionReturn(0);
1527 }
1528 /* -------------------------------------------------------------------------- */
1529 
1530 extern PetscErrorCode FETIDPMatMult(Mat,Vec,Vec);
1531 extern PetscErrorCode FETIDPMatMultTranspose(Mat,Vec,Vec);
1532 extern PetscErrorCode PCBDDCDestroyFETIDPMat(Mat);
1533 extern PetscErrorCode FETIDPPCApply(PC,Vec,Vec);
1534 extern PetscErrorCode FETIDPPCApplyTranspose(PC,Vec,Vec);
1535 extern PetscErrorCode PCBDDCDestroyFETIDPPC(PC);
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "PCBDDCCreateFETIDPOperators_BDDC"
1539 static PetscErrorCode PCBDDCCreateFETIDPOperators_BDDC(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1540 {
1541 
1542   FETIDPMat_ctx  fetidpmat_ctx;
1543   Mat            newmat;
1544   FETIDPPC_ctx   fetidppc_ctx;
1545   PC             newpc;
1546   MPI_Comm       comm;
1547   PetscErrorCode ierr;
1548 
1549   PetscFunctionBegin;
1550   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
1551   /* FETIDP linear matrix */
1552   ierr = PCBDDCCreateFETIDPMatContext(pc,&fetidpmat_ctx);CHKERRQ(ierr);
1553   ierr = PCBDDCSetupFETIDPMatContext(fetidpmat_ctx);CHKERRQ(ierr);
1554   ierr = MatCreateShell(comm,PETSC_DECIDE,PETSC_DECIDE,fetidpmat_ctx->n_lambda,fetidpmat_ctx->n_lambda,fetidpmat_ctx,&newmat);CHKERRQ(ierr);
1555   ierr = MatShellSetOperation(newmat,MATOP_MULT,(void (*)(void))FETIDPMatMult);CHKERRQ(ierr);
1556   ierr = MatShellSetOperation(newmat,MATOP_MULT_TRANSPOSE,(void (*)(void))FETIDPMatMultTranspose);CHKERRQ(ierr);
1557   ierr = MatShellSetOperation(newmat,MATOP_DESTROY,(void (*)(void))PCBDDCDestroyFETIDPMat);CHKERRQ(ierr);
1558   ierr = MatSetUp(newmat);CHKERRQ(ierr);
1559   /* FETIDP preconditioner */
1560   ierr = PCBDDCCreateFETIDPPCContext(pc,&fetidppc_ctx);CHKERRQ(ierr);
1561   ierr = PCBDDCSetupFETIDPPCContext(newmat,fetidppc_ctx);CHKERRQ(ierr);
1562   ierr = PCCreate(comm,&newpc);CHKERRQ(ierr);
1563   ierr = PCSetType(newpc,PCSHELL);CHKERRQ(ierr);
1564   ierr = PCShellSetContext(newpc,fetidppc_ctx);CHKERRQ(ierr);
1565   ierr = PCShellSetApply(newpc,FETIDPPCApply);CHKERRQ(ierr);
1566   ierr = PCShellSetApplyTranspose(newpc,FETIDPPCApplyTranspose);CHKERRQ(ierr);
1567   ierr = PCShellSetDestroy(newpc,PCBDDCDestroyFETIDPPC);CHKERRQ(ierr);
1568   ierr = PCSetOperators(newpc,newmat,newmat,SAME_PRECONDITIONER);CHKERRQ(ierr);
1569   ierr = PCSetUp(newpc);CHKERRQ(ierr);
1570   /* return pointers for objects created */
1571   *fetidp_mat=newmat;
1572   *fetidp_pc=newpc;
1573   PetscFunctionReturn(0);
1574 }
1575 
1576 #undef __FUNCT__
1577 #define __FUNCT__ "PCBDDCCreateFETIDPOperators"
1578 /*@
1579  PCBDDCCreateFETIDPOperators - Create operators for FETIDP
1580 
1581    Collective
1582 
1583    Input Parameters:
1584 +  pc - the BDDC preconditioning context already setup
1585 
1586    Output Parameters:
1587 .  fetidp_mat - shell FETIDP matrix object
1588 .  fetidp_pc  - shell Dirichlet preconditioner for FETIDP matrix
1589 
1590    Options Database Keys:
1591 -    -fetidp_fullyredundant: use or not a fully redundant set of Lagrange multipliers
1592 
1593    Level: developer
1594 
1595    Notes:
1596      Currently the only operation provided for FETIDP matrix is MatMult
1597 
1598 .seealso: PCBDDC
1599 @*/
1600 PetscErrorCode PCBDDCCreateFETIDPOperators(PC pc, Mat *fetidp_mat, PC *fetidp_pc)
1601 {
1602   PetscErrorCode ierr;
1603 
1604   PetscFunctionBegin;
1605   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1606   if (pc->setupcalled) {
1607     ierr = PetscUseMethod(pc,"PCBDDCCreateFETIDPOperators_C",(PC,Mat*,PC*),(pc,fetidp_mat,fetidp_pc));CHKERRQ(ierr);
1608   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"You must call PCSetup_BDDC() first \n");
1609   PetscFunctionReturn(0);
1610 }
1611 /* -------------------------------------------------------------------------- */
1612 /*MC
1613    PCBDDC - Balancing Domain Decomposition by Constraints.
1614 
1615    An implementation of the BDDC preconditioner based on
1616 
1617 .vb
1618    [1] C. R. Dohrmann. "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149-168, March 2007
1619    [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
1620    [3] J. Mandel, B. Sousedik, C. R. Dohrmann. "Multispace and Multilevel BDDC", http://arxiv.org/abs/0712.3977
1621 .ve
1622 
1623    The matrix to be preconditioned (Pmat) must be of type MATIS.
1624 
1625    Currently works with MATIS matrices with local Neumann matrices of type MATSEQAIJ, MATSEQBAIJ or MATSEQSBAIJ, either with real or complex numbers.
1626 
1627    It also works with unsymmetric and indefinite problems.
1628 
1629    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.
1630 
1631    Approximate local solvers are automatically adapted for singular linear problems (see [1]) if the user has provided the nullspace using PCBDDCSetNullSpace
1632 
1633    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
1634 
1635    Constraints can be customized by attaching a MatNullSpace object to the MATIS matrix via MatSetNearNullSpace.
1636 
1637    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.
1638 
1639    The PETSc implementation also supports multilevel BDDC [3]. Coarse grids are partitioned using MatPartitioning object.
1640 
1641    Options Database Keys:
1642 
1643 .    -pc_bddc_use_vertices <1> - use or not vertices in primal space
1644 .    -pc_bddc_use_edges <1> - use or not edges in primal space
1645 .    -pc_bddc_use_faces <0> - use or not faces in primal space
1646 .    -pc_bddc_use_change_of_basis <0> - use change of basis approach (on edges only)
1647 .    -pc_bddc_use_change_on_faces <0> - use change of basis approach on faces if change of basis has been requested
1648 .    -pc_bddc_switch_static <0> - switches from M_2 to M_3 operator (see reference article [1])
1649 .    -pc_bddc_levels <0> - maximum number of levels for multilevel
1650 .    -pc_bddc_coarsening_ratio - H/h ratio at the coarser level
1651 -    -pc_bddc_check_level <0> - set verbosity level of debugging output
1652 
1653    Options for Dirichlet, Neumann or coarse solver can be set with
1654 .vb
1655       -pc_bddc_dirichlet_
1656       -pc_bddc_neumann_
1657       -pc_bddc_coarse_
1658 .ve
1659    e.g -pc_bddc_dirichlet_ksp_type richardson -pc_bddc_dirichlet_pc_type gamg
1660 
1661    When using a multilevel approach, solvers' options at the N-th level can be specified as
1662 .vb
1663       -pc_bddc_dirichlet_lN_
1664       -pc_bddc_neumann_lN_
1665       -pc_bddc_coarse_lN_
1666 .ve
1667    Note that level number ranges from the finest 0 to the coarsest N.
1668 
1669    Level: intermediate
1670 
1671    Developer notes:
1672 
1673    New deluxe scaling operator will be available soon.
1674 
1675    Contributed by Stefano Zampini
1676 
1677 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,  MATIS
1678 M*/
1679 
1680 #undef __FUNCT__
1681 #define __FUNCT__ "PCCreate_BDDC"
1682 PETSC_EXTERN PetscErrorCode PCCreate_BDDC(PC pc)
1683 {
1684   PetscErrorCode      ierr;
1685   PC_BDDC             *pcbddc;
1686 
1687   PetscFunctionBegin;
1688   /* Creates the private data structure for this preconditioner and attach it to the PC object. */
1689   ierr      = PetscNewLog(pc,PC_BDDC,&pcbddc);CHKERRQ(ierr);
1690   pc->data  = (void*)pcbddc;
1691 
1692   /* create PCIS data structure */
1693   ierr = PCISCreate(pc);CHKERRQ(ierr);
1694 
1695   /* BDDC customization */
1696   pcbddc->use_vertices        = PETSC_TRUE;
1697   pcbddc->use_edges           = PETSC_TRUE;
1698   pcbddc->use_faces           = PETSC_FALSE;
1699   pcbddc->use_change_of_basis = PETSC_FALSE;
1700   pcbddc->use_change_on_faces = PETSC_FALSE;
1701   pcbddc->switch_static       = PETSC_FALSE;
1702   pcbddc->use_nnsp_true       = PETSC_FALSE; /* not yet exposed */
1703   pcbddc->dbg_flag            = 0;
1704 
1705   pcbddc->BtoNmap                    = 0;
1706   pcbddc->local_primal_size          = 0;
1707   pcbddc->n_vertices                 = 0;
1708   pcbddc->n_actual_vertices          = 0;
1709   pcbddc->n_constraints              = 0;
1710   pcbddc->primal_indices_local_idxs  = 0;
1711   pcbddc->recompute_topography       = PETSC_FALSE;
1712   pcbddc->coarse_size                = -1;
1713   pcbddc->new_primal_space           = PETSC_FALSE;
1714   pcbddc->new_primal_space_local     = PETSC_FALSE;
1715   pcbddc->global_primal_indices      = 0;
1716   pcbddc->onearnullspace             = 0;
1717   pcbddc->onearnullvecs_state        = 0;
1718   pcbddc->user_primal_vertices       = 0;
1719   pcbddc->NullSpace                  = 0;
1720   pcbddc->temp_solution              = 0;
1721   pcbddc->original_rhs               = 0;
1722   pcbddc->local_mat                  = 0;
1723   pcbddc->ChangeOfBasisMatrix        = 0;
1724   pcbddc->coarse_vec                 = 0;
1725   pcbddc->coarse_rhs                 = 0;
1726   pcbddc->coarse_ksp                 = 0;
1727   pcbddc->coarse_phi_B               = 0;
1728   pcbddc->coarse_phi_D               = 0;
1729   pcbddc->coarse_psi_B               = 0;
1730   pcbddc->coarse_psi_D               = 0;
1731   pcbddc->vec1_P                     = 0;
1732   pcbddc->vec1_R                     = 0;
1733   pcbddc->vec2_R                     = 0;
1734   pcbddc->local_auxmat1              = 0;
1735   pcbddc->local_auxmat2              = 0;
1736   pcbddc->R_to_B                     = 0;
1737   pcbddc->R_to_D                     = 0;
1738   pcbddc->ksp_D                      = 0;
1739   pcbddc->ksp_R                      = 0;
1740   pcbddc->NeumannBoundaries          = 0;
1741   pcbddc->NeumannBoundariesLocal     = 0;
1742   pcbddc->DirichletBoundaries        = 0;
1743   pcbddc->DirichletBoundariesLocal   = 0;
1744   pcbddc->user_provided_isfordofs    = PETSC_FALSE;
1745   pcbddc->n_ISForDofs                = 0;
1746   pcbddc->n_ISForDofsLocal           = 0;
1747   pcbddc->ISForDofs                  = 0;
1748   pcbddc->ISForDofsLocal             = 0;
1749   pcbddc->ConstraintMatrix           = 0;
1750   pcbddc->use_exact_dirichlet_trick  = PETSC_TRUE;
1751   pcbddc->coarse_loc_to_glob         = 0;
1752   pcbddc->coarsening_ratio           = 8;
1753   pcbddc->current_level              = 0;
1754   pcbddc->max_levels                 = 0;
1755   pcbddc->use_coarse_estimates       = PETSC_FALSE;
1756   pcbddc->coarse_subassembling       = 0;
1757   pcbddc->coarse_subassembling_init  = 0;
1758 
1759   /* create local graph structure */
1760   ierr = PCBDDCGraphCreate(&pcbddc->mat_graph);CHKERRQ(ierr);
1761 
1762   /* scaling */
1763   pcbddc->use_deluxe_scaling         = PETSC_FALSE;
1764   pcbddc->work_scaling               = 0;
1765 
1766   /* function pointers */
1767   pc->ops->apply               = PCApply_BDDC;
1768   pc->ops->applytranspose      = PCApplyTranspose_BDDC;
1769   pc->ops->setup               = PCSetUp_BDDC;
1770   pc->ops->destroy             = PCDestroy_BDDC;
1771   pc->ops->setfromoptions      = PCSetFromOptions_BDDC;
1772   pc->ops->view                = 0;
1773   pc->ops->applyrichardson     = 0;
1774   pc->ops->applysymmetricleft  = 0;
1775   pc->ops->applysymmetricright = 0;
1776   pc->ops->presolve            = PCPreSolve_BDDC;
1777   pc->ops->postsolve           = PCPostSolve_BDDC;
1778 
1779   /* composing function */
1780   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",PCBDDCSetPrimalVerticesLocalIS_BDDC);CHKERRQ(ierr);
1781   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",PCBDDCSetCoarseningRatio_BDDC);CHKERRQ(ierr);
1782   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",PCBDDCSetLevel_BDDC);CHKERRQ(ierr);
1783   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",PCBDDCSetUseExactDirichlet_BDDC);CHKERRQ(ierr);
1784   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",PCBDDCSetLevels_BDDC);CHKERRQ(ierr);
1785   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNullSpace_C",PCBDDCSetNullSpace_BDDC);CHKERRQ(ierr);
1786   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",PCBDDCSetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1787   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",PCBDDCSetDirichletBoundariesLocal_BDDC);CHKERRQ(ierr);
1788   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",PCBDDCSetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1789   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",PCBDDCSetNeumannBoundariesLocal_BDDC);CHKERRQ(ierr);
1790   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",PCBDDCGetDirichletBoundaries_BDDC);CHKERRQ(ierr);
1791   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",PCBDDCGetDirichletBoundariesLocal_BDDC);CHKERRQ(ierr);
1792   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",PCBDDCGetNeumannBoundaries_BDDC);CHKERRQ(ierr);
1793   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",PCBDDCGetNeumannBoundariesLocal_BDDC);CHKERRQ(ierr);
1794   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",PCBDDCSetDofsSplitting_BDDC);CHKERRQ(ierr);
1795   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",PCBDDCSetDofsSplittingLocal_BDDC);CHKERRQ(ierr);
1796   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",PCBDDCSetLocalAdjacencyGraph_BDDC);CHKERRQ(ierr);
1797   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",PCBDDCCreateFETIDPOperators_BDDC);CHKERRQ(ierr);
1798   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",PCBDDCMatFETIDPGetRHS_BDDC);CHKERRQ(ierr);
1799   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",PCBDDCMatFETIDPGetSolution_BDDC);CHKERRQ(ierr);
1800   PetscFunctionReturn(0);
1801 }
1802 
1803