xref: /petsc/src/ksp/pc/impls/bddc/bddcgraph.c (revision 5b1b9aea142b601757be3eaa4fa8e2a0641097a1)
1 #include <petsc-private/petscimpl.h>
2 #include <../src/ksp/pc/impls/bddc/bddcprivate.h>
3 #include <../src/ksp/pc/impls/bddc/bddcstructs.h>
4 
5 /* special marks: they cannot be enums, since special marks should in principle range from -4 to -max_int */
6 #define NEUMANN_MARK -1
7 #define DIRICHLET_MARK -2
8 #define LOCAL_PERIODIC_MARK -3
9 #define SPECIAL_MARK -4
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "PCBDDCGraphASCIIView"
13 PetscErrorCode PCBDDCGraphASCIIView(PCBDDCGraph graph, PetscInt verbosity_level, PetscViewer viewer)
14 {
15   PetscInt       i,j,tabs;
16   PetscInt*      queue_in_global_numbering;
17   PetscErrorCode ierr;
18 
19   PetscFunctionBegin;
20   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
21   ierr = PetscViewerASCIIGetTab(viewer,&tabs);CHKERRQ(ierr);
22   ierr = PetscViewerASCIIPrintf(viewer,"--------------------------------------------------\n");CHKERRQ(ierr);
23   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
24   ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Local BDDC graph for subdomain %04d\n",PetscGlobalRank);CHKERRQ(ierr);
25   ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Number of vertices %d\n",graph->nvtxs);CHKERRQ(ierr);
26   if (verbosity_level > 1) {
27     for (i=0;i<graph->nvtxs;i++) {
28       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"%d:\n",i);CHKERRQ(ierr);
29       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   which_dof: %d\n",graph->which_dof[i]);CHKERRQ(ierr);
30       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   special_dof: %d\n",graph->special_dof[i]);CHKERRQ(ierr);
31       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   neighbours: %d\n",graph->count[i]);CHKERRQ(ierr);
32       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
33       if (graph->count[i]) {
34         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"     set of neighbours:");CHKERRQ(ierr);
35         for (j=0;j<graph->count[i];j++) {
36           ierr = PetscViewerASCIISynchronizedPrintf(viewer," %d",graph->neighbours_set[i][j]);CHKERRQ(ierr);
37         }
38         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
39       }
40       ierr = PetscViewerASCIISetTab(viewer,tabs);CHKERRQ(ierr);
41       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
42       if (graph->mirrors) {
43         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   mirrors: %d\n",graph->mirrors[i]);CHKERRQ(ierr);
44         if (graph->mirrors[i]) {
45           ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
46           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"     set of mirrors:");CHKERRQ(ierr);
47           for (j=0;j<graph->mirrors[i];j++) {
48             ierr = PetscViewerASCIISynchronizedPrintf(viewer," %d",graph->mirrors_set[i][j]);CHKERRQ(ierr);
49           }
50           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
51           ierr = PetscViewerASCIISetTab(viewer,tabs);CHKERRQ(ierr);
52           ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
53         }
54       }
55       if (verbosity_level > 2) {
56         if (graph->xadj && graph->adjncy) {
57           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   local adj list:");CHKERRQ(ierr);
58           ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
59           for (j=graph->xadj[i];j<graph->xadj[i+1];j++) {
60             ierr = PetscViewerASCIISynchronizedPrintf(viewer," %d",graph->adjncy[j]);CHKERRQ(ierr);
61           }
62           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
63           ierr = PetscViewerASCIISetTab(viewer,tabs);CHKERRQ(ierr);
64           ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
65         }
66       }
67       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   interface subset id: %d\n",graph->subset[i]);CHKERRQ(ierr);
68       if (graph->subset[i] && graph->subset_ncc) {
69         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"   ncc for subset: %d\n",graph->subset_ncc[graph->subset[i]-1]);CHKERRQ(ierr);
70       }
71     }
72   }
73   ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Total number of connected components %d\n",graph->ncc);CHKERRQ(ierr);
74   ierr = PetscMalloc1(graph->cptr[graph->ncc],&queue_in_global_numbering);CHKERRQ(ierr);
75   ierr = ISLocalToGlobalMappingApply(graph->l2gmap,graph->cptr[graph->ncc],graph->queue,queue_in_global_numbering);CHKERRQ(ierr);
76   for (i=0;i<graph->ncc;i++) {
77     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"  %d (neighs:",i);CHKERRQ(ierr);
78     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
79     PetscInt node_num=graph->queue[graph->cptr[i]];
80     for (j=0;j<graph->count[node_num];j++) {
81       ierr = PetscViewerASCIISynchronizedPrintf(viewer," %d",graph->neighbours_set[node_num][j]);CHKERRQ(ierr);
82     }
83     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"):");CHKERRQ(ierr);
84     for (j=graph->cptr[i];j<graph->cptr[i+1];j++) {
85       ierr = PetscViewerASCIISynchronizedPrintf(viewer," %d (%d)",graph->queue[j],queue_in_global_numbering[j]);CHKERRQ(ierr);
86     }
87     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr);
88     ierr = PetscViewerASCIISetTab(viewer,tabs);CHKERRQ(ierr);
89     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
90   }
91   ierr = PetscFree(queue_in_global_numbering);CHKERRQ(ierr);
92   if (graph->custom_minimal_size > 1 && verbosity_level > 1) {
93     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Custom minimal size %d\n",graph->custom_minimal_size);CHKERRQ(ierr);
94   }
95   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
96   PetscFunctionReturn(0);
97 }
98 
99 #undef __FUNCT__
100 #define __FUNCT__ "PCBDDCGraphGetCandidatesIS"
101 PetscErrorCode PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph, PetscBool use_faces, PetscBool use_edges, PetscBool use_vertices, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
102 {
103   IS             *ISForFaces,*ISForEdges,ISForVertices;
104   PetscInt       i,j,nfc,nec,nvc,*idx;
105   PetscBool      twodim_flag;
106   PetscErrorCode ierr;
107 
108   PetscFunctionBegin;
109   /* loop on ccs to evalute number of faces, edges and vertices */
110   nfc = 0;
111   nec = 0;
112   nvc = 0;
113   twodim_flag = PETSC_FALSE;
114   for (i=0;i<graph->ncc;i++) {
115     if (graph->cptr[i+1]-graph->cptr[i] > graph->custom_minimal_size) {
116       if (graph->count[graph->queue[graph->cptr[i]]] == 1 && graph->special_dof[graph->queue[graph->cptr[i]]] != NEUMANN_MARK) {
117         nfc++;
118       } else { /* note that nec will be zero in 2d */
119         nec++;
120       }
121     } else {
122       nvc += graph->cptr[i+1]-graph->cptr[i];
123     }
124   }
125   if (!nec) { /* we are in a 2d case -> no faces, only edges */
126     nec = nfc;
127     nfc = 0;
128     twodim_flag = PETSC_TRUE;
129   }
130   /* allocate IS arrays for faces, edges. Vertices need a single index set. */
131   ISForFaces = 0;
132   ISForEdges = 0;
133   ISForVertices = 0;
134   if (use_faces && nfc) {
135     ierr = PetscMalloc1(nfc,&ISForFaces);CHKERRQ(ierr);
136   }
137   if (use_edges && nec) {
138     ierr = PetscMalloc1(nec,&ISForEdges);CHKERRQ(ierr);
139   }
140   if (use_vertices && nvc) {
141     ierr = PetscMalloc1(nvc,&idx);CHKERRQ(ierr);
142   }
143   /* loop on ccs to compute index sets for faces and edges */
144   nfc = 0;
145   nec = 0;
146   for (i=0;i<graph->ncc;i++) {
147     if (graph->cptr[i+1]-graph->cptr[i] > graph->custom_minimal_size) {
148       if (graph->count[graph->queue[graph->cptr[i]]] == 1 && graph->special_dof[graph->queue[graph->cptr[i]]] != NEUMANN_MARK) {
149         if (twodim_flag) {
150           if (use_edges) {
151             ierr = ISCreateGeneral(PETSC_COMM_SELF,graph->cptr[i+1]-graph->cptr[i],&graph->queue[graph->cptr[i]],PETSC_COPY_VALUES,&ISForEdges[nec]);CHKERRQ(ierr);
152             nec++;
153           }
154         } else {
155           if (use_faces) {
156             ierr = ISCreateGeneral(PETSC_COMM_SELF,graph->cptr[i+1]-graph->cptr[i],&graph->queue[graph->cptr[i]],PETSC_COPY_VALUES,&ISForFaces[nfc]);CHKERRQ(ierr);
157             nfc++;
158           }
159         }
160       } else {
161         if (use_edges) {
162           ierr = ISCreateGeneral(PETSC_COMM_SELF,graph->cptr[i+1]-graph->cptr[i],&graph->queue[graph->cptr[i]],PETSC_COPY_VALUES,&ISForEdges[nec]);CHKERRQ(ierr);
163           nec++;
164         }
165       }
166     }
167   }
168   /* index set for vertices */
169   if (use_vertices && nvc) {
170     nvc = 0;
171     for (i=0;i<graph->ncc;i++) {
172       if (graph->cptr[i+1]-graph->cptr[i] <= graph->custom_minimal_size) {
173         for (j=graph->cptr[i];j<graph->cptr[i+1];j++) {
174           idx[nvc]=graph->queue[j];
175           nvc++;
176         }
177       }
178     }
179     /* sort vertex set (by local ordering) */
180     ierr = PetscSortInt(nvc,idx);CHKERRQ(ierr);
181     ierr = ISCreateGeneral(PETSC_COMM_SELF,nvc,idx,PETSC_OWN_POINTER,&ISForVertices);CHKERRQ(ierr);
182   }
183   /* get back info */
184   *n_faces = nfc;
185   *FacesIS = ISForFaces;
186   *n_edges = nec;
187   *EdgesIS = ISForEdges;
188   *VerticesIS = ISForVertices;
189   PetscFunctionReturn(0);
190 }
191 
192 #undef __FUNCT__
193 #define __FUNCT__ "PCBDDCGraphComputeConnectedComponents"
194 PetscErrorCode PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph)
195 {
196   PetscInt       i,adapt_interface,adapt_interface_reduced;
197   MPI_Comm       interface_comm;
198   PetscErrorCode ierr;
199 
200   PetscFunctionBegin;
201   /* compute connected components locally */
202   ierr = PetscObjectGetComm((PetscObject)(graph->l2gmap),&interface_comm);CHKERRQ(ierr);
203   ierr = PCBDDCGraphComputeConnectedComponentsLocal(graph);CHKERRQ(ierr);
204   /* check consistency of connected components among neighbouring subdomains -> it adapt them in case it is needed */
205   adapt_interface = 0;
206   adapt_interface_reduced = 0;
207   for (i=0;i<graph->n_subsets;i++) {
208     /* We are not sure that on a given subset of the local interface,
209        with two connected components, the latters be the same among sharing subdomains */
210     if (graph->subset_ncc[i] > 1) {
211       adapt_interface=1;
212       break;
213     }
214   }
215   ierr = MPI_Allreduce(&adapt_interface,&adapt_interface_reduced,1,MPIU_INT,MPI_LOR,interface_comm);CHKERRQ(ierr);
216 
217   if (graph->n_subsets && adapt_interface_reduced) {
218     MPI_Request *send_requests;
219     MPI_Request *recv_requests;
220     PetscInt    *aux_new_xadj,*new_xadj,*new_adjncy,**temp_buffer;
221     PetscInt    *old_xadj,*old_adjncy;
222     PetscInt    j,k,s,sum_requests,buffer_size,size_of_recv,temp_buffer_size;
223     PetscMPIInt rank,neigh,tag,mpi_buffer_size;
224     PetscInt    *cum_recv_counts,*subset_to_nodes_indices,*recv_buffer_subset,*nodes_to_temp_buffer_indices;
225     PetscInt    *send_buffer,*recv_buffer,*queue_in_global_numbering,*sizes_of_sends,*add_to_subset;
226     PetscInt    start_of_recv,start_of_send,size_of_send,global_subset_counter,ins_val;
227     PetscBool   *subset_cc_adapt,same_set;
228 
229     /* Retrict adjacency graph using information from previously computed connected components */
230     ierr = PetscMalloc1(graph->nvtxs,&aux_new_xadj);CHKERRQ(ierr);
231     for (i=0;i<graph->nvtxs;i++) {
232       aux_new_xadj[i]=1;
233     }
234     for (i=0;i<graph->ncc;i++) {
235       k = graph->cptr[i+1]-graph->cptr[i];
236       for (j=0;j<k;j++) {
237         aux_new_xadj[graph->queue[graph->cptr[i]+j]]=k;
238       }
239     }
240     j = 0;
241     for (i=0;i<graph->nvtxs;i++) {
242       j += aux_new_xadj[i];
243     }
244     ierr = PetscMalloc1((graph->nvtxs+1),&new_xadj);CHKERRQ(ierr);
245     ierr = PetscMalloc1(j,&new_adjncy);CHKERRQ(ierr);
246     new_xadj[0]=0;
247     for (i=0;i<graph->nvtxs;i++) {
248       new_xadj[i+1]=new_xadj[i]+aux_new_xadj[i];
249       if (aux_new_xadj[i]==1) {
250         new_adjncy[new_xadj[i]]=i;
251       }
252     }
253     ierr = PetscFree(aux_new_xadj);CHKERRQ(ierr);
254     for (i=0;i<graph->ncc;i++) {
255       k = graph->cptr[i+1]-graph->cptr[i];
256       for (j=0;j<k;j++) {
257         ierr = PetscMemcpy(&new_adjncy[new_xadj[graph->queue[graph->cptr[i]+j]]],&graph->queue[graph->cptr[i]],k*sizeof(PetscInt));CHKERRQ(ierr);
258       }
259     }
260     /* set temporarly new CSR into graph */
261     old_xadj = graph->xadj;
262     old_adjncy = graph->adjncy;
263     graph->xadj = new_xadj;
264     graph->adjncy = new_adjncy;
265     /* allocate some space */
266     ierr = MPI_Comm_rank(interface_comm,&rank);CHKERRQ(ierr);
267     ierr = PetscMalloc1((graph->n_subsets+1),&cum_recv_counts);CHKERRQ(ierr);
268     ierr = PetscMemzero(cum_recv_counts,(graph->n_subsets+1)*sizeof(*cum_recv_counts));CHKERRQ(ierr);
269     ierr = PetscMalloc1(graph->n_subsets,&subset_to_nodes_indices);CHKERRQ(ierr);
270     /* first count how many neighbours per connected component I will receive from */
271     cum_recv_counts[0]=0;
272     for (i=1;i<graph->n_subsets+1;i++) {
273       j = 0;
274       while (graph->subset[j] != i) {
275         j++;
276       }
277       subset_to_nodes_indices[i-1]=j;
278       /* We don't want sends/recvs_to/from_self -> here I don't count myself  */
279       cum_recv_counts[i]=cum_recv_counts[i-1]+graph->count[j];
280     }
281     ierr = PetscMalloc1(2*cum_recv_counts[graph->n_subsets],&recv_buffer_subset);CHKERRQ(ierr);
282     ierr = PetscMalloc1(cum_recv_counts[graph->n_subsets],&send_requests);CHKERRQ(ierr);
283     ierr = PetscMalloc1(cum_recv_counts[graph->n_subsets],&recv_requests);CHKERRQ(ierr);
284     for (i=0;i<cum_recv_counts[graph->n_subsets];i++) {
285       send_requests[i]=MPI_REQUEST_NULL;
286       recv_requests[i]=MPI_REQUEST_NULL;
287     }
288     /* exchange with my neighbours the number of my connected components on the shared interface */
289     sum_requests = 0;
290     for (i=0;i<graph->n_subsets;i++) {
291       j = subset_to_nodes_indices[i];
292       ierr = PetscMPIIntCast(graph->subset_ref_node[i],&tag);CHKERRQ(ierr);
293       for (k=0;k<graph->count[j];k++) {
294         ierr = PetscMPIIntCast(graph->neighbours_set[j][k],&neigh);CHKERRQ(ierr);
295         ierr = MPI_Isend(&graph->subset_ncc[i],1,MPIU_INT,neigh,tag,interface_comm,&send_requests[sum_requests]);CHKERRQ(ierr);
296         ierr = MPI_Irecv(&recv_buffer_subset[sum_requests],1,MPIU_INT,neigh,tag,interface_comm,&recv_requests[sum_requests]);CHKERRQ(ierr);
297         sum_requests++;
298       }
299     }
300     ierr = MPI_Waitall(sum_requests,recv_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
301     ierr = MPI_Waitall(sum_requests,send_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
302     /* determine the connected component I need to adapt */
303     ierr = PetscMalloc1(graph->n_subsets,&subset_cc_adapt);CHKERRQ(ierr);
304     ierr = PetscMemzero(subset_cc_adapt,graph->n_subsets*sizeof(*subset_cc_adapt));CHKERRQ(ierr);
305     for (i=0;i<graph->n_subsets;i++) {
306       for (j=cum_recv_counts[i];j<cum_recv_counts[i+1];j++){
307         /* The first condition is natural (someone has a different number of ccs than me), the second one is just to be safe */
308         if (graph->subset_ncc[i] != recv_buffer_subset[j] || graph->subset_ncc[i] > 1) {
309           subset_cc_adapt[i] = PETSC_TRUE;
310           break;
311         }
312       }
313     }
314     buffer_size = 0;
315     for (i=0;i<graph->n_subsets;i++) {
316       if (subset_cc_adapt[i]) {
317         for (j=i;j<graph->ncc;j++) {
318           if (graph->subset[graph->queue[graph->cptr[j]]] == i+1) { /* WARNING -> subset values goes from 1 to graph->n_subsets included */
319             buffer_size += 1 + graph->cptr[j+1]-graph->cptr[j];
320           }
321         }
322       }
323     }
324     ierr = PetscMalloc1(buffer_size,&send_buffer);CHKERRQ(ierr);
325     /* now get from neighbours their ccs (in global numbering) and adapt them (in case it is needed) */
326     ierr = PetscMalloc1(graph->cptr[graph->ncc],&queue_in_global_numbering);CHKERRQ(ierr);
327     ierr = ISLocalToGlobalMappingApply(graph->l2gmap,graph->cptr[graph->ncc],graph->queue,queue_in_global_numbering);CHKERRQ(ierr);
328     /* determine how much data to send (size of each queue plus the global indices) and communicate it to neighbours */
329     ierr = PetscMalloc1(graph->n_subsets,&sizes_of_sends);CHKERRQ(ierr);
330     ierr = PetscMemzero(sizes_of_sends,graph->n_subsets*sizeof(*sizes_of_sends));CHKERRQ(ierr);
331     sum_requests = 0;
332     start_of_send = 0;
333     start_of_recv = cum_recv_counts[graph->n_subsets];
334     for (i=0;i<graph->n_subsets;i++) {
335       if (subset_cc_adapt[i]) {
336         size_of_send = 0;
337         for (j=i;j<graph->ncc;j++) {
338           if (graph->subset[graph->queue[graph->cptr[j]]] == i+1) { /* WARNING -> subset values goes from 1 to graph->n_subsets included */
339             send_buffer[start_of_send+size_of_send]=graph->cptr[j+1]-graph->cptr[j];
340             size_of_send += 1;
341             ierr = PetscMemcpy(&send_buffer[start_of_send+size_of_send],
342                                &queue_in_global_numbering[graph->cptr[j]],
343                                (graph->cptr[j+1]-graph->cptr[j])*sizeof(*send_buffer));CHKERRQ(ierr);
344             size_of_send = size_of_send+graph->cptr[j+1]-graph->cptr[j];
345           }
346         }
347         j = subset_to_nodes_indices[i];
348         sizes_of_sends[i] = size_of_send;
349         ierr = PetscMPIIntCast(graph->subset_ref_node[i]+1,&tag);CHKERRQ(ierr);
350         for (k=0;k<graph->count[j];k++) {
351           ierr = PetscMPIIntCast(graph->neighbours_set[j][k],&neigh);CHKERRQ(ierr);
352           ierr = MPI_Isend(&sizes_of_sends[i],1,MPIU_INT,neigh,tag,interface_comm,&send_requests[sum_requests]);CHKERRQ(ierr);
353           ierr = MPI_Irecv(&recv_buffer_subset[sum_requests+start_of_recv],1,MPIU_INT,neigh,tag,interface_comm,&recv_requests[sum_requests]);CHKERRQ(ierr);
354           sum_requests++;
355         }
356         start_of_send += size_of_send;
357       }
358     }
359     ierr = MPI_Waitall(sum_requests,send_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
360     ierr = MPI_Waitall(sum_requests,recv_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
361     buffer_size = 0;
362     for (k=0;k<sum_requests;k++) {
363       buffer_size += recv_buffer_subset[start_of_recv+k];
364     }
365     ierr = PetscMalloc1(buffer_size,&recv_buffer);CHKERRQ(ierr);
366     /* now exchange the data */
367     start_of_recv = 0;
368     start_of_send = 0;
369     sum_requests = 0;
370     for (i=0;i<graph->n_subsets;i++) {
371       if (subset_cc_adapt[i]) {
372         size_of_send = sizes_of_sends[i];
373         j = subset_to_nodes_indices[i];
374         ierr = PetscMPIIntCast(graph->subset_ref_node[i]+2,&tag);CHKERRQ(ierr);
375         for (k=0;k<graph->count[j];k++) {
376           ierr = PetscMPIIntCast(graph->neighbours_set[j][k],&neigh);CHKERRQ(ierr);
377           ierr = PetscMPIIntCast(size_of_send,&mpi_buffer_size);CHKERRQ(ierr);
378           ierr = MPI_Isend(&send_buffer[start_of_send],mpi_buffer_size,MPIU_INT,neigh,tag,interface_comm,&send_requests[sum_requests]);CHKERRQ(ierr);
379           size_of_recv = recv_buffer_subset[cum_recv_counts[graph->n_subsets]+sum_requests];
380           ierr = PetscMPIIntCast(size_of_recv,&mpi_buffer_size);CHKERRQ(ierr);
381           ierr = MPI_Irecv(&recv_buffer[start_of_recv],mpi_buffer_size,MPIU_INT,neigh,tag,interface_comm,&recv_requests[sum_requests]);CHKERRQ(ierr);
382           start_of_recv += size_of_recv;
383           sum_requests++;
384         }
385         start_of_send += size_of_send;
386       }
387     }
388     ierr = MPI_Waitall(sum_requests,recv_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
389     ierr = MPI_Waitall(sum_requests,send_requests,MPI_STATUSES_IGNORE);CHKERRQ(ierr);
390     for (j=0;j<buffer_size;) {
391        ierr = ISGlobalToLocalMappingApply(graph->l2gmap,IS_GTOLM_MASK,recv_buffer[j],&recv_buffer[j+1],&recv_buffer[j],&recv_buffer[j+1]);CHKERRQ(ierr);
392        /* we need to adapt the output of GlobalToLocal mapping if there are mirrored nodes */
393        if (graph->mirrors) {
394          PetscBool mirrored_found=PETSC_FALSE;
395          for (k=0;k<recv_buffer[j];k++) {
396            if (graph->mirrors[recv_buffer[j+k+1]]) {
397              mirrored_found=PETSC_TRUE;
398              recv_buffer[j+k+1]=graph->mirrors_set[recv_buffer[j+k+1]][0];
399            }
400          }
401          if (mirrored_found) {
402            ierr = PetscSortInt(recv_buffer[j],&recv_buffer[j+1]);CHKERRQ(ierr);
403            k=0;
404            while (k<recv_buffer[j]) {
405              for (s=1;s<graph->mirrors[recv_buffer[j+1+k]];s++) {
406                recv_buffer[j+1+k+s] = graph->mirrors_set[recv_buffer[j+1+k]][s];
407              }
408              k+=graph->mirrors[recv_buffer[j+1+k]]+s;
409            }
410          }
411        }
412        k = recv_buffer[j]+1;
413        j += k;
414     }
415     sum_requests = cum_recv_counts[graph->n_subsets];
416     start_of_recv = 0;
417     ierr = PetscMalloc1(graph->nvtxs,&nodes_to_temp_buffer_indices);CHKERRQ(ierr);
418     global_subset_counter = 0;
419     for (i=0;i<graph->n_subsets;i++) {
420       if (subset_cc_adapt[i]) {
421         temp_buffer_size = 0;
422         /* find nodes on the shared interface we need to adapt */
423         for (j=0;j<graph->nvtxs;j++) {
424           if (graph->subset[j]==i+1) {
425             nodes_to_temp_buffer_indices[j] = temp_buffer_size;
426             temp_buffer_size++;
427           } else {
428             nodes_to_temp_buffer_indices[j] = -1;
429           }
430         }
431         /* allocate some temporary space */
432         ierr = PetscMalloc1(temp_buffer_size,&temp_buffer);CHKERRQ(ierr);
433         ierr = PetscMalloc1(temp_buffer_size*(cum_recv_counts[i+1]-cum_recv_counts[i]),&temp_buffer[0]);CHKERRQ(ierr);
434         ierr = PetscMemzero(temp_buffer[0],temp_buffer_size*(cum_recv_counts[i+1]-cum_recv_counts[i])*sizeof(PetscInt));CHKERRQ(ierr);
435         for (j=1;j<temp_buffer_size;j++) {
436           temp_buffer[j] = temp_buffer[j-1]+cum_recv_counts[i+1]-cum_recv_counts[i];
437         }
438         /* analyze contributions from neighbouring subdomains for i-th conn comp
439            temp buffer structure:
440            supposing part of the interface has dimension 5 (for example with global dofs 0,1,2,3,4)
441            3 neighs procs with structured connected components:
442              neigh 0: [0 1 4], [2 3];  (2 connected components)
443              neigh 1: [0 1], [2 3 4];  (2 connected components)
444              neigh 2: [0 4], [1], [2 3]; (3 connected components)
445            tempbuffer (row-oriented) will be filled as:
446              [ 0, 0, 0;
447                0, 0, 1;
448                1, 1, 2;
449                1, 1, 2;
450                0, 1, 0; ];
451            This way we can simply find intersections of ccs among neighs.
452            For the example above, the graph->subset array will be modified to reproduce the following 4 connected components [0], [1], [2 3], [4];
453                                                                                                                                    */
454         for (j=0;j<cum_recv_counts[i+1]-cum_recv_counts[i];j++) {
455           ins_val = 0;
456           size_of_recv = recv_buffer_subset[sum_requests];  /* total size of recv from neighs */
457           for (buffer_size=0;buffer_size<size_of_recv;) {  /* loop until all data from neighs has been taken into account */
458             for (k=1;k<recv_buffer[buffer_size+start_of_recv]+1;k++) { /* filling properly temp_buffer using data from a single recv */
459               temp_buffer[nodes_to_temp_buffer_indices[recv_buffer[start_of_recv+buffer_size+k]]][j] = ins_val;
460             }
461             buffer_size += k;
462             ins_val++;
463           }
464           start_of_recv += size_of_recv;
465           sum_requests++;
466         }
467         ierr = PetscMalloc1(temp_buffer_size,&add_to_subset);CHKERRQ(ierr);
468         ierr = PetscMemzero(add_to_subset,temp_buffer_size*sizeof(*add_to_subset));CHKERRQ(ierr);
469         for (j=0;j<temp_buffer_size;j++) {
470           if (!add_to_subset[j]) { /* found a new cc  */
471             global_subset_counter++;
472             add_to_subset[j] = global_subset_counter;
473             for (k=j+1;k<temp_buffer_size;k++) { /* check for other nodes in new cc */
474               same_set = PETSC_TRUE;
475               for (s=0;s<cum_recv_counts[i+1]-cum_recv_counts[i];s++) {
476                 if (temp_buffer[j][s]!=temp_buffer[k][s]) {
477                   same_set = PETSC_FALSE;
478                   break;
479                 }
480               }
481               if (same_set) {
482                 add_to_subset[k] = global_subset_counter;
483               }
484             }
485           }
486         }
487         /* insert new data in subset array */
488         temp_buffer_size = 0;
489         for (j=0;j<graph->nvtxs;j++) {
490           if (graph->subset[j]==i+1) {
491             graph->subset[j] = graph->n_subsets+add_to_subset[temp_buffer_size];
492             temp_buffer_size++;
493           }
494         }
495         ierr = PetscFree(temp_buffer[0]);CHKERRQ(ierr);
496         ierr = PetscFree(temp_buffer);CHKERRQ(ierr);
497         ierr = PetscFree(add_to_subset);CHKERRQ(ierr);
498       }
499     }
500     ierr = PetscFree(nodes_to_temp_buffer_indices);CHKERRQ(ierr);
501     ierr = PetscFree(sizes_of_sends);CHKERRQ(ierr);
502     ierr = PetscFree(send_requests);CHKERRQ(ierr);
503     ierr = PetscFree(recv_requests);CHKERRQ(ierr);
504     ierr = PetscFree(recv_buffer);CHKERRQ(ierr);
505     ierr = PetscFree(recv_buffer_subset);CHKERRQ(ierr);
506     ierr = PetscFree(send_buffer);CHKERRQ(ierr);
507     ierr = PetscFree(cum_recv_counts);CHKERRQ(ierr);
508     ierr = PetscFree(subset_to_nodes_indices);CHKERRQ(ierr);
509     ierr = PetscFree(subset_cc_adapt);CHKERRQ(ierr);
510     /* We are ready to find for connected components consistent among neighbouring subdomains */
511     if (global_subset_counter) {
512       ierr = PetscBTMemzero(graph->nvtxs,graph->touched);CHKERRQ(ierr);
513       global_subset_counter = 0;
514       for (i=0;i<graph->nvtxs;i++) {
515         if (graph->subset[i] && !PetscBTLookup(graph->touched,i)) {
516           global_subset_counter++;
517           for (j=i+1;j<graph->nvtxs;j++) {
518             if (!PetscBTLookup(graph->touched,j) && graph->subset[j]==graph->subset[i]) {
519               graph->subset[j] = global_subset_counter;
520               ierr = PetscBTSet(graph->touched,j);CHKERRQ(ierr);
521             }
522           }
523           graph->subset[i] = global_subset_counter;
524           ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
525         }
526       }
527       /* refine connected components locally */
528       ierr = PCBDDCGraphComputeConnectedComponentsLocal(graph);CHKERRQ(ierr);
529     }
530     /* restore original CSR graph of dofs */
531     ierr = PetscFree(new_xadj);CHKERRQ(ierr);
532     ierr = PetscFree(new_adjncy);CHKERRQ(ierr);
533     graph->xadj = old_xadj;
534     graph->adjncy = old_adjncy;
535     ierr = PetscFree(queue_in_global_numbering);CHKERRQ(ierr);
536   }
537   PetscFunctionReturn(0);
538 }
539 
540 /* The following code has been adapted from function IsConnectedSubdomain contained
541    in source file contig.c of METIS library (version 5.0.1)
542    It finds connected components for each subset  */
543 #undef __FUNCT__
544 #define __FUNCT__ "PCBDDCGraphComputeConnectedComponentsLocal"
545 PetscErrorCode PCBDDCGraphComputeConnectedComponentsLocal(PCBDDCGraph graph)
546 {
547   PetscInt       i,j,k,first,last,nleft,ncc,pid,cum_queue,n,ncc_pid;
548   PetscInt       *queue_global;
549   PetscErrorCode ierr;
550 
551   PetscFunctionBegin;
552   /* quiet return if no csr info is available */
553   if (!graph->xadj || !graph->adjncy) {
554     PetscFunctionReturn(0);
555   }
556 
557   /* reset any previous search of connected components */
558   ierr = PetscBTMemzero(graph->nvtxs,graph->touched);CHKERRQ(ierr);
559   graph->n_subsets = 0;
560   for (i=0;i<graph->nvtxs;i++) {
561     if (graph->special_dof[i] == DIRICHLET_MARK || !graph->count[i]) {
562       ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
563       graph->subset[i] = 0;
564     }
565     graph->n_subsets = PetscMax(graph->n_subsets,graph->subset[i]);
566   }
567   ierr = PetscFree(graph->subset_ncc);CHKERRQ(ierr);
568   ierr = PetscMalloc1(graph->n_subsets,&graph->subset_ncc);CHKERRQ(ierr);
569   ierr = PetscMemzero(graph->subset_ncc,graph->n_subsets*sizeof(*graph->subset_ncc));CHKERRQ(ierr);
570   ierr = PetscMemzero(graph->cptr,(graph->nvtxs+1)*sizeof(*graph->cptr));CHKERRQ(ierr);
571   ierr = PetscMemzero(graph->queue,graph->nvtxs*sizeof(*graph->queue));CHKERRQ(ierr);
572 
573   /* begin search for connected components */
574   cum_queue = 0;
575   ncc = 0;
576   for (n=0;n<graph->n_subsets;n++) {
577     pid = n+1;  /* partition labeled by 0 is discarded */
578     nleft = 0;
579     for (i=0;i<graph->nvtxs;i++) {
580       if (graph->subset[i] == pid) {
581         nleft++;
582       }
583     }
584     for (i=0; i<graph->nvtxs; i++) {
585       if (graph->subset[i] == pid) {
586         break;
587       }
588     }
589     ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
590     graph->queue[cum_queue] = i;
591     first = 0;
592     last = 1;
593     graph->cptr[ncc] = cum_queue;
594     ncc_pid = 0;
595     while (first != nleft) {
596       if (first == last) {
597         graph->cptr[++ncc] = first+cum_queue;
598         ncc_pid++;
599         for (i=0; i<graph->nvtxs; i++) { /* TODO-> use a while! */
600           if (graph->subset[i] == pid && !PetscBTLookup(graph->touched,i)) {
601             break;
602           }
603         }
604         graph->queue[cum_queue+last] = i;
605         last++;
606         ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
607       }
608       i = graph->queue[cum_queue+first];
609       first++;
610       for (j=graph->xadj[i];j<graph->xadj[i+1];j++) {
611         k = graph->adjncy[j];
612         if (graph->subset[k] == pid && !PetscBTLookup(graph->touched,k)) {
613           graph->queue[cum_queue+last] = k;
614           last++;
615           ierr = PetscBTSet(graph->touched,k);CHKERRQ(ierr);
616         }
617       }
618     }
619     graph->cptr[++ncc] = first+cum_queue;
620     ncc_pid++;
621     cum_queue = graph->cptr[ncc];
622     graph->subset_ncc[n] = ncc_pid;
623   }
624   graph->ncc = ncc;
625   /* For consistency among neighbours, I need to sort (by global ordering) each connected component */
626   ierr = PetscMalloc1(graph->cptr[graph->ncc],&queue_global);CHKERRQ(ierr);
627   ierr = ISLocalToGlobalMappingApply(graph->l2gmap,graph->cptr[graph->ncc],graph->queue,queue_global);CHKERRQ(ierr);
628   for (i=0;i<graph->ncc;i++) {
629     ierr = PetscSortIntWithArray(graph->cptr[i+1]-graph->cptr[i],&queue_global[graph->cptr[i]],&graph->queue[graph->cptr[i]]);CHKERRQ(ierr);
630   }
631   ierr = PetscFree(queue_global);CHKERRQ(ierr);
632   PetscFunctionReturn(0);
633 }
634 
635 #undef __FUNCT__
636 #define __FUNCT__ "PCBDDCGraphSetUp"
637 PetscErrorCode PCBDDCGraphSetUp(PCBDDCGraph graph, PetscInt custom_minimal_size, IS neumann_is, IS dirichlet_is, PetscInt n_ISForDofs, IS ISForDofs[], IS custom_primal_vertices)
638 {
639   VecScatter     scatter_ctx;
640   Vec            local_vec,local_vec2,global_vec;
641   IS             to,from;
642   MPI_Comm       comm;
643   PetscScalar    *array,*array2;
644   const PetscInt *is_indices;
645   PetscInt       n_neigh,*neigh,*n_shared,**shared,*queue_global;
646   PetscInt       i,j,k,s,total_counts,nodes_touched,is_size;
647   PetscErrorCode ierr;
648   PetscBool      same_set,mirrors_found;
649 
650   PetscFunctionBegin;
651   ierr = PetscObjectGetComm((PetscObject)(graph->l2gmap),&comm);CHKERRQ(ierr);
652   /* custom_minimal_size */
653   graph->custom_minimal_size = PetscMax(graph->custom_minimal_size,custom_minimal_size);
654   /* get info l2gmap and allocate work vectors  */
655   ierr = ISLocalToGlobalMappingGetInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
656   ierr = ISLocalToGlobalMappingGetIndices(graph->l2gmap,&is_indices);CHKERRQ(ierr);
657   j = 0;
658   for (i=0;i<graph->nvtxs;i++) {
659     j = PetscMax(j,is_indices[i]);
660   }
661   ierr = MPI_Allreduce(&j,&i,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
662   i++;
663   ierr = VecCreate(PETSC_COMM_SELF,&local_vec);CHKERRQ(ierr);
664   ierr = VecSetSizes(local_vec,PETSC_DECIDE,graph->nvtxs);CHKERRQ(ierr);
665   ierr = VecSetType(local_vec,VECSTANDARD);CHKERRQ(ierr);
666   ierr = VecDuplicate(local_vec,&local_vec2);CHKERRQ(ierr);
667   ierr = VecCreate(comm,&global_vec);CHKERRQ(ierr);
668   ierr = VecSetSizes(global_vec,PETSC_DECIDE,i);CHKERRQ(ierr);
669   ierr = VecSetType(global_vec,VECSTANDARD);CHKERRQ(ierr);
670   ierr = ISCreateStride(PETSC_COMM_SELF,graph->nvtxs,0,1,&to);CHKERRQ(ierr);
671   ierr = ISLocalToGlobalMappingApplyIS(graph->l2gmap,to,&from);CHKERRQ(ierr);
672   ierr = VecScatterCreate(global_vec,from,local_vec,to,&scatter_ctx);CHKERRQ(ierr);
673 
674   /* get local periodic nodes */
675   mirrors_found = PETSC_FALSE;
676   if (graph->nvtxs && n_neigh) {
677     for (i=0; i<n_shared[0]; i++) graph->count[shared[0][i]] += 1;
678     for (i=0; i<n_shared[0]; i++) {
679       if (graph->count[shared[0][i]] > 1) {
680         mirrors_found = PETSC_TRUE;
681         break;
682       }
683     }
684   }
685   /* compute local mirrors (if any) */
686   if (mirrors_found) {
687     PetscInt *local_indices,*global_indices;
688     /* get arrays of local and global indices */
689     ierr = PetscMalloc1(graph->nvtxs,&local_indices);CHKERRQ(ierr);
690     ierr = ISGetIndices(to,(const PetscInt**)&is_indices);CHKERRQ(ierr);
691     ierr = PetscMemcpy(local_indices,is_indices,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
692     ierr = ISRestoreIndices(to,(const PetscInt**)&is_indices);CHKERRQ(ierr);
693     ierr = PetscMalloc1(graph->nvtxs,&global_indices);CHKERRQ(ierr);
694     ierr = ISGetIndices(from,(const PetscInt**)&is_indices);CHKERRQ(ierr);
695     ierr = PetscMemcpy(global_indices,is_indices,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
696     ierr = ISRestoreIndices(from,(const PetscInt**)&is_indices);CHKERRQ(ierr);
697     /* allocate space for mirrors */
698     ierr = PetscMalloc2(graph->nvtxs,&graph->mirrors,graph->nvtxs,&graph->mirrors_set);CHKERRQ(ierr);
699     ierr = PetscMemzero(graph->mirrors,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
700     graph->mirrors_set[0] = 0;
701 
702     k=0;
703     for (i=0;i<n_shared[0];i++) {
704       j=shared[0][i];
705       if (graph->count[j] > 1) {
706         graph->mirrors[j]++;
707         k++;
708       }
709     }
710     /* allocate space for set of mirrors */
711     ierr = PetscMalloc1(k,&graph->mirrors_set[0]);CHKERRQ(ierr);
712     for (i=1;i<graph->nvtxs;i++)
713       graph->mirrors_set[i]=graph->mirrors_set[i-1]+graph->mirrors[i-1];
714 
715     /* fill arrays */
716     ierr = PetscMemzero(graph->mirrors,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
717     for (j=0;j<n_shared[0];j++) {
718       i=shared[0][j];
719       if (graph->count[i] > 1)
720         graph->mirrors_set[i][graph->mirrors[i]++]=global_indices[i];
721     }
722     ierr = PetscSortIntWithArray(graph->nvtxs,global_indices,local_indices);CHKERRQ(ierr);
723     for (i=0;i<graph->nvtxs;i++) {
724       if (graph->mirrors[i] > 0) {
725         ierr = PetscFindInt(graph->mirrors_set[i][0],graph->nvtxs,global_indices,&k);CHKERRQ(ierr);
726         j = global_indices[k];
727         while ( k > 0 && global_indices[k-1] == j) k--;
728         for (j=0;j<graph->mirrors[i];j++) {
729           graph->mirrors_set[i][j]=local_indices[k+j];
730         }
731         ierr = PetscSortInt(graph->mirrors[i],graph->mirrors_set[i]);CHKERRQ(ierr);
732       }
733     }
734     ierr = PetscFree(local_indices);CHKERRQ(ierr);
735     ierr = PetscFree(global_indices);CHKERRQ(ierr);
736   }
737   ierr = PetscMemzero(graph->count,graph->nvtxs*sizeof(*graph->count));CHKERRQ(ierr);
738   ierr = ISDestroy(&to);CHKERRQ(ierr);
739   ierr = ISDestroy(&from);CHKERRQ(ierr);
740 
741   /* Count total number of neigh per node */
742   k=0;
743   for (i=1;i<n_neigh;i++) {
744     k += n_shared[i];
745     for (j=0;j<n_shared[i];j++) {
746       graph->count[shared[i][j]] += 1;
747     }
748   }
749   /* Allocate space for storing the set of neighbours for each node */
750   if (graph->nvtxs) {
751     ierr = PetscMalloc1(k,&graph->neighbours_set[0]);CHKERRQ(ierr);
752   }
753   for (i=1;i<graph->nvtxs;i++) { /* dont count myself */
754     graph->neighbours_set[i]=graph->neighbours_set[i-1]+graph->count[i-1];
755   }
756   /* Get information for sharing subdomains */
757   ierr = PetscMemzero(graph->count,graph->nvtxs*sizeof(*graph->count));CHKERRQ(ierr);
758   for (i=1;i<n_neigh;i++) { /* dont count myself */
759     s = n_shared[i];
760     for (j=0;j<s;j++) {
761       k = shared[i][j];
762       graph->neighbours_set[k][graph->count[k]] = neigh[i];
763       graph->count[k] += 1;
764     }
765   }
766   /* sort set of sharing subdomains */
767   for (i=0;i<graph->nvtxs;i++) {
768     ierr = PetscSortRemoveDupsInt(&graph->count[i],graph->neighbours_set[i]);CHKERRQ(ierr);
769   }
770   /* Get info for dofs splitting */
771   for (i=0;i<n_ISForDofs;i++) {
772     ierr = ISGetLocalSize(ISForDofs[i],&is_size);CHKERRQ(ierr);
773     ierr = ISGetIndices(ISForDofs[i],(const PetscInt**)&is_indices);CHKERRQ(ierr);
774     for (j=0;j<is_size;j++) {
775       graph->which_dof[is_indices[j]]=i;
776     }
777     ierr = ISRestoreIndices(ISForDofs[i],(const PetscInt**)&is_indices);CHKERRQ(ierr);
778   }
779   /* Take into account Neumann nodes */
780   ierr = VecSet(local_vec,0.0);CHKERRQ(ierr);
781   ierr = VecSet(local_vec2,0.0);CHKERRQ(ierr);
782   if (neumann_is) {
783     ierr = VecGetArray(local_vec,&array);CHKERRQ(ierr);
784     ierr = ISGetLocalSize(neumann_is,&is_size);CHKERRQ(ierr);
785     ierr = ISGetIndices(neumann_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
786     for (i=0;i<is_size;i++) {
787       array[is_indices[i]] = 1.0;
788     }
789     ierr = ISRestoreIndices(neumann_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
790     ierr = VecRestoreArray(local_vec,&array);CHKERRQ(ierr);
791   }
792   /* Neumann nodes: impose consistency among neighbours */
793   ierr = VecSet(global_vec,0.0);CHKERRQ(ierr);
794   ierr = VecScatterBegin(scatter_ctx,local_vec,global_vec,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
795   ierr = VecScatterEnd(scatter_ctx,local_vec,global_vec,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
796   ierr = VecScatterBegin(scatter_ctx,global_vec,local_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
797   ierr = VecScatterEnd(scatter_ctx,global_vec,local_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
798   ierr = VecGetArray(local_vec,&array);CHKERRQ(ierr);
799   for (i=0;i<graph->nvtxs;i++) {
800     if (PetscRealPart(array[i]) > 0.0) {
801       graph->special_dof[i] = NEUMANN_MARK;
802     }
803   }
804   ierr = VecRestoreArray(local_vec,&array);CHKERRQ(ierr);
805   /* Take into account Dirichlet nodes */
806   ierr = VecSet(local_vec2,0.0);CHKERRQ(ierr);
807   if (dirichlet_is) {
808     ierr = VecGetArray(local_vec,&array);CHKERRQ(ierr);
809     ierr = VecGetArray(local_vec2,&array2);CHKERRQ(ierr);
810     ierr = ISGetLocalSize(dirichlet_is,&is_size);CHKERRQ(ierr);
811     ierr = ISGetIndices(dirichlet_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
812     for (i=0;i<is_size;i++){
813       k = is_indices[i];
814       if (graph->count[k] && !PetscBTLookup(graph->touched,k)) {
815         if (PetscRealPart(array[k]) > 0.0) {
816           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"BDDC cannot have boundary nodes which are marked Neumann and Dirichlet at the same time! Local node %d is wrong!\n",k);
817         }
818         array2[k] = 1.0;
819       }
820     }
821     ierr = ISRestoreIndices(dirichlet_is,(const PetscInt**)&is_indices);CHKERRQ(ierr);
822     ierr = VecRestoreArray(local_vec,&array);CHKERRQ(ierr);
823     ierr = VecRestoreArray(local_vec2,&array2);CHKERRQ(ierr);
824   }
825   /* Dirichlet nodes: impose consistency among neighbours */
826   ierr = VecSet(global_vec,0.0);CHKERRQ(ierr);
827   ierr = VecScatterBegin(scatter_ctx,local_vec2,global_vec,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
828   ierr = VecScatterEnd(scatter_ctx,local_vec2,global_vec,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
829   ierr = VecScatterBegin(scatter_ctx,global_vec,local_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
830   ierr = VecScatterEnd(scatter_ctx,global_vec,local_vec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
831   ierr = VecGetArray(local_vec,&array);CHKERRQ(ierr);
832   for (i=0;i<graph->nvtxs;i++) {
833     if (PetscRealPart(array[i]) > 0.0) {
834       ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
835       graph->subset[i] = 0; /* dirichlet nodes treated as internal -> is it ok? */
836       graph->special_dof[i] = DIRICHLET_MARK;
837     }
838   }
839   ierr = VecRestoreArray(local_vec,&array);CHKERRQ(ierr);
840 
841   /* mark local periodic nodes (if any) and adapt CSR graph (if any) */
842   if (graph->mirrors) {
843     for (i=0;i<graph->nvtxs;i++)
844       if (graph->mirrors[i])
845         graph->special_dof[i] = LOCAL_PERIODIC_MARK;
846 
847     if (graph->xadj && graph->adjncy) {
848       PetscInt *new_xadj,*new_adjncy;
849       /* sort CSR graph */
850       for (i=0;i<graph->nvtxs;i++)
851         ierr = PetscSortInt(graph->xadj[i+1]-graph->xadj[i],&graph->adjncy[graph->xadj[i]]);CHKERRQ(ierr);
852 
853       /* adapt local CSR graph in case of local periodicity */
854       k=0;
855       for (i=0;i<graph->nvtxs;i++)
856         for (j=graph->xadj[i];j<graph->xadj[i+1];j++)
857           k += graph->mirrors[graph->adjncy[j]];
858 
859       ierr = PetscMalloc1((graph->nvtxs+1),&new_xadj);CHKERRQ(ierr);
860       ierr = PetscMalloc1((k+graph->xadj[graph->nvtxs]),&new_adjncy);CHKERRQ(ierr);
861       new_xadj[0]=0;
862       for (i=0;i<graph->nvtxs;i++) {
863         k = graph->xadj[i+1]-graph->xadj[i];
864         ierr = PetscMemcpy(&new_adjncy[new_xadj[i]],&graph->adjncy[graph->xadj[i]],k*sizeof(PetscInt));CHKERRQ(ierr);
865         new_xadj[i+1]=new_xadj[i]+k;
866         for (j=graph->xadj[i];j<graph->xadj[i+1];j++) {
867           k = graph->mirrors[graph->adjncy[j]];
868           ierr = PetscMemcpy(&new_adjncy[new_xadj[i+1]],graph->mirrors_set[graph->adjncy[j]],k*sizeof(PetscInt));CHKERRQ(ierr);
869           new_xadj[i+1]+=k;
870         }
871         k = new_xadj[i+1]-new_xadj[i];
872         ierr = PetscSortRemoveDupsInt(&k,&new_adjncy[new_xadj[i]]);CHKERRQ(ierr);
873         new_xadj[i+1]=new_xadj[i]+k;
874       }
875       /* set new CSR into graph */
876       ierr = PetscFree(graph->xadj);CHKERRQ(ierr);
877       ierr = PetscFree(graph->adjncy);CHKERRQ(ierr);
878       graph->xadj = new_xadj;
879       graph->adjncy = new_adjncy;
880     }
881   }
882 
883   /* mark special nodes -> each will become a single node equivalence class */
884   if (custom_primal_vertices) {
885     ierr = ISGetLocalSize(custom_primal_vertices,&is_size);CHKERRQ(ierr);
886     ierr = ISGetIndices(custom_primal_vertices,(const PetscInt**)&is_indices);CHKERRQ(ierr);
887     for (i=0;i<is_size;i++) {
888       graph->special_dof[is_indices[i]] = SPECIAL_MARK-i;
889     }
890     ierr = ISRestoreIndices(custom_primal_vertices,(const PetscInt**)&is_indices);CHKERRQ(ierr);
891   }
892   /* mark interior nodes as touched and belonging to partition number 0 */
893   for (i=0;i<graph->nvtxs;i++) {
894     if (!graph->count[i]) {
895       ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
896       graph->subset[i] = 0;
897     }
898   }
899   /* init graph structure and compute default subsets */
900   nodes_touched=0;
901   for (i=0;i<graph->nvtxs;i++) {
902     if (PetscBTLookup(graph->touched,i)) {
903       nodes_touched++;
904     }
905   }
906   i = 0;
907   graph->ncc = 0;
908   total_counts = 0;
909   while (nodes_touched<graph->nvtxs) {
910     /*  find first untouched node in local ordering */
911     while (PetscBTLookup(graph->touched,i)) {
912       i++;
913     }
914     ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr);
915     graph->subset[i] = graph->ncc+1;
916     graph->cptr[graph->ncc] = total_counts;
917     graph->queue[total_counts] = i;
918     total_counts++;
919     nodes_touched++;
920     /* now find all other nodes having the same set of sharing subdomains */
921     for (j=i+1;j<graph->nvtxs;j++) {
922       /* check for same number of sharing subdomains, dof number and same special mark */
923       if (!PetscBTLookup(graph->touched,j) && graph->count[i] == graph->count[j] && graph->which_dof[i] == graph->which_dof[j] && graph->special_dof[i] == graph->special_dof[j]) {
924         /* check for same set of sharing subdomains */
925         same_set=PETSC_TRUE;
926         for (k=0;k<graph->count[j];k++){
927           if (graph->neighbours_set[i][k]!=graph->neighbours_set[j][k]) {
928             same_set=PETSC_FALSE;
929           }
930         }
931         /* I found a friend of mine */
932         if (same_set) {
933           graph->subset[j]=graph->ncc+1;
934           ierr = PetscBTSet(graph->touched,j);CHKERRQ(ierr);
935           nodes_touched++;
936           graph->queue[total_counts] = j;
937           total_counts++;
938         }
939       }
940     }
941     graph->ncc++;
942   }
943   /* set default number of subsets (at this point no info on csr graph has been taken into account, so n_subsets = ncc */
944   graph->n_subsets = graph->ncc;
945   ierr = PetscMalloc1(graph->n_subsets,&graph->subset_ncc);CHKERRQ(ierr);
946   for (i=0;i<graph->n_subsets;i++) {
947     graph->subset_ncc[i] = 1;
948   }
949   /* final pointer */
950   graph->cptr[graph->ncc] = total_counts;
951   /* free memory allocated by ISLocalToGlobalMappingGetInfo */
952   ierr = ISLocalToGlobalMappingRestoreInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr);
953   /* get a reference node (min index in global ordering) for each subset */
954   ierr = PetscMalloc1(graph->ncc,&graph->subset_ref_node);CHKERRQ(ierr);
955   ierr = PetscMalloc1(graph->cptr[graph->ncc],&queue_global);CHKERRQ(ierr);
956   ierr = ISLocalToGlobalMappingApply(graph->l2gmap,graph->cptr[graph->ncc],graph->queue,queue_global);CHKERRQ(ierr);
957   for (i=0;i<graph->ncc;i++) {
958     PetscInt minval = queue_global[graph->cptr[i]];
959     for (j=graph->cptr[i]+1;j<graph->cptr[i+1];j++) {
960       minval = PetscMin(minval,queue_global[j]);
961     }
962     graph->subset_ref_node[i] = minval;
963   }
964   ierr = PetscFree(queue_global);CHKERRQ(ierr);
965   /* free objects */
966   ierr = VecDestroy(&local_vec);CHKERRQ(ierr);
967   ierr = VecDestroy(&local_vec2);CHKERRQ(ierr);
968   ierr = VecDestroy(&global_vec);CHKERRQ(ierr);
969   ierr = VecScatterDestroy(&scatter_ctx);CHKERRQ(ierr);
970   PetscFunctionReturn(0);
971 }
972 
973 #undef __FUNCT__
974 #define __FUNCT__ "PCBDDCGraphResetCSR"
975 PetscErrorCode PCBDDCGraphResetCSR(PCBDDCGraph graph)
976 {
977   PetscErrorCode ierr;
978 
979   PetscFunctionBegin;
980   ierr = PetscFree(graph->xadj);CHKERRQ(ierr);
981   ierr = PetscFree(graph->adjncy);CHKERRQ(ierr);
982   graph->nvtxs_csr = 0;
983   PetscFunctionReturn(0);
984 }
985 
986 #undef __FUNCT__
987 #define __FUNCT__ "PCBDDCGraphReset"
988 PetscErrorCode PCBDDCGraphReset(PCBDDCGraph graph)
989 {
990   PetscErrorCode ierr;
991 
992   PetscFunctionBegin;
993   ierr = ISLocalToGlobalMappingDestroy(&graph->l2gmap);CHKERRQ(ierr);
994   ierr = PetscFree(graph->subset_ncc);CHKERRQ(ierr);
995   ierr = PetscFree(graph->subset_ref_node);CHKERRQ(ierr);
996   if (graph->nvtxs) {
997     ierr = PetscFree(graph->neighbours_set[0]);CHKERRQ(ierr);
998   }
999   ierr = PetscBTDestroy(&graph->touched);CHKERRQ(ierr);
1000   ierr = PetscFree7(graph->count,
1001                     graph->neighbours_set,
1002                     graph->subset,
1003                     graph->which_dof,
1004                     graph->cptr,
1005                     graph->queue,
1006                     graph->special_dof);CHKERRQ(ierr);
1007   if (graph->mirrors) {
1008     ierr = PetscFree(graph->mirrors_set[0]);CHKERRQ(ierr);
1009   }
1010   ierr = PetscFree2(graph->mirrors,graph->mirrors_set);CHKERRQ(ierr);
1011   graph->nvtxs = 0;
1012   graph->n_subsets = 0;
1013   graph->custom_minimal_size = 1;
1014   PetscFunctionReturn(0);
1015 }
1016 
1017 #undef __FUNCT__
1018 #define __FUNCT__ "PCBDDCGraphInit"
1019 PetscErrorCode PCBDDCGraphInit(PCBDDCGraph graph, ISLocalToGlobalMapping l2gmap)
1020 {
1021   PetscInt       n;
1022   PetscErrorCode ierr;
1023 
1024   PetscFunctionBegin;
1025   PetscValidPointer(graph,1);
1026   PetscValidHeaderSpecific(l2gmap,IS_LTOGM_CLASSID,2);
1027   /* raise an error if already allocated */
1028   if (graph->nvtxs) {
1029     SETERRQ(PetscObjectComm((PetscObject)l2gmap),PETSC_ERR_PLIB,"BDDCGraph already initialized");
1030   }
1031   /* set number of vertices */
1032   ierr = PetscObjectReference((PetscObject)l2gmap);CHKERRQ(ierr);
1033   graph->l2gmap = l2gmap;
1034   ierr = ISLocalToGlobalMappingGetSize(l2gmap,&n);CHKERRQ(ierr);
1035   graph->nvtxs = n;
1036   /* allocate used space */
1037   ierr = PetscBTCreate(graph->nvtxs,&graph->touched);CHKERRQ(ierr);
1038   ierr = PetscMalloc7(graph->nvtxs,&graph->count,
1039                       graph->nvtxs,&graph->neighbours_set,
1040                       graph->nvtxs,&graph->subset,
1041                       graph->nvtxs,&graph->which_dof,
1042                       graph->nvtxs+1,&graph->cptr,
1043                       graph->nvtxs,&graph->queue,
1044                       graph->nvtxs,&graph->special_dof);CHKERRQ(ierr);
1045   /* zeroes memory */
1046   ierr = PetscMemzero(graph->count,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
1047   ierr = PetscMemzero(graph->subset,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
1048   /* use -1 as a default value for which_dof array */
1049   for (n=0;n<graph->nvtxs;n++) graph->which_dof[n] = -1;
1050   ierr = PetscMemzero(graph->cptr,(graph->nvtxs+1)*sizeof(PetscInt));CHKERRQ(ierr);
1051   ierr = PetscMemzero(graph->queue,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
1052   ierr = PetscMemzero(graph->special_dof,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr);
1053   /* zeroes first pointer to neighbour set */
1054   if (graph->nvtxs) {
1055     graph->neighbours_set[0] = 0;
1056   }
1057   /* zeroes workspace for values of ncc */
1058   graph->subset_ncc = 0;
1059   graph->subset_ref_node = 0;
1060   PetscFunctionReturn(0);
1061 }
1062 
1063 #undef __FUNCT__
1064 #define __FUNCT__ "PCBDDCGraphDestroy"
1065 PetscErrorCode PCBDDCGraphDestroy(PCBDDCGraph* graph)
1066 {
1067   PetscErrorCode ierr;
1068 
1069   PetscFunctionBegin;
1070   ierr = PCBDDCGraphReset(*graph);CHKERRQ(ierr);
1071   ierr = PetscFree(*graph);CHKERRQ(ierr);
1072   PetscFunctionReturn(0);
1073 }
1074 
1075 #undef __FUNCT__
1076 #define __FUNCT__ "PCBDDCGraphCreate"
1077 PetscErrorCode PCBDDCGraphCreate(PCBDDCGraph *graph)
1078 {
1079   PCBDDCGraph    new_graph;
1080   PetscErrorCode ierr;
1081 
1082   PetscFunctionBegin;
1083   ierr = PetscMalloc(sizeof(*new_graph),&new_graph);CHKERRQ(ierr);
1084   /* local to global mapping of dofs */
1085   new_graph->l2gmap = 0;
1086   /* vertex size */
1087   new_graph->nvtxs = 0;
1088   new_graph->n_subsets = 0;
1089   new_graph->custom_minimal_size = 1;
1090   /* zeroes ponters */
1091   new_graph->mirrors = 0;
1092   new_graph->mirrors_set = 0;
1093   new_graph->neighbours_set = 0;
1094   new_graph->subset = 0;
1095   new_graph->which_dof = 0;
1096   new_graph->special_dof = 0;
1097   new_graph->cptr = 0;
1098   new_graph->queue = 0;
1099   new_graph->count = 0;
1100   new_graph->subset_ncc = 0;
1101   new_graph->subset_ref_node = 0;
1102   new_graph->touched = 0;
1103   /* zeroes pointers to csr graph of local nodes connectivity (optional data) */
1104   new_graph->nvtxs_csr = 0;
1105   new_graph->xadj = 0;
1106   new_graph->adjncy = 0;
1107   *graph = new_graph;
1108   PetscFunctionReturn(0);
1109 }
1110