xref: /petsc/src/ksp/pc/impls/is/pcis.c (revision 0e9bae810fdaeb60e2713eaa8ddb89f42e079fd1)
1 
2 #include "../src/ksp/pc/impls/is/pcis.h" /*I "petscpc.h" I*/
3 
4 EXTERN_C_BEGIN
5 #undef __FUNCT__
6 #define __FUNCT__ "PCISSetSubdomainDiagonalScaling_IS"
7 static PetscErrorCode PCISSetSubdomainDiagonalScaling_IS(PC pc, Vec scaling_factors)
8 {
9   PetscErrorCode ierr;
10   PC_IS  *pcis = (PC_IS*)pc->data;
11 
12   PetscFunctionBegin;
13   ierr = VecDestroy(&pcis->D);CHKERRQ(ierr);
14   ierr = PetscObjectReference((PetscObject)scaling_factors);CHKERRQ(ierr);
15   pcis->D = scaling_factors;
16   PetscFunctionReturn(0);
17 }
18 EXTERN_C_END
19 
20 #undef __FUNCT__
21 #define __FUNCT__ "PCISSetSubdomainDiagonalScaling"
22 /*@
23  PCISSetSubdomainDiagonalScaling - Set diagonal scaling for PCIS.
24 
25    Not collective
26 
27    Input Parameters:
28 +  pc - the preconditioning context
29 -  scaling_factors - scaling factors for the subdomain
30 
31    Level: intermediate
32 
33    Notes:
34    Intended to use with jumping coefficients cases.
35 
36 .seealso: PCBDDC
37 @*/
38 PetscErrorCode PCISSetSubdomainDiagonalScaling(PC pc, Vec scaling_factors)
39 {
40   PetscErrorCode ierr;
41 
42   PetscFunctionBegin;
43   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
44   ierr = PetscTryMethod(pc,"PCISSetSubdomainDiagonalScaling_C",(PC,Vec),(pc,scaling_factors));CHKERRQ(ierr);
45   PetscFunctionReturn(0);
46 }
47 
48 EXTERN_C_BEGIN
49 #undef __FUNCT__
50 #define __FUNCT__ "PCISSetSubdomainScalingFactor_IS"
51 static PetscErrorCode PCISSetSubdomainScalingFactor_IS(PC pc, PetscScalar scal)
52 {
53   PC_IS  *pcis = (PC_IS*)pc->data;
54 
55   PetscFunctionBegin;
56   pcis->scaling_factor = scal;
57   PetscFunctionReturn(0);
58 }
59 EXTERN_C_END
60 
61 #undef __FUNCT__
62 #define __FUNCT__ "PCISSetSubdomainScalingFactor"
63 /*@
64  PCISSetSubdomainScalingFactor - Set scaling factor for PCIS.
65 
66    Not collective
67 
68    Input Parameters:
69 +  pc - the preconditioning context
70 -  scal - scaling factor for the subdomain
71 
72    Level: intermediate
73 
74    Notes:
75    Intended to use with jumping coefficients cases.
76 
77 .seealso: PCBDDC
78 @*/
79 PetscErrorCode PCISSetSubdomainScalingFactor(PC pc, PetscScalar scal)
80 {
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
85   ierr = PetscTryMethod(pc,"PCISSetSubdomainScalingFactor_C",(PC,PetscScalar),(pc,scal));CHKERRQ(ierr);
86   PetscFunctionReturn(0);
87 }
88 
89 
90 /* -------------------------------------------------------------------------- */
91 /*
92    PCISSetUp -
93 */
94 #undef __FUNCT__
95 #define __FUNCT__ "PCISSetUp"
96 PetscErrorCode  PCISSetUp(PC pc)
97 {
98   PC_IS           *pcis = (PC_IS*)(pc->data);
99   Mat_IS          *matis = (Mat_IS*)pc->mat->data;
100   PetscInt        i;
101   PetscErrorCode  ierr;
102   PetscBool       flg;
103   Vec    counter;
104 
105   PetscFunctionBegin;
106   ierr = PetscObjectTypeCompare((PetscObject)pc->mat,MATIS,&flg);CHKERRQ(ierr);
107   if (!flg) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG,"Preconditioner type of Neumann Neumman requires matrix of type MATIS");
108 
109   pcis->pure_neumann = matis->pure_neumann;
110 
111   /*
112     Creating the local vector vec1_N, containing the inverse of the number
113     of subdomains to which each local node (either owned or ghost)
114     pertains. To accomplish that, we scatter local vectors of 1's to
115     a global vector (adding the values); scatter the result back to
116     local vectors and finally invert the result.
117   */
118   ierr = VecDuplicate(matis->x,&pcis->vec1_N);CHKERRQ(ierr);
119   ierr = MatGetVecs(pc->pmat,&counter,0);CHKERRQ(ierr); /* temporary auxiliar vector */
120   ierr = VecSet(counter,0.0);CHKERRQ(ierr);
121   ierr = VecSet(pcis->vec1_N,1.0);CHKERRQ(ierr);
122   ierr = VecScatterBegin(matis->ctx,pcis->vec1_N,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
123   ierr = VecScatterEnd  (matis->ctx,pcis->vec1_N,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
124   ierr = VecScatterBegin(matis->ctx,counter,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
125   ierr = VecScatterEnd  (matis->ctx,counter,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
126   /*
127     Creating local and global index sets for interior and
128     inteface nodes. Notice that interior nodes have D[i]==1.0.
129   */
130   {
131     PetscInt     n_I;
132     PetscInt    *idx_I_local,*idx_B_local,*idx_I_global,*idx_B_global;
133     PetscScalar *array;
134     /* Identifying interior and interface nodes, in local numbering */
135     ierr = VecGetSize(pcis->vec1_N,&pcis->n);CHKERRQ(ierr);
136     ierr = VecGetArray(pcis->vec1_N,&array);CHKERRQ(ierr);
137     ierr = PetscMalloc(pcis->n*sizeof(PetscInt),&idx_I_local);CHKERRQ(ierr);
138     ierr = PetscMalloc(pcis->n*sizeof(PetscInt),&idx_B_local);CHKERRQ(ierr);
139     for (i=0, pcis->n_B=0, n_I=0; i<pcis->n; i++) {
140       if (array[i] == 1.0) { idx_I_local[n_I]       = i; n_I++;       }
141       else                 { idx_B_local[pcis->n_B] = i; pcis->n_B++; }
142     }
143     /* Getting the global numbering */
144     idx_B_global = idx_I_local + n_I; /* Just avoiding allocating extra memory, since we have vacant space */
145     idx_I_global = idx_B_local + pcis->n_B;
146     ierr = ISLocalToGlobalMappingApply(matis->mapping,pcis->n_B,idx_B_local,idx_B_global);CHKERRQ(ierr);
147     ierr = ISLocalToGlobalMappingApply(matis->mapping,n_I,      idx_I_local,idx_I_global);CHKERRQ(ierr);
148     /* Creating the index sets. */
149     ierr = ISCreateGeneral(MPI_COMM_SELF,pcis->n_B,idx_B_local,PETSC_COPY_VALUES, &pcis->is_B_local);CHKERRQ(ierr);
150     ierr = ISCreateGeneral(MPI_COMM_SELF,pcis->n_B,idx_B_global,PETSC_COPY_VALUES,&pcis->is_B_global);CHKERRQ(ierr);
151     ierr = ISCreateGeneral(MPI_COMM_SELF,n_I      ,idx_I_local,PETSC_COPY_VALUES, &pcis->is_I_local);CHKERRQ(ierr);
152     ierr = ISCreateGeneral(MPI_COMM_SELF,n_I      ,idx_I_global,PETSC_COPY_VALUES,&pcis->is_I_global);CHKERRQ(ierr);
153     /* Freeing memory and restoring arrays */
154     ierr = PetscFree(idx_B_local);CHKERRQ(ierr);
155     ierr = PetscFree(idx_I_local);CHKERRQ(ierr);
156     ierr = VecRestoreArray(pcis->vec1_N,&array);CHKERRQ(ierr);
157   }
158 
159   /*
160     Extracting the blocks A_II, A_BI, A_IB and A_BB from A. If the numbering
161     is such that interior nodes come first than the interface ones, we have
162 
163     [           |      ]
164     [    A_II   | A_IB ]
165     A = [           |      ]
166     [-----------+------]
167     [    A_BI   | A_BB ]
168   */
169 
170   ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_I_local,MAT_INITIAL_MATRIX,&pcis->A_II);CHKERRQ(ierr);
171   ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&pcis->A_IB);CHKERRQ(ierr);
172   ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_I_local,MAT_INITIAL_MATRIX,&pcis->A_BI);CHKERRQ(ierr);
173   ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&pcis->A_BB);CHKERRQ(ierr);
174 
175   /*
176     Creating work vectors and arrays
177   */
178   /* pcis->vec1_N has already been created */
179   ierr = VecDuplicate(pcis->vec1_N,&pcis->vec2_N);CHKERRQ(ierr);
180   ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n-pcis->n_B,&pcis->vec1_D);CHKERRQ(ierr);
181   ierr = VecDuplicate(pcis->vec1_D,&pcis->vec2_D);CHKERRQ(ierr);
182   ierr = VecDuplicate(pcis->vec1_D,&pcis->vec3_D);CHKERRQ(ierr);
183   ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n_B,&pcis->vec1_B);CHKERRQ(ierr);
184   ierr = VecDuplicate(pcis->vec1_B,&pcis->vec2_B);CHKERRQ(ierr);
185   ierr = VecDuplicate(pcis->vec1_B,&pcis->vec3_B);CHKERRQ(ierr);
186   ierr = MatGetVecs(pc->pmat,&pcis->vec1_global,0);CHKERRQ(ierr);
187   ierr = PetscMalloc((pcis->n)*sizeof(PetscScalar),&pcis->work_N);CHKERRQ(ierr);
188 
189   /* Creating the scatter contexts */
190   ierr = VecScatterCreate(pcis->vec1_global,pcis->is_I_global,pcis->vec1_D,(IS)0,&pcis->global_to_D);CHKERRQ(ierr);
191   ierr = VecScatterCreate(pcis->vec1_N,pcis->is_B_local,pcis->vec1_B,(IS)0,&pcis->N_to_B);CHKERRQ(ierr);
192   ierr = VecScatterCreate(pcis->vec1_global,pcis->is_B_global,pcis->vec1_B,(IS)0,&pcis->global_to_B);CHKERRQ(ierr);
193 
194   /* Creating scaling "matrix" D */
195   if( !pcis->D ) {
196     ierr = VecSet(pcis->vec1_B,pcis->scaling_factor);CHKERRQ(ierr);
197   } else {
198     ierr = VecCopy(pcis->D,pcis->vec1_B);CHKERRQ(ierr);
199   }
200   ierr = VecSet(counter,0.0);CHKERRQ(ierr);
201   ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
202   ierr = VecScatterEnd  (pcis->global_to_B,pcis->vec1_B,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
203   ierr = VecScatterBegin(pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
204   ierr = VecScatterEnd  (pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
205   if( !pcis->D ) {
206     ierr = VecDuplicate(pcis->vec1_B,&pcis->D);CHKERRQ(ierr);
207     ierr = VecCopy(pcis->vec1_B,pcis->D);CHKERRQ(ierr);
208     ierr = VecReciprocal(pcis->D);CHKERRQ(ierr);
209     ierr = VecScale(pcis->D,pcis->scaling_factor);CHKERRQ(ierr);
210   } else {
211     ierr = VecPointwiseDivide(pcis->D,pcis->D,pcis->vec1_B);CHKERRQ(ierr);
212   }
213 
214   /* See historical note 01, at the bottom of this file. */
215 
216   /*
217     Creating the KSP contexts for the local Dirichlet and Neumann problems.
218   */
219   {
220     PC  pc_ctx;
221     /* Dirichlet */
222     ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_D);CHKERRQ(ierr);
223     ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_D,(PetscObject)pc,1);CHKERRQ(ierr);
224     ierr = KSPSetOperators(pcis->ksp_D,pcis->A_II,pcis->A_II,SAME_PRECONDITIONER);CHKERRQ(ierr);
225     ierr = KSPSetOptionsPrefix(pcis->ksp_D,"is_localD_");CHKERRQ(ierr);
226     ierr = KSPGetPC(pcis->ksp_D,&pc_ctx);CHKERRQ(ierr);
227     ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr);
228     ierr = KSPSetType(pcis->ksp_D,KSPPREONLY);CHKERRQ(ierr);
229     ierr = KSPSetFromOptions(pcis->ksp_D);CHKERRQ(ierr);
230     /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */
231     ierr = KSPSetUp(pcis->ksp_D);CHKERRQ(ierr);
232     /* Neumann */
233     ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_N);CHKERRQ(ierr);
234     ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_N,(PetscObject)pc,1);CHKERRQ(ierr);
235     ierr = KSPSetOperators(pcis->ksp_N,matis->A,matis->A,SAME_PRECONDITIONER);CHKERRQ(ierr);
236     ierr = KSPSetOptionsPrefix(pcis->ksp_N,"is_localN_");CHKERRQ(ierr);
237     ierr = KSPGetPC(pcis->ksp_N,&pc_ctx);CHKERRQ(ierr);
238     ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr);
239     ierr = KSPSetType(pcis->ksp_N,KSPPREONLY);CHKERRQ(ierr);
240     ierr = KSPSetFromOptions(pcis->ksp_N);CHKERRQ(ierr);
241     {
242       PetscBool  damp_fixed = PETSC_FALSE,
243                  remove_nullspace_fixed = PETSC_FALSE,
244                  set_damping_factor_floating = PETSC_FALSE,
245                  not_damp_floating = PETSC_FALSE,
246                  not_remove_nullspace_floating = PETSC_FALSE;
247       PetscReal  fixed_factor,
248                  floating_factor;
249 
250       ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&fixed_factor,&damp_fixed);CHKERRQ(ierr);
251       if (!damp_fixed) { fixed_factor = 0.0; }
252       ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&damp_fixed,PETSC_NULL);CHKERRQ(ierr);
253 
254       ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->prefix,"-pc_is_remove_nullspace_fixed",&remove_nullspace_fixed,PETSC_NULL);CHKERRQ(ierr);
255 
256       ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating",
257 			      &floating_factor,&set_damping_factor_floating);CHKERRQ(ierr);
258       if (!set_damping_factor_floating) { floating_factor = 0.0; }
259       ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating",&set_damping_factor_floating,PETSC_NULL);CHKERRQ(ierr);
260       if (!set_damping_factor_floating) { floating_factor = 1.e-12; }
261 
262       ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->prefix,"-pc_is_not_damp_floating",&not_damp_floating,PETSC_NULL);CHKERRQ(ierr);
263 
264       ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->prefix,"-pc_is_not_remove_nullspace_floating",&not_remove_nullspace_floating,PETSC_NULL);CHKERRQ(ierr);
265 
266       if (pcis->pure_neumann) {  /* floating subdomain */
267 	if (!(not_damp_floating)) {
268           ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr);
269           ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr);
270 	}
271 	if (!(not_remove_nullspace_floating)){
272 	  MatNullSpace nullsp;
273 	  ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,PETSC_NULL,&nullsp);CHKERRQ(ierr);
274 	  ierr = KSPSetNullSpace(pcis->ksp_N,nullsp);CHKERRQ(ierr);
275 	  ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr);
276 	}
277       } else {  /* fixed subdomain */
278 	if (damp_fixed) {
279           ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr);
280           ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr);
281 	}
282 	if (remove_nullspace_fixed) {
283 	  MatNullSpace nullsp;
284 	  ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,PETSC_NULL,&nullsp);CHKERRQ(ierr);
285 	  ierr = KSPSetNullSpace(pcis->ksp_N,nullsp);CHKERRQ(ierr);
286 	  ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr);
287 	}
288       }
289     }
290     /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */
291     ierr = KSPSetUp(pcis->ksp_N);CHKERRQ(ierr);
292   }
293 
294   ierr = ISLocalToGlobalMappingGetInfo(((Mat_IS*)(pc->mat->data))->mapping,&(pcis->n_neigh),&(pcis->neigh),&(pcis->n_shared),&(pcis->shared));CHKERRQ(ierr);
295   pcis->ISLocalToGlobalMappingGetInfoWasCalled = PETSC_TRUE;
296   ierr = VecDestroy(&counter);CHKERRQ(ierr);
297   PetscFunctionReturn(0);
298 }
299 
300 /* -------------------------------------------------------------------------- */
301 /*
302    PCISDestroy -
303 */
304 #undef __FUNCT__
305 #define __FUNCT__ "PCISDestroy"
306 PetscErrorCode  PCISDestroy(PC pc)
307 {
308   PC_IS          *pcis = (PC_IS*)(pc->data);
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = ISDestroy(&pcis->is_B_local);CHKERRQ(ierr);
313   ierr = ISDestroy(&pcis->is_I_local);CHKERRQ(ierr);
314   ierr = ISDestroy(&pcis->is_B_global);CHKERRQ(ierr);
315   ierr = ISDestroy(&pcis->is_I_global);CHKERRQ(ierr);
316   ierr = MatDestroy(&pcis->A_II);CHKERRQ(ierr);
317   ierr = MatDestroy(&pcis->A_IB);CHKERRQ(ierr);
318   ierr = MatDestroy(&pcis->A_BI);CHKERRQ(ierr);
319   ierr = MatDestroy(&pcis->A_BB);CHKERRQ(ierr);
320   ierr = VecDestroy(&pcis->D);CHKERRQ(ierr);
321   ierr = KSPDestroy(&pcis->ksp_N);CHKERRQ(ierr);
322   ierr = KSPDestroy(&pcis->ksp_D);CHKERRQ(ierr);
323   ierr = VecDestroy(&pcis->vec1_N);CHKERRQ(ierr);
324   ierr = VecDestroy(&pcis->vec2_N);CHKERRQ(ierr);
325   ierr = VecDestroy(&pcis->vec1_D);CHKERRQ(ierr);
326   ierr = VecDestroy(&pcis->vec2_D);CHKERRQ(ierr);
327   ierr = VecDestroy(&pcis->vec3_D);CHKERRQ(ierr);
328   ierr = VecDestroy(&pcis->vec1_B);CHKERRQ(ierr);
329   ierr = VecDestroy(&pcis->vec2_B);CHKERRQ(ierr);
330   ierr = VecDestroy(&pcis->vec3_B);CHKERRQ(ierr);
331   ierr = VecDestroy(&pcis->vec1_global);CHKERRQ(ierr);
332   ierr = VecScatterDestroy(&pcis->global_to_D);CHKERRQ(ierr);
333   ierr = VecScatterDestroy(&pcis->N_to_B);CHKERRQ(ierr);
334   ierr = VecScatterDestroy(&pcis->global_to_B);CHKERRQ(ierr);
335   ierr = PetscFree(pcis->work_N);CHKERRQ(ierr);
336   if (pcis->ISLocalToGlobalMappingGetInfoWasCalled) {
337     ierr = ISLocalToGlobalMappingRestoreInfo((ISLocalToGlobalMapping)0,&(pcis->n_neigh),&(pcis->neigh),&(pcis->n_shared),&(pcis->shared));CHKERRQ(ierr);
338   }
339   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCISSetSubdomainScalingFactor_C","",PETSC_NULL);CHKERRQ(ierr);
340   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCISSetSubdomainDiagonalScaling_C","",PETSC_NULL);CHKERRQ(ierr);
341   PetscFunctionReturn(0);
342 }
343 
344 /* -------------------------------------------------------------------------- */
345 /*
346    PCISCreate -
347 */
348 #undef __FUNCT__
349 #define __FUNCT__ "PCISCreate"
350 PetscErrorCode  PCISCreate(PC pc)
351 {
352   PC_IS *pcis = (PC_IS*)(pc->data);
353   PetscErrorCode ierr;
354 
355   PetscFunctionBegin;
356   pcis->is_B_local  = 0;
357   pcis->is_I_local  = 0;
358   pcis->is_B_global = 0;
359   pcis->is_I_global = 0;
360   pcis->A_II        = 0;
361   pcis->A_IB        = 0;
362   pcis->A_BI        = 0;
363   pcis->A_BB        = 0;
364   pcis->D           = 0;
365   pcis->ksp_N      = 0;
366   pcis->ksp_D      = 0;
367   pcis->vec1_N      = 0;
368   pcis->vec2_N      = 0;
369   pcis->vec1_D      = 0;
370   pcis->vec2_D      = 0;
371   pcis->vec3_D      = 0;
372   pcis->vec1_B      = 0;
373   pcis->vec2_B      = 0;
374   pcis->vec3_B      = 0;
375   pcis->vec1_global = 0;
376   pcis->work_N      = 0;
377   pcis->global_to_D = 0;
378   pcis->N_to_B      = 0;
379   pcis->global_to_B = 0;
380   pcis->ISLocalToGlobalMappingGetInfoWasCalled = PETSC_FALSE;
381   pcis->scaling_factor = 1.0;
382   /* composing functions */
383   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCISSetSubdomainScalingFactor_C","PCISSetSubdomainScalingFactor_IS",
384                     PCISSetSubdomainScalingFactor_IS);CHKERRQ(ierr);
385   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCISSetSubdomainDiagonalScaling_C","PCISSetSubdomainDiagonalScaling_IS",
386                     PCISSetSubdomainDiagonalScaling_IS);CHKERRQ(ierr);
387   PetscFunctionReturn(0);
388 }
389 
390 /* -------------------------------------------------------------------------- */
391 /*
392    PCISApplySchur -
393 
394    Input parameters:
395 .  pc - preconditioner context
396 .  v - vector to which the Schur complement is to be applied (it is NOT modified inside this function, UNLESS vec2_B is null)
397 
398    Output parameters:
399 .  vec1_B - result of Schur complement applied to chunk
400 .  vec2_B - garbage (used as work space), or null (and v is used as workspace)
401 .  vec1_D - garbage (used as work space)
402 .  vec2_D - garbage (used as work space)
403 
404 */
405 #undef __FUNCT__
406 #define __FUNCT__ "PCISApplySchur"
407 PetscErrorCode  PCISApplySchur(PC pc, Vec v, Vec vec1_B, Vec vec2_B, Vec vec1_D, Vec vec2_D)
408 {
409   PetscErrorCode ierr;
410   PC_IS          *pcis = (PC_IS*)(pc->data);
411 
412   PetscFunctionBegin;
413   if (!vec2_B) { vec2_B = v; }
414 
415   ierr = MatMult(pcis->A_BB,v,vec1_B);CHKERRQ(ierr);
416   ierr = MatMult(pcis->A_IB,v,vec1_D);CHKERRQ(ierr);
417   ierr = KSPSolve(pcis->ksp_D,vec1_D,vec2_D);CHKERRQ(ierr);
418   ierr = MatMult(pcis->A_BI,vec2_D,vec2_B);CHKERRQ(ierr);
419   ierr = VecAXPY(vec1_B,-1.0,vec2_B);CHKERRQ(ierr);
420   PetscFunctionReturn(0);
421 }
422 
423 /* -------------------------------------------------------------------------- */
424 /*
425    PCISScatterArrayNToVecB - Scatters interface node values from a big array (of all local nodes, interior or interface,
426    including ghosts) into an interface vector, when in SCATTER_FORWARD mode, or vice-versa, when in SCATTER_REVERSE
427    mode.
428 
429    Input parameters:
430 .  pc - preconditioner context
431 .  array_N - [when in SCATTER_FORWARD mode] Array to be scattered into the vector
432 .  v_B - [when in SCATTER_REVERSE mode] Vector to be scattered into the array
433 
434    Output parameter:
435 .  array_N - [when in SCATTER_REVERSE mode] Array to receive the scattered vector
436 .  v_B - [when in SCATTER_FORWARD mode] Vector to receive the scattered array
437 
438    Notes:
439    The entries in the array that do not correspond to interface nodes remain unaltered.
440 */
441 #undef __FUNCT__
442 #define __FUNCT__ "PCISScatterArrayNToVecB"
443 PetscErrorCode  PCISScatterArrayNToVecB (PetscScalar *array_N, Vec v_B, InsertMode imode, ScatterMode smode, PC pc)
444 {
445   PetscInt       i;
446   const PetscInt *idex;
447   PetscErrorCode ierr;
448   PetscScalar    *array_B;
449   PC_IS          *pcis = (PC_IS*)(pc->data);
450 
451   PetscFunctionBegin;
452   ierr = VecGetArray(v_B,&array_B);CHKERRQ(ierr);
453   ierr = ISGetIndices(pcis->is_B_local,&idex);CHKERRQ(ierr);
454 
455   if (smode == SCATTER_FORWARD) {
456     if (imode == INSERT_VALUES) {
457       for (i=0; i<pcis->n_B; i++) { array_B[i]  = array_N[idex[i]]; }
458     } else {  /* ADD_VALUES */
459       for (i=0; i<pcis->n_B; i++) { array_B[i] += array_N[idex[i]]; }
460     }
461   } else {  /* SCATTER_REVERSE */
462     if (imode == INSERT_VALUES) {
463       for (i=0; i<pcis->n_B; i++) { array_N[idex[i]]  = array_B[i]; }
464     } else {  /* ADD_VALUES */
465       for (i=0; i<pcis->n_B; i++) { array_N[idex[i]] += array_B[i]; }
466     }
467   }
468   ierr = ISRestoreIndices(pcis->is_B_local,&idex);CHKERRQ(ierr);
469   ierr = VecRestoreArray(v_B,&array_B);CHKERRQ(ierr);
470   PetscFunctionReturn(0);
471 }
472 
473 /* -------------------------------------------------------------------------- */
474 /*
475    PCISApplyInvSchur - Solves the Neumann problem related to applying the inverse of the Schur complement.
476    More precisely, solves the problem:
477                                         [ A_II  A_IB ] [ . ]   [ 0 ]
478                                         [            ] [   ] = [   ]
479                                         [ A_BI  A_BB ] [ x ]   [ b ]
480 
481    Input parameters:
482 .  pc - preconditioner context
483 .  b - vector of local interface nodes (including ghosts)
484 
485    Output parameters:
486 .  x - vector of local interface nodes (including ghosts); returns the application of the inverse of the Schur
487        complement to b
488 .  vec1_N - vector of local nodes (interior and interface, including ghosts); returns garbage (used as work space)
489 .  vec2_N - vector of local nodes (interior and interface, including ghosts); returns garbage (used as work space)
490 
491 */
492 #undef __FUNCT__
493 #define __FUNCT__ "PCISApplyInvSchur"
494 PetscErrorCode  PCISApplyInvSchur (PC pc, Vec b, Vec x, Vec vec1_N, Vec vec2_N)
495 {
496   PetscErrorCode ierr;
497   PC_IS          *pcis = (PC_IS*)(pc->data);
498 
499   PetscFunctionBegin;
500   /*
501     Neumann solvers.
502     Applying the inverse of the local Schur complement, i.e, solving a Neumann
503     Problem with zero at the interior nodes of the RHS and extracting the interface
504     part of the solution. inverse Schur complement is applied to b and the result
505     is stored in x.
506   */
507   /* Setting the RHS vec1_N */
508   ierr = VecSet(vec1_N,0.0);CHKERRQ(ierr);
509   ierr = VecScatterBegin(pcis->N_to_B,b,vec1_N,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
510   ierr = VecScatterEnd  (pcis->N_to_B,b,vec1_N,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
511   /* Checking for consistency of the RHS */
512   {
513     PetscBool  flg = PETSC_FALSE;
514     ierr = PetscOptionsGetBool(PETSC_NULL,"-pc_is_check_consistency",&flg,PETSC_NULL);CHKERRQ(ierr);
515     if (flg) {
516       PetscScalar average;
517       PetscViewer viewer;
518       ierr = PetscViewerASCIIGetStdout(((PetscObject)pc)->comm,&viewer);CHKERRQ(ierr);
519 
520       ierr = VecSum(vec1_N,&average);CHKERRQ(ierr);
521       average = average / ((PetscReal)pcis->n);
522       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
523       if (pcis->pure_neumann) {
524         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Subdomain %04d is floating. Average = % 1.14e\n",PetscGlobalRank,PetscAbsScalar(average));CHKERRQ(ierr);
525       } else {
526         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Subdomain %04d is fixed.    Average = % 1.14e\n",PetscGlobalRank,PetscAbsScalar(average));CHKERRQ(ierr);
527       }
528       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
529       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
530     }
531   }
532   /* Solving the system for vec2_N */
533   ierr = KSPSolve(pcis->ksp_N,vec1_N,vec2_N);CHKERRQ(ierr);
534   /* Extracting the local interface vector out of the solution */
535   ierr = VecScatterBegin(pcis->N_to_B,vec2_N,x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
536   ierr = VecScatterEnd  (pcis->N_to_B,vec2_N,x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
537   PetscFunctionReturn(0);
538 }
539 
540 
541 
542 
543 
544 
545 
546 
547 
548