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