xref: /petsc/src/dm/impls/network/network.c (revision efa12513287cff49a2b9648ae83199dcbfaad71a)
1 #include <petsc/private/dmnetworkimpl.h>  /*I  "petscdmnetwork.h"  I*/
2 
3 /*@
4   DMNetworkGetPlex - Gets the Plex DM associated with this network DM
5 
6   Not collective
7 
8   Input Parameters:
9 . dm - the dm object
10 
11   Output Parameters:
12 . plexdm - the plex dm object
13 
14   Level: Advanced
15 
16 .seealso: DMNetworkCreate()
17 @*/
18 PetscErrorCode DMNetworkGetPlex(DM dm,DM *plexdm)
19 {
20   DM_Network *network = (DM_Network*)dm->data;
21 
22   PetscFunctionBegin;
23   *plexdm = network->plex;
24   PetscFunctionReturn(0);
25 }
26 
27 /*@
28   DMNetworkGetNumSubNetworks - Gets the the number of subnetworks
29 
30   Not collective
31 
32   Input Parameters:
33 . dm - the dm object
34 
35   Output Parameters:
36 + nsubnet - local number of subnetworks
37 - Nsubnet - global number of subnetworks
38 
39   Level: beginner
40 
41 .seealso: DMNetworkCreate(), DMNetworkSetNumSubNetworks()
42 @*/
43 PetscErrorCode DMNetworkGetNumSubNetworks(DM dm,PetscInt *nsubnet,PetscInt *Nsubnet)
44 {
45   DM_Network *network = (DM_Network*)dm->data;
46 
47   PetscFunctionBegin;
48   if (nsubnet) *nsubnet = network->nsubnet;
49   if (Nsubnet) *Nsubnet = network->Nsubnet;
50   PetscFunctionReturn(0);
51 }
52 
53 /*@
54   DMNetworkSetNumSubNetworks - Sets the number of subnetworks
55 
56   Collective on dm
57 
58   Input Parameters:
59 + dm - the dm object
60 . nsubnet - local number of subnetworks
61 - Nsubnet - global number of subnetworks
62 
63    Level: beginner
64 
65 .seealso: DMNetworkCreate(), DMNetworkGetNumSubNetworks()
66 @*/
67 PetscErrorCode DMNetworkSetNumSubNetworks(DM dm,PetscInt nsubnet,PetscInt Nsubnet)
68 {
69   PetscErrorCode ierr;
70   DM_Network     *network = (DM_Network*)dm->data;
71 
72   PetscFunctionBegin;
73   if (network->Nsubnet != 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Network sizes alread set, cannot resize the network");
74 
75   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
76   PetscValidLogicalCollectiveInt(dm,nsubnet,2);
77   PetscValidLogicalCollectiveInt(dm,Nsubnet,3);
78 
79   if (Nsubnet == PETSC_DECIDE) {
80     if (nsubnet < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of local subnetworks %D cannot be less than 0",nsubnet);
81     ierr = MPIU_Allreduce(&nsubnet,&Nsubnet,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
82   }
83   if (Nsubnet < 1) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Number of global subnetworks %D cannot be less than 1",Nsubnet);
84 
85   network->Nsubnet  = Nsubnet;
86   network->nsubnet  = 0;       /* initia value; will be determind by DMNetworkAddSubnetwork() */
87   ierr = PetscCalloc1(Nsubnet,&network->subnet);CHKERRQ(ierr);
88 
89   /* num of shared vertices */
90   network->nsvtx = 0;
91   network->Nsvtx = 0;
92   PetscFunctionReturn(0);
93 }
94 
95 /*@
96   DMNetworkAddSubnetwork - Add a subnetwork
97 
98   Collective on dm
99 
100   Input Parameters:
101 + dm - the dm object
102 . name - name of the subnetwork
103 . nv - number of local vertices of this subnetwork
104 . ne - number of local edges of this subnetwork
105 - edgelist - list of edges for this subnetwork
106 
107   Output Parameters:
108 . netnum - global index of the subnetwork
109 
110   Notes:
111   There is no copy involved in this operation, only the pointer is referenced. The edgelist should
112   not be destroyed before the call to DMNetworkLayoutSetUp()
113 
114   Level: beginner
115 
116   Example usage:
117   Consider the following network:
118 .vb
119  network 1: v1 -> v2 -> v0
120 .ve
121 
122  The resulting input
123    edgelist = [1 2 | 2 0]
124 
125 .seealso: DMNetworkCreate(), DMNetworkSetNumSubnetworks()
126 @*/
127 PetscErrorCode DMNetworkAddSubnetwork(DM dm,const char* name,PetscInt nv,PetscInt ne,PetscInt edgelist[],PetscInt *netnum)
128 {
129   PetscErrorCode ierr;
130   DM_Network     *network = (DM_Network*)dm->data;
131   PetscInt       i = network->nsubnet,a[2],b[2];
132 
133   PetscFunctionBegin;
134   if (name) {
135     ierr = PetscStrcpy(network->subnet[i].name,name);CHKERRQ(ierr);
136   }
137 
138   network->subnet[i].nvtx     = nv;
139   network->subnet[i].nedge    = ne;
140   network->subnet[i].edgelist = edgelist;
141 
142   /* Get global number of vertices and edges for subnet[i] */
143   a[0] = nv; a[1] = ne;
144   ierr = MPIU_Allreduce(a,b,2,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
145   network->subnet[i].Nvtx  = b[0];
146   network->subnet[i].Nedge = b[1];
147 
148   /* ----------------------------------------------------------
149    p=v or e;
150    subnet[0].pStart   = 0
151    subnet[i+1].pStart = subnet[i].pEnd = subnet[i].pStart + (nE[i] or NV[i])
152    ----------------------------------------------------------------------- */
153   /* GLOBAL subnet[].vStart and vEnd, used by DMNetworkLayoutSetUp() */
154   network->subnet[i].vStart = network->NVertices;
155   network->subnet[i].vEnd   = network->subnet[i].vStart + network->subnet[i].Nvtx; /* global vEnd of subnet[i] */
156 
157   network->nVertices += nv;
158   network->NVertices += network->subnet[i].Nvtx;
159 
160   /* LOCAL subnet[].eStart and eEnd, used by DMNetworkLayoutSetUp() */
161   network->subnet[i].eStart = network->nEdges;
162   network->subnet[i].eEnd   = network->subnet[i].eStart + ne;
163   network->nEdges += ne;
164   network->NEdges += network->subnet[i].Nedge;
165 
166   ierr = PetscStrcpy(network->subnet[i].name,name);CHKERRQ(ierr);
167   if (netnum) *netnum = network->nsubnet;
168   network->nsubnet++;
169   PetscFunctionReturn(0);
170 }
171 
172 /*
173   SetUp a single svtx struct. See SVtx defined in dmnetworkimpl.h
174   Set gidx and type if input v=(net,idx) is a from_vertex;
175   Get gid, type and index in the svtx array if input v=(net,idx) is a to_vertex.
176 
177   Input:  Nsvtx, svtx, net, idx, gidx
178   Output: gidx, svtype, svtx_idx
179  */
180 static PetscErrorCode SVtxSetUp(PetscInt Nsvtx,SVtx *svtx,PetscInt net,PetscInt idx,PetscInt *gidx,SVtxType *svtype,PetscInt *svtx_idx)
181 {
182   PetscInt i,j,*svto;
183   SVtxType vtype;
184 
185   PetscFunctionBegin;
186   if (!Nsvtx) PetscFunctionReturn(0);
187 
188   vtype = SVNONE;
189   for (i=0; i<Nsvtx; i++) {
190     if (net == svtx[i].sv[0] && idx == svtx[i].sv[1]) {
191       /* (1) input vertex net.idx is a shared from_vertex, set its global index and output its svtype */
192       svtx[i].gidx = *gidx; /* set gidx */
193       vtype        = SVFROM;
194     } else { /* loop over svtx[i].n */
195       for (j=1; j<svtx[i].n; j++) {
196         svto = svtx[i].sv + 2*j;
197         if (net == svto[0] && idx == svto[1]) {
198           /* input vertex net.idx is a shared to_vertex, output its global index and its svtype */
199           *gidx = svtx[i].gidx; /* output gidx for to_vertex */
200           vtype = SVTO;
201         }
202       }
203     }
204     if (vtype != SVNONE) break;
205   }
206   if (svtype)   *svtype   = vtype;
207   if (svtx_idx) *svtx_idx = i;
208   PetscFunctionReturn(0);
209 }
210 
211 /*
212  Add a new shared vertex sv=(net,idx) to table svtas[ita]
213 */
214 static PetscErrorCode TableAddSVtx(PetscTable *svtas,PetscInt ita,PetscInt* tdata,PetscInt *sv_wk,PetscInt *ii,PetscInt *sedgelist,PetscInt k,DM_Network *network,PetscInt **ta2sv)
215 {
216   PetscInt       net,idx,gidx,i=*ii;
217   PetscErrorCode ierr;
218 
219   PetscFunctionBegin;
220   net = sv_wk[2*i]   = sedgelist[k];
221   idx = sv_wk[2*i+1] = sedgelist[k+1];
222   gidx = network->subnet[net].vStart + idx;
223   ierr = PetscTableAdd(svtas[ita],gidx+1,tdata[ita]+1,INSERT_VALUES);CHKERRQ(ierr);
224   *(ta2sv[ita] + tdata[ita]) = i; /* maps tdata to index of sv_wk; sv_wk keeps (net,idx) info */
225   tdata[ita]++; (*ii)++;
226   PetscFunctionReturn(0);
227 }
228 
229 /*
230   Create an array of shared vertices. See SVtx and SVtxType in dmnetworkimpl.h
231 
232   Input:  dm, Nsedgelist, sedgelist
233   Output: Nsvtx,svtx
234 
235   Note: Output svtx is organized as
236         sv(net[0],idx[0]) --> sv(net[1],idx[1])
237                           --> sv(net[1],idx[1])
238                           ...
239                           --> sv(net[n-1],idx[n-1])
240         and net[0] < net[1] < ... < net[n-1]
241         where sv[0] has SVFROM type, sv[i], i>0, has SVTO type.
242  */
243 static PetscErrorCode SVtxCreate(DM dm,PetscInt Nsedgelist,PetscInt *sedgelist,PetscInt *Nsvtx,SVtx **svtx)
244 {
245   PetscErrorCode ierr;
246   SVtx           *sedges = NULL;
247   PetscInt       *sv,k,j,nsv,*tdata,**ta2sv;
248   PetscTable     *svtas;
249   PetscInt       gidx,net,idx,i,nta,ita,idx_from,idx_to,n,*sv_wk;
250   DM_Network     *network = (DM_Network*)dm->data;
251   PetscTablePosition ppos;
252 
253   PetscFunctionBegin;
254   /* (1) Crete ctables svtas */
255   ierr = PetscCalloc4(Nsedgelist,&svtas,Nsedgelist,&tdata,4*Nsedgelist,&sv_wk,2*Nsedgelist,&ta2sv);CHKERRQ(ierr);
256 
257   j   = 0;   /* sedgelist counter */
258   k   = 0;   /* sedgelist vertex counter j = 4*k */
259   i   = 0;   /* sv_wk (vertices added to the ctables) counter */
260   nta = 0;   /* num of sv tables created */
261 
262   /* for j=0 */
263   ierr = PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]);CHKERRQ(ierr);
264   ierr = PetscMalloc1(2*Nsedgelist,&ta2sv[nta]);CHKERRQ(ierr);
265 
266   ierr = TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);CHKERRQ(ierr);
267   ierr = TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);CHKERRQ(ierr);
268   nta++; k += 4;
269 
270   for (j = 1; j < Nsedgelist; j++) {
271     for (ita = 0; ita < nta; ita++) {
272       /* vfrom */
273       net = sedgelist[k]; idx = sedgelist[k+1];
274       gidx = network->subnet[net].vStart + idx; /* global index of the vertex net.idx before merging shared vertices */
275       ierr = PetscTableFind(svtas[ita],gidx+1,&idx_from);CHKERRQ(ierr);
276 
277       /* vto */
278       net = sedgelist[k+2]; idx = sedgelist[k+3];
279       gidx = network->subnet[net].vStart + idx;
280       ierr = PetscTableFind(svtas[ita],gidx+1,&idx_to);CHKERRQ(ierr);
281 
282       if (idx_from || idx_to) { /* vfrom or vto is on table svtas[ita] */
283         idx_from--; idx_to--;
284         if (idx_from < 0) { /* vto is on svtas[ita] */
285           ierr = TableAddSVtx(svtas,ita,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);CHKERRQ(ierr);
286           break;
287         } else if (idx_to < 0) {
288           ierr = TableAddSVtx(svtas,ita,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);CHKERRQ(ierr);
289           break;
290         }
291       }
292     }
293 
294     if (ita == nta) {
295       ierr = PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]);CHKERRQ(ierr);
296       ierr = PetscMalloc1(2*Nsedgelist, &ta2sv[nta]);CHKERRQ(ierr);
297 
298       ierr = TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);CHKERRQ(ierr);
299       ierr = TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);CHKERRQ(ierr);
300       nta++;
301     }
302     k += 4;
303   }
304 
305   /* (2) Construct sedges from ctable
306      sedges: edges connect vertex sv[0]=(net[0],idx[0]) to vertices sv[k], k=1,...,n-1;
307      net[k], k=0, ...,n-1, are in ascending order */
308   ierr = PetscMalloc1(nta,&sedges);CHKERRQ(ierr);
309   for (nsv = 0; nsv < nta; nsv++) {
310     /* for a single svtx, put shared vertices in ascending order of gidx */
311     ierr = PetscTableGetCount(svtas[nsv],&n);CHKERRQ(ierr);
312     ierr = PetscCalloc1(2*n,&sv);CHKERRQ(ierr);
313     sedges[nsv].sv   = sv;
314     sedges[nsv].n    = n;
315     sedges[nsv].gidx = -1; /* initialization */
316 
317     ierr = PetscTableGetHeadPosition(svtas[nsv],&ppos);CHKERRQ(ierr);
318     for (k=0; k<n; k++) { /* gidx is sorted in ascending order */
319       ierr = PetscTableGetNext(svtas[nsv],&ppos,&gidx,&i);CHKERRQ(ierr);
320       gidx--; i--;
321 
322       j = ta2sv[nsv][i]; /* maps i to index of sv_wk */
323       sv[2*k]   = sv_wk[2*j];
324       sv[2*k+1] = sv_wk[2*j + 1];
325     }
326   }
327 
328   for (j=0; j<nta; j++) {
329     ierr = PetscTableDestroy(&svtas[j]);CHKERRQ(ierr);
330     ierr = PetscFree(ta2sv[j]);CHKERRQ(ierr);
331   }
332   ierr = PetscFree4(svtas,tdata,sv_wk,ta2sv);CHKERRQ(ierr);
333 
334   *Nsvtx = nta;
335   *svtx  = sedges;
336   PetscFunctionReturn(0);
337 }
338 
339 static PetscErrorCode DMNetworkLayoutSetUp_Coupling(DM dm)
340 {
341   PetscErrorCode ierr;
342   DM_Network     *network = (DM_Network*)dm->data;
343   PetscInt       i,j,ctr,np,*edges,*subnetvtx,vStart;
344   PetscInt       k,*vidxlTog,Nsv=0,Nsubnet=network->Nsubnet;
345   PetscInt       *sedgelist=network->sedgelist;
346   const PetscInt *cone;
347   MPI_Comm       comm;
348   PetscMPIInt    size,rank,*recvcounts=NULL,*displs=NULL;
349   PetscInt       net,idx,gidx,nmerged,e,v,vfrom,vto,*vrange,*eowners,gidx_from,net_from,sv_idx;
350   SVtxType       svtype = SVNONE;
351   SVtx           *svtx=NULL;
352   PetscSection   sectiong;
353 
354   PetscFunctionBegin;
355   /* This implementation requires user input each subnet by a single processor, thus subnet[net].nvtx=subnet[net].Nvtx */
356   for (net=0; net<Nsubnet; net++) {
357     if (network->subnet[net].nvtx && network->subnet[net].nvtx != network->subnet[net].Nvtx) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"subnetwork %D local num of vertices %D != %D global num",net,network->subnet[net].nvtx,network->subnet[net].Nvtx);
358   }
359 
360   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
361   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
362   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
363 
364   /* (1) Create svtx[] from sedgelist */
365   /* -------------------------------- */
366   /* Nsv: global number of SVtx; svtx: shared vertices, see SVtx in dmnetworkimpl.h */
367   ierr = SVtxCreate(dm,network->Nsvtx,sedgelist,&Nsv,&svtx);CHKERRQ(ierr);
368 
369   /* (2) Setup svtx; Shared vto vertices are merged to their vfrom vertex with same global vetex index (gidx) */
370   /* -------------------------------------------------------------------------------------------------------- */
371   /* (2.1) compute vrage[rank]: global index of 1st local vertex in proc[rank] */
372   ierr = PetscMalloc3(size+1,&vrange,size,&displs,size,&recvcounts);CHKERRQ(ierr);
373   for (i=0; i<size; i++) {displs[i] = i; recvcounts[i] = 1;}
374 
375   vrange[0] = 0;
376   ierr = MPI_Allgatherv(&network->nVertices,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm);CHKERRMPI(ierr);
377   for (i=2; i<size+1; i++) {
378     vrange[i] += vrange[i-1];
379   }
380 
381   /* (2.2) Create vidxlTog: maps UN-MERGED local vertex index i to global index gidx (plex, excluding ghost vertices) */
382   ierr = PetscMalloc1(network->nVertices,&vidxlTog);CHKERRQ(ierr);
383   i = 0; gidx = 0;
384   nmerged = 0; /* local num of merged vertices */
385   network->nsvtx = 0;
386   for (net=0; net<Nsubnet; net++) {
387     for (idx=0; idx<network->subnet[net].Nvtx; idx++) {
388       gidx_from = gidx;
389       sv_idx    = -1;
390 
391       ierr = SVtxSetUp(Nsv,svtx,net,idx,&gidx_from,&svtype,&sv_idx);CHKERRQ(ierr);
392       if (svtype == SVTO) {
393         if (network->subnet[net].nvtx) {/* this proc owns sv_to */
394           net_from = svtx[sv_idx].sv[0]; /* subnet num of its shared vertex */
395           if (network->subnet[net_from].nvtx == 0) {
396             /* this proc does not own v_from, thus a new local coupling vertex */
397             network->nsvtx++;
398           }
399           vidxlTog[i++] = gidx_from;
400           nmerged++; /* a coupling vertex -- merged */
401         }
402       } else {
403         if (svtype == SVFROM) {
404           if (network->subnet[net].nvtx) {
405             /* this proc owns this v_from, a new local coupling vertex */
406             network->nsvtx++;
407           }
408         }
409         if (network->subnet[net].nvtx) vidxlTog[i++] = gidx;
410         gidx++;
411       }
412     }
413   }
414 #if defined(PETSC_USE_DEBUG)
415   if (i != network->nVertices) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"%D != %D nVertices",i,network->nVertices);
416 #endif
417 
418   /* (2.3) Setup svtable for querry shared vertices */
419   for (v=0; v<Nsv; v++) {
420     gidx = svtx[v].gidx;
421     ierr = PetscTableAdd(network->svtable,gidx+1,v+1,INSERT_VALUES);CHKERRQ(ierr);
422   }
423 
424   /* (2.4) Shared vertices in the subnetworks are merged, update global NVertices: np = sum(local nmerged) */
425   ierr = MPI_Allreduce(&nmerged,&np,1,MPIU_INT,MPI_SUM,comm);CHKERRMPI(ierr);
426   network->NVertices -= np;
427 
428   ierr = PetscCalloc1(2*network->nEdges,&edges);CHKERRQ(ierr);
429   ierr = PetscCalloc1(network->nVertices+network->nsvtx,&network->subnetvtx);CHKERRQ(ierr);
430 
431   ctr = 0;
432   for (net=0; net<Nsubnet; net++) {
433     for (j = 0; j < network->subnet[net].nedge; j++) {
434       /* vfrom: */
435       i = network->subnet[net].edgelist[2*j] + (network->subnet[net].vStart - vrange[rank]);
436       edges[2*ctr] = vidxlTog[i];
437 
438       /* vto */
439       i = network->subnet[net].edgelist[2*j+1] + (network->subnet[net].vStart - vrange[rank]);
440       edges[2*ctr+1] = vidxlTog[i];
441       ctr++;
442     }
443   }
444   ierr = PetscFree3(vrange,displs,recvcounts);CHKERRQ(ierr);
445   ierr = PetscFree(vidxlTog);CHKERRQ(ierr);
446 
447   /* (3) Create network->plex */
448   ierr = DMCreate(comm,&network->plex);CHKERRQ(ierr);
449   ierr = DMSetType(network->plex,DMPLEX);CHKERRQ(ierr);
450   ierr = DMSetDimension(network->plex,1);CHKERRQ(ierr);
451   if (size == 1) {
452     ierr = DMPlexBuildFromCellList(network->plex,network->nEdges,network->nVertices-nmerged,2,edges);CHKERRQ(ierr);
453   } else {
454     ierr = DMPlexBuildFromCellListParallel(network->plex,network->nEdges,network->nVertices-nmerged,PETSC_DECIDE,2,edges,NULL);CHKERRQ(ierr);
455   }
456 
457   ierr = DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);CHKERRQ(ierr);
458   ierr = DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);CHKERRQ(ierr);
459   ierr = DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);CHKERRQ(ierr);
460   vStart = network->vStart;
461 
462   ierr = PetscSectionCreate(comm,&network->DataSection);CHKERRQ(ierr);
463   ierr = PetscSectionCreate(comm,&network->DofSection);CHKERRQ(ierr);
464   ierr = PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);CHKERRQ(ierr);
465   ierr = PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);CHKERRQ(ierr);
466 
467   network->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
468   np = network->pEnd - network->pStart;
469   ierr = PetscCalloc2(np,&network->header,np,&network->cvalue);CHKERRQ(ierr);
470 
471   /* (4) Create vidxlTog: maps MERGED plex local vertex index (including ghosts) to User's global vertex index (without merging shared vertices) */
472   np = network->vEnd - vStart; /* include ghost vertices */
473   ierr = PetscMalloc2(np,&vidxlTog,size+1,&eowners);CHKERRQ(ierr);
474 
475   ctr = 0;
476   for (e=network->eStart; e<network->eEnd; e++) {
477     ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
478     vidxlTog[cone[0] - vStart] = edges[2*ctr];
479     vidxlTog[cone[1] - vStart] = edges[2*ctr+1];
480     ctr++;
481   }
482   ierr = PetscFree(edges);CHKERRQ(ierr);
483 
484   /* (5) Create vertices and edges array for the subnetworks */
485   subnetvtx = network->subnetvtx;
486   for (j=0; j < Nsubnet; j++) {
487     ierr = PetscCalloc1(network->subnet[j].nedge,&network->subnet[j].edges);CHKERRQ(ierr);
488     network->subnet[j].vertices = subnetvtx;
489     subnetvtx                  += network->subnet[j].nvtx;
490   }
491   network->svertices                = subnetvtx;
492 
493   /* Get edge ownership */
494   np = network->eEnd - network->eStart; /* num of local edges */
495   ierr = MPI_Allgather(&np,1,MPIU_INT,eowners+1,1,MPIU_INT,comm);CHKERRMPI(ierr);
496   eowners[0] = 0;
497   for (i=2; i<=size; i++) eowners[i] += eowners[i-1];
498 
499   e = 0;
500   for (i=0; i < Nsubnet; i++) {
501     v = 0;
502     for (j = 0; j < network->subnet[i].nedge; j++) {
503 
504       /* edge e */
505       network->header[e].index    = e + eowners[rank]; /* Global edge index */
506       network->header[e].subnetid = i;                 /* Subnetwork id */
507       network->subnet[i].edges[j] = e;
508       network->header[e].ndata           = 0;
509       network->header[e].offset[0]       = 0;
510       network->header[e].offsetvarrel[0] = 0;
511       ierr = PetscSectionAddDof(network->DataSection,e,network->dataheadersize);CHKERRQ(ierr);
512 
513       /* connected vertices */
514       ierr = DMPlexGetCone(network->plex,e,&cone);CHKERRQ(ierr);
515 
516       /* vertex cone[0] */
517       vfrom = network->subnet[i].edgelist[2*v];
518       network->header[cone[0]].index = vidxlTog[cone[0]-vStart]; /*  Global vertex index */
519       network->header[cone[0]].subnetid = i;                     /* Subnetwork id */
520       network->subnet[i].vertices[vfrom] = cone[0];              /* user's subnet[].dix = petsc's v */
521 
522       /* vertex cone[1] */
523       vto = network->subnet[i].edgelist[2*v+1];
524       network->header[cone[1]].index = vidxlTog[cone[1]-vStart]; /*  Global vertex index */
525       network->header[cone[1]].subnetid   = i;
526       network->subnet[i].vertices[vto]= cone[1];
527 
528       e++; v++;
529     }
530   }
531 
532   /* Set vertex array for the subnetworks */
533   k = 0;
534   for (v=vStart; v<network->vEnd; v++) { /* local vertices, including ghosts */
535     network->header[v].ndata           = 0;
536     network->header[v].offset[0]       = 0;
537     network->header[v].offsetvarrel[0] = 0;
538     ierr = PetscSectionAddDof(network->DataSection,v,network->dataheadersize);CHKERRQ(ierr);
539 
540     /* shared vertex */
541     ierr = PetscTableFind(network->svtable,vidxlTog[v-vStart]+1,&i);CHKERRQ(ierr);
542     if (i) network->svertices[k++] = v;
543   }
544 #if defined(PETSC_USE_DEBUG)
545   if (k != network->nsvtx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"k %D != %D nsvtx",k,network->nsvtx);
546 #endif
547 
548   ierr = PetscFree2(vidxlTog,eowners);CHKERRQ(ierr);
549 
550   network->svtx  = svtx;
551   network->Nsvtx = Nsv;
552   ierr = PetscFree(sedgelist);CHKERRQ(ierr);
553 
554   /* Create a global section to be used by DMNetworkIsGhostVertex() which is a non-collective routine */
555   ierr = DMGetGlobalSection(network->plex,&sectiong);CHKERRQ(ierr);
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560   DMNetworkLayoutSetUp - Sets up the bare layout (graph) for the network
561 
562   Collective on dm
563 
564   Input Parameters:
565 . DM - the dmnetwork object
566 
567   Notes:
568   This routine should be called after the network sizes and edgelists have been provided. It creates
569   the bare layout of the network and sets up the network to begin insertion of components.
570 
571   All the components should be registered before calling this routine.
572 
573   Level: beginner
574 
575 .seealso: DMNetworkSetNumSubNetworks(), DMNetworkAddSubnetwork()
576 @*/
577 PetscErrorCode DMNetworkLayoutSetUp(DM dm)
578 {
579   PetscErrorCode ierr;
580   DM_Network     *network = (DM_Network*)dm->data;
581   PetscInt       i,j,ctr,Nsubnet=network->Nsubnet,*eowners,np,*edges,*subnetvtx;
582   PetscInt       e,v,vfrom,vto;
583   const PetscInt *cone;
584   MPI_Comm       comm;
585   PetscMPIInt    size,rank;
586 
587   PetscFunctionBegin;
588   if (network->nsubnet != network->Nsubnet) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Must call DMNetworkAddSubnetwork() %D times",network->Nsubnet);
589 
590   /* Create svtable for querry shared vertices */
591   ierr = PetscTableCreate(network->Nsvtx,network->NVertices+1,&network->svtable);CHKERRQ(ierr);
592 
593   if (network->Nsvtx) {
594     ierr = DMNetworkLayoutSetUp_Coupling(dm);CHKERRQ(ierr);
595     PetscFunctionReturn(0);
596   }
597 
598   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
599   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
600   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
601 
602   /* Create LOCAL edgelist for the network by concatenating local input edgelists of the subnetworks */
603   ierr = PetscCalloc1(2*network->nEdges,&edges);CHKERRQ(ierr);
604   ctr = 0;
605   for (i=0; i < Nsubnet; i++) {
606     for (j = 0; j < network->subnet[i].nedge; j++) {
607       edges[2*ctr]   = network->subnet[i].vStart + network->subnet[i].edgelist[2*j];
608       edges[2*ctr+1] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j+1];
609       ctr++;
610     }
611   }
612 
613   /* Create network->plex; One dimensional network, numCorners=2 */
614   ierr = DMCreate(comm,&network->plex);CHKERRQ(ierr);
615   ierr = DMSetType(network->plex,DMPLEX);CHKERRQ(ierr);
616   ierr = DMSetDimension(network->plex,1);CHKERRQ(ierr);
617   if (size == 1) {
618     ierr = DMPlexBuildFromCellList(network->plex,network->nEdges,network->nVertices,2,edges);CHKERRQ(ierr);
619   } else {
620     ierr = DMPlexBuildFromCellListParallel(network->plex,network->nEdges,network->nVertices,PETSC_DECIDE,2,edges,NULL);CHKERRQ(ierr);
621   }
622   ierr = PetscFree(edges);CHKERRQ(ierr); /* local edge list with global idx used by DMPlexBuildFromCellList() */
623 
624   ierr = DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);CHKERRQ(ierr);
625   ierr = DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);CHKERRQ(ierr);
626   ierr = DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);CHKERRQ(ierr);
627 
628   ierr = PetscSectionCreate(comm,&network->DataSection);CHKERRQ(ierr);
629   ierr = PetscSectionCreate(comm,&network->DofSection);CHKERRQ(ierr);
630   ierr = PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);CHKERRQ(ierr);
631   ierr = PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);CHKERRQ(ierr);
632 
633   network->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
634   np = network->pEnd - network->pStart;
635   ierr = PetscCalloc2(np,&network->header,np,&network->cvalue);CHKERRQ(ierr);
636 
637   /* Create edge and vertex arrays for the subnetworks */
638   for (j=0; j < network->Nsubnet; j++) {
639     ierr = PetscCalloc1(network->subnet[j].nedge,&network->subnet[j].edges);CHKERRQ(ierr);
640   }
641 
642   /* Get edge ownership */
643   ierr = PetscMalloc1(size+1,&eowners);CHKERRQ(ierr);
644   np = network->eEnd - network->eStart;
645   ierr = MPI_Allgather(&np,1,MPIU_INT,eowners+1,1,MPIU_INT,comm);CHKERRMPI(ierr);
646   eowners[0] = 0;
647   for (i=2; i<=size; i++) eowners[i] += eowners[i-1];
648 
649   /* Set network->subnet[*].vertices on array network->subnetvtx */
650   np = 0;
651   for (j=0; j<network->Nsubnet; j++) {
652     /* sum up subnet[j].Nvtx instead of subnet[j].nvtx, because a subnet might be owned by more than one processor;
653        below, subnet[i].vertices[vfrom/vto] requires vfrom/vto =0, ...,Nvtx-1
654      */
655     if (network->subnet[j].nvtx) np += network->subnet[j].Nvtx;
656   }
657 
658   ierr = PetscCalloc1(np,&network->subnetvtx);CHKERRQ(ierr); /* Maps local vertex to local subnetwork's vertex */
659   subnetvtx = network->subnetvtx;
660   for (j=0; j<network->Nsubnet; j++) {
661     network->subnet[j].vertices = subnetvtx;
662     if (network->subnet[j].nvtx) subnetvtx += network->subnet[j].Nvtx;
663   }
664 
665   /* Setup edge and vertex arrays for subnetworks */
666   e = 0;
667   for (i=0; i < Nsubnet; i++) {
668     v = 0;
669     for (j = 0; j < network->subnet[i].nedge; j++) {
670       /* edge e */
671       network->header[e].index    = e + eowners[rank];   /* Global edge index */
672       network->header[e].subnetid = i;
673       network->subnet[i].edges[j] = e;
674 
675       network->header[e].ndata           = 0;
676       network->header[e].offset[0]       = 0;
677       network->header[e].offsetvarrel[0] = 0;
678       ierr = PetscSectionAddDof(network->DataSection,e,network->dataheadersize);CHKERRQ(ierr);
679 
680       /* connected vertices */
681       ierr = DMPlexGetCone(network->plex,e,&cone);CHKERRQ(ierr);
682 
683       /* vertex cone[0] */
684       vfrom = network->subnet[i].edgelist[2*v];     /* =subnet[i].idx, Global index! */
685       network->header[cone[0]].index     = vfrom + network->subnet[i].vStart; /* Global vertex index */
686       network->header[cone[0]].subnetid  = i;       /* Subnetwork id */
687       network->subnet[i].vertices[vfrom] = cone[0]; /* user's subnet[].dix = petsc's v */
688 
689       /* vertex cone[1] */
690       vto   = network->subnet[i].edgelist[2*v+1];   /* =subnet[i].idx, Global index! */
691       network->header[cone[1]].index    = vto + network->subnet[i].vStart;  /* Global vertex index */
692       network->header[cone[1]].subnetid = i;
693       network->subnet[i].vertices[vto]  = cone[1];  /* user's subnet[].dix = petsc's v */
694 
695       e++; v++;
696     }
697   }
698   ierr = PetscFree(eowners);CHKERRQ(ierr);
699 
700   for (v = network->vStart; v < network->vEnd; v++) {
701     network->header[v].ndata           = 0;
702     network->header[v].offset[0]       = 0;
703     network->header[v].offsetvarrel[0] = 0;
704     ierr = PetscSectionAddDof(network->DataSection,v,network->dataheadersize);CHKERRQ(ierr);
705   }
706   PetscFunctionReturn(0);
707 }
708 
709 /*@C
710   DMNetworkGetSubnetwork - Returns the information about a requested subnetwork
711 
712   Not collective
713 
714   Input Parameters:
715 + dm - the DM object
716 - netnum - the global index of the subnetwork
717 
718   Output Parameters:
719 + nv - number of vertices (local)
720 . ne - number of edges (local)
721 . vtx - local vertices of the subnetwork
722 - edge - local edges of the subnetwork
723 
724   Notes:
725   Cannot call this routine before DMNetworkLayoutSetup()
726 
727   Level: intermediate
728 
729 .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkLayoutSetUp()
730 @*/
731 PetscErrorCode DMNetworkGetSubnetwork(DM dm,PetscInt netnum,PetscInt *nv,PetscInt *ne,const PetscInt **vtx,const PetscInt **edge)
732 {
733   DM_Network *network = (DM_Network*)dm->data;
734 
735   PetscFunctionBegin;
736   if (netnum >= network->Nsubnet) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Subnet index %D exceeds the num of subnets %D",netnum,network->Nsubnet);
737   if (nv) *nv     = network->subnet[netnum].nvtx;
738   if (ne) *ne     = network->subnet[netnum].nedge;
739   if (vtx) *vtx   = network->subnet[netnum].vertices;
740   if (edge) *edge = network->subnet[netnum].edges;
741   PetscFunctionReturn(0);
742 }
743 
744 /*@
745   DMNetworkAddSharedVertices - Add shared vertices that connect two given subnetworks
746 
747   Collective on dm
748 
749   Input Parameters:
750 + dm - the dm object
751 . anetnum - first subnetwork global numbering returned by DMNetworkAddSubnetwork()
752 . bnetnum - second subnetwork global numbering returned by DMNetworkAddSubnetwork()
753 . nsvtx - number of vertices that are shared by the two subnetworks
754 . asvtx - vertex index in the first subnetwork
755 - bsvtx - vertex index in the second subnetwork
756 
757   Level: beginner
758 
759 .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkGetSharedVertices()
760 @*/
761 PetscErrorCode DMNetworkAddSharedVertices(DM dm,PetscInt anetnum,PetscInt bnetnum,PetscInt nsvtx,PetscInt asvtx[],PetscInt bsvtx[])
762 {
763   PetscErrorCode ierr;
764   DM_Network     *network = (DM_Network*)dm->data;
765   PetscInt       i,nsubnet = network->Nsubnet,*sedgelist,Nsvtx=network->Nsvtx;
766 
767   PetscFunctionBegin;
768   if (anetnum == bnetnum) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Subnetworks must have different netnum");
769   if (anetnum < 0 || bnetnum < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"netnum cannot be negative");
770   if (!Nsvtx) {
771     /* allocate network->sedgelist to hold at most 2*nsubnet pairs of shared vertices */
772     ierr = PetscMalloc1(2*4*nsubnet,&network->sedgelist);CHKERRQ(ierr);
773   }
774 
775   sedgelist = network->sedgelist;
776   for (i=0; i<nsvtx; i++) {
777     sedgelist[4*Nsvtx]   = anetnum; sedgelist[4*Nsvtx+1] = asvtx[i];
778     sedgelist[4*Nsvtx+2] = bnetnum; sedgelist[4*Nsvtx+3] = bsvtx[i];
779     Nsvtx++;
780   }
781   if (Nsvtx > 2*nsubnet) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"allocate more space for coupling edgelist");
782   network->Nsvtx = Nsvtx;
783   PetscFunctionReturn(0);
784 }
785 
786 /*@C
787   DMNetworkGetSharedVertices - Returns the info for the shared vertices
788 
789   Not collective
790 
791   Input Parameters:
792 . dm - the DM object
793 
794   Output Parameters:
795 + nsv - number of local shared vertices
796 - svtx - local shared vertices
797 
798   Notes:
799   Cannot call this routine before DMNetworkLayoutSetup()
800 
801   Level: intermediate
802 
803 .seealso: DMNetworkGetSubnetwork(), DMNetworkLayoutSetUp(), DMNetworkAddSharedVertices()
804 @*/
805 PetscErrorCode DMNetworkGetSharedVertices(DM dm,PetscInt *nsv,const PetscInt **svtx)
806 {
807   DM_Network *net = (DM_Network*)dm->data;
808 
809   PetscFunctionBegin;
810   if (net->Nsvtx) {
811     *nsv  = net->nsvtx;
812     *svtx = net->svertices;
813   } else {
814     *nsv  = 0;
815     *svtx = NULL;
816   }
817   PetscFunctionReturn(0);
818 }
819 
820 /*@C
821   DMNetworkRegisterComponent - Registers the network component
822 
823   Logically collective on dm
824 
825   Input Parameters:
826 + dm - the network object
827 . name - the component name
828 - size - the storage size in bytes for this component data
829 
830    Output Parameters:
831 .  key - an integer key that defines the component
832 
833    Notes
834    This routine should be called by all processors before calling DMNetworkLayoutSetup().
835 
836    Level: beginner
837 
838 .seealso: DMNetworkCreate(), DMNetworkLayoutSetUp()
839 @*/
840 PetscErrorCode DMNetworkRegisterComponent(DM dm,const char *name,size_t size,PetscInt *key)
841 {
842   PetscErrorCode        ierr;
843   DM_Network            *network = (DM_Network*) dm->data;
844   DMNetworkComponent    *component=&network->component[network->ncomponent];
845   PetscBool             flg=PETSC_FALSE;
846   PetscInt              i;
847 
848   PetscFunctionBegin;
849   for (i=0; i < network->ncomponent; i++) {
850     ierr = PetscStrcmp(component->name,name,&flg);CHKERRQ(ierr);
851     if (flg) {
852       *key = i;
853       PetscFunctionReturn(0);
854     }
855   }
856   if (network->ncomponent == MAX_COMPONENTS) {
857     SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Number of components registered exceeds the max %D",MAX_COMPONENTS);
858   }
859 
860   ierr = PetscStrcpy(component->name,name);CHKERRQ(ierr);
861   component->size = size/sizeof(DMNetworkComponentGenericDataType);
862   *key = network->ncomponent;
863   network->ncomponent++;
864   PetscFunctionReturn(0);
865 }
866 
867 /*@
868   DMNetworkGetVertexRange - Get the bounds [start, end) for the local vertices
869 
870   Not Collective
871 
872   Input Parameters:
873 . dm - the DMNetwork object
874 
875   Output Parameters:
876 + vStart - the first vertex point
877 - vEnd - one beyond the last vertex point
878 
879   Level: beginner
880 
881 .seealso: DMNetworkGetEdgeRange()
882 @*/
883 PetscErrorCode DMNetworkGetVertexRange(DM dm,PetscInt *vStart,PetscInt *vEnd)
884 {
885   DM_Network *network = (DM_Network*)dm->data;
886 
887   PetscFunctionBegin;
888   if (vStart) *vStart = network->vStart;
889   if (vEnd) *vEnd = network->vEnd;
890   PetscFunctionReturn(0);
891 }
892 
893 /*@
894   DMNetworkGetEdgeRange - Get the bounds [start, end) for the local edges
895 
896   Not Collective
897 
898   Input Parameters:
899 . dm - the DMNetwork object
900 
901   Output Parameters:
902 + eStart - The first edge point
903 - eEnd - One beyond the last edge point
904 
905   Level: beginner
906 
907 .seealso: DMNetworkGetVertexRange()
908 @*/
909 PetscErrorCode DMNetworkGetEdgeRange(DM dm,PetscInt *eStart,PetscInt *eEnd)
910 {
911   DM_Network *network = (DM_Network*)dm->data;
912 
913   PetscFunctionBegin;
914   if (eStart) *eStart = network->eStart;
915   if (eEnd) *eEnd = network->eEnd;
916   PetscFunctionReturn(0);
917 }
918 
919 static PetscErrorCode DMNetworkGetIndex(DM dm,PetscInt p,PetscInt *index)
920 {
921   PetscErrorCode    ierr;
922   DM_Network        *network = (DM_Network*)dm->data;
923   PetscInt          offsetp;
924   DMNetworkComponentHeader header;
925 
926   PetscFunctionBegin;
927   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE,"Must call DMSetUp() first");
928   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
929   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
930   *index = header->index;
931   PetscFunctionReturn(0);
932 }
933 
934 /*@
935   DMNetworkGetGlobalEdgeIndex - Get the global numbering for the edge on the network
936 
937   Not Collective
938 
939   Input Parameters:
940 + dm - DMNetwork object
941 - p - edge point
942 
943   Output Parameters:
944 . index - the global numbering for the edge
945 
946   Level: intermediate
947 
948 .seealso: DMNetworkGetGlobalVertexIndex()
949 @*/
950 PetscErrorCode DMNetworkGetGlobalEdgeIndex(DM dm,PetscInt p,PetscInt *index)
951 {
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955   ierr = DMNetworkGetIndex(dm,p,index);CHKERRQ(ierr);
956   PetscFunctionReturn(0);
957 }
958 
959 /*@
960   DMNetworkGetGlobalVertexIndex - Get the global numbering for the vertex on the network
961 
962   Not Collective
963 
964   Input Parameters:
965 + dm - DMNetwork object
966 - p  - vertex point
967 
968   Output Parameters:
969 . index - the global numbering for the vertex
970 
971   Level: intermediate
972 
973 .seealso: DMNetworkGetGlobalEdgeIndex()
974 @*/
975 PetscErrorCode DMNetworkGetGlobalVertexIndex(DM dm,PetscInt p,PetscInt *index)
976 {
977   PetscErrorCode ierr;
978 
979   PetscFunctionBegin;
980   ierr = DMNetworkGetIndex(dm,p,index);CHKERRQ(ierr);
981   PetscFunctionReturn(0);
982 }
983 
984 /*@
985   DMNetworkGetNumComponents - Get the number of components at a vertex/edge
986 
987   Not Collective
988 
989   Input Parameters:
990 + dm - the DMNetwork object
991 - p - vertex/edge point
992 
993   Output Parameters:
994 . numcomponents - Number of components at the vertex/edge
995 
996   Level: beginner
997 
998 .seealso: DMNetworkRegisterComponent(), DMNetworkAddComponent()
999 @*/
1000 PetscErrorCode DMNetworkGetNumComponents(DM dm,PetscInt p,PetscInt *numcomponents)
1001 {
1002   PetscErrorCode ierr;
1003   PetscInt       offset;
1004   DM_Network     *network = (DM_Network*)dm->data;
1005 
1006   PetscFunctionBegin;
1007   ierr = PetscSectionGetOffset(network->DataSection,p,&offset);CHKERRQ(ierr);
1008   *numcomponents = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
1009   PetscFunctionReturn(0);
1010 }
1011 
1012 /*@
1013   DMNetworkGetLocalVecOffset - Get the offset for accessing the variables associated with a component at the given vertex/edge from the local vector
1014 
1015   Not Collective
1016 
1017   Input Parameters:
1018 + dm - the DMNetwork object
1019 . p - the edge/vertex point
1020 - compnum - component number; use ALL_COMPONENTS if no specific component is requested
1021 
1022   Output Parameters:
1023 . offset - the local offset
1024 
1025   Level: intermediate
1026 
1027 .seealso: DMGetLocalVector(), DMNetworkGetComponent(), DMNetworkGetGlobalVecOffset()
1028 @*/
1029 PetscErrorCode DMNetworkGetLocalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offset)
1030 {
1031   PetscErrorCode ierr;
1032   DM_Network     *network = (DM_Network*)dm->data;
1033   PetscInt       offsetp,offsetd;
1034   DMNetworkComponentHeader header;
1035 
1036   PetscFunctionBegin;
1037   ierr = PetscSectionGetOffset(network->plex->localSection,p,&offsetp);CHKERRQ(ierr);
1038   if (compnum == ALL_COMPONENTS) {
1039     *offset = offsetp;
1040     PetscFunctionReturn(0);
1041   }
1042 
1043   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetd);CHKERRQ(ierr);
1044   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1045   *offset = offsetp + header->offsetvarrel[compnum];
1046   PetscFunctionReturn(0);
1047 }
1048 
1049 /*@
1050   DMNetworkGetGlobalVecOffset - Get the global offset for accessing the variables associated with a component for the given vertex/edge from the global vector
1051 
1052   Not Collective
1053 
1054   Input Parameters:
1055 + dm - the DMNetwork object
1056 . p - the edge/vertex point
1057 - compnum - component number; use ALL_COMPONENTS if no specific component is requested
1058 
1059   Output Parameters:
1060 . offsetg - the global offset
1061 
1062   Level: intermediate
1063 
1064 .seealso: DMNetworkGetLocalVecOffset(), DMGetGlobalVector(), DMNetworkGetComponent()
1065 @*/
1066 PetscErrorCode DMNetworkGetGlobalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offsetg)
1067 {
1068   PetscErrorCode ierr;
1069   DM_Network     *network = (DM_Network*)dm->data;
1070   PetscInt       offsetp,offsetd;
1071   DMNetworkComponentHeader header;
1072 
1073   PetscFunctionBegin;
1074   ierr = PetscSectionGetOffset(network->plex->globalSection,p,&offsetp);CHKERRQ(ierr);
1075   if (offsetp < 0) offsetp = -(offsetp + 1); /* Convert to actual global offset for ghost vertex */
1076 
1077   if (compnum == ALL_COMPONENTS) {
1078     *offsetg = offsetp;
1079     PetscFunctionReturn(0);
1080   }
1081   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetd);CHKERRQ(ierr);
1082   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1083   *offsetg = offsetp + header->offsetvarrel[compnum];
1084   PetscFunctionReturn(0);
1085 }
1086 
1087 /*@
1088   DMNetworkGetEdgeOffset - Get the offset for accessing the variables associated with the given edge from the local subvector
1089 
1090   Not Collective
1091 
1092   Input Parameters:
1093 + dm - the DMNetwork object
1094 - p - the edge point
1095 
1096   Output Parameters:
1097 . offset - the offset
1098 
1099   Level: intermediate
1100 
1101 .seealso: DMNetworkGetLocalVecOffset(), DMGetLocalVector()
1102 @*/
1103 PetscErrorCode DMNetworkGetEdgeOffset(DM dm,PetscInt p,PetscInt *offset)
1104 {
1105   PetscErrorCode ierr;
1106   DM_Network     *network = (DM_Network*)dm->data;
1107 
1108   PetscFunctionBegin;
1109   ierr = PetscSectionGetOffset(network->edge.DofSection,p,offset);CHKERRQ(ierr);
1110   PetscFunctionReturn(0);
1111 }
1112 
1113 /*@
1114   DMNetworkGetVertexOffset - Get the offset for accessing the variables associated with the given vertex from the local subvector
1115 
1116   Not Collective
1117 
1118   Input Parameters:
1119 + dm - the DMNetwork object
1120 - p - the vertex point
1121 
1122   Output Parameters:
1123 . offset - the offset
1124 
1125   Level: intermediate
1126 
1127 .seealso: DMNetworkGetEdgeOffset(), DMGetLocalVector()
1128 @*/
1129 PetscErrorCode DMNetworkGetVertexOffset(DM dm,PetscInt p,PetscInt *offset)
1130 {
1131   PetscErrorCode ierr;
1132   DM_Network     *network = (DM_Network*)dm->data;
1133 
1134   PetscFunctionBegin;
1135   p -= network->vStart;
1136   ierr = PetscSectionGetOffset(network->vertex.DofSection,p,offset);CHKERRQ(ierr);
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 /*@
1141   DMNetworkAddComponent - Adds a network component and number of variables at the given point (vertex/edge)
1142 
1143   Not Collective
1144 
1145   Input Parameters:
1146 + dm - the DMNetworkObject
1147 . p - the vertex/edge point
1148 . componentkey - component key returned while registering the component; ignored if compvalue=NULL
1149 . compvalue - pointer to the data structure for the component, or NULL if not required.
1150 - nvar - number of variables for the component at the vertex/edge point
1151 
1152   Level: beginner
1153 
1154 .seealso: DMNetworkGetComponent()
1155 @*/
1156 PetscErrorCode DMNetworkAddComponent(DM dm,PetscInt p,PetscInt componentkey,void* compvalue,PetscInt nvar)
1157 {
1158   PetscErrorCode           ierr;
1159   DM_Network               *network = (DM_Network*)dm->data;
1160   DMNetworkComponent       *component = &network->component[componentkey];
1161   DMNetworkComponentHeader header = &network->header[p];
1162   DMNetworkComponentValue  cvalue = &network->cvalue[p];
1163   PetscBool                sharedv=PETSC_FALSE;
1164   PetscInt                 compnum=header->ndata;
1165 
1166   PetscFunctionBegin;
1167   ierr = PetscSectionAddDof(network->DofSection,p,nvar);CHKERRQ(ierr);
1168   if (!compvalue) PetscFunctionReturn(0);
1169 
1170   ierr = DMNetworkIsSharedVertex(dm,p,&sharedv);CHKERRQ(ierr);
1171   if (sharedv) {
1172     PetscBool ghost;
1173     ierr = DMNetworkIsGhostVertex(dm,p,&ghost);CHKERRQ(ierr);
1174     if (ghost) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Adding a component at a leaf(ghost) shared vertex is not supported");
1175   }
1176 
1177   if (compnum == MAX_DATA_AT_POINT) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Number of components at a point exceeds the max %D",MAX_DATA_AT_POINT);
1178 
1179   header->size[compnum] = component->size;
1180   ierr = PetscSectionAddDof(network->DataSection,p,component->size);CHKERRQ(ierr);
1181   header->key[compnum] = componentkey;
1182   if (compnum != 0) header->offset[compnum] = header->offset[compnum-1] + header->size[compnum-1];
1183   cvalue->data[compnum] = (void*)compvalue;
1184 
1185   /* variables */
1186   header->nvar[compnum] += nvar;
1187   if (compnum != 0) header->offsetvarrel[compnum] = header->offsetvarrel[compnum-1] + header->nvar[compnum-1];
1188 
1189   header->ndata++;
1190   PetscFunctionReturn(0);
1191 }
1192 
1193 /*@
1194   DMNetworkGetComponent - Gets the component key, the component data, and the number of variables at a given network point
1195 
1196   Not Collective
1197 
1198   Input Parameters:
1199 + dm - the DMNetwork object
1200 . p - vertex/edge point
1201 . compnum - component number; use ALL_COMPONENTS if sum up all the components
1202 
1203   Output Parameters:
1204 + compkey - the key obtained when registering the component (use NULL if not required)
1205 . component - the component data (use NULL if not required)
1206 - nvar  - number of variables (use NULL if not required)
1207 
1208   Level: beginner
1209 
1210 .seealso: DMNetworkAddComponent(), DMNetworkGetNumComponents()
1211 @*/
1212 PetscErrorCode DMNetworkGetComponent(DM dm,PetscInt p,PetscInt compnum,PetscInt *compkey,void **component,PetscInt *nvar)
1213 {
1214   PetscErrorCode ierr;
1215   DM_Network     *network = (DM_Network*)dm->data;
1216   PetscInt       offset = 0;
1217   DMNetworkComponentHeader header;
1218 
1219   PetscFunctionBegin;
1220   if (compnum == ALL_COMPONENTS) {
1221     ierr = PetscSectionGetDof(network->DofSection,p,nvar);CHKERRQ(ierr);
1222     PetscFunctionReturn(0);
1223   }
1224 
1225   ierr = PetscSectionGetOffset(network->DataSection,p,&offset);CHKERRQ(ierr);
1226   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);CHKERRQ(ierr);
1227 
1228   if (compnum >= 0) {
1229     if (compkey) *compkey = header->key[compnum];
1230     if (component) {
1231       offset += network->dataheadersize+header->offset[compnum];
1232       *component = network->componentdataarray+offset;
1233     }
1234   }
1235 
1236   if (nvar) *nvar = header->nvar[compnum];
1237   PetscFunctionReturn(0);
1238 }
1239 
1240 /*
1241  Sets up the array that holds the data for all components and its associated section.
1242  It copies the data for all components in a contiguous array called componentdataarray. The component data is stored pointwise with an additional header (metadata) stored for each point. The header has metadata information such as number of components at each point, number of variables for each component, offsets for the components data, etc.
1243 */
1244 PetscErrorCode DMNetworkComponentSetUp(DM dm)
1245 {
1246   PetscErrorCode           ierr;
1247   DM_Network               *network = (DM_Network*)dm->data;
1248   PetscInt                 arr_size,p,offset,offsetp,ncomp,i;
1249   MPI_Comm                 comm;
1250   PetscMPIInt              size,rank;
1251   DMNetworkComponentHeader header;
1252   DMNetworkComponentValue  cvalue;
1253   DMNetworkComponentGenericDataType *componentdataarray;
1254 
1255   PetscFunctionBegin;
1256   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1257   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
1258   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1259 #if 0
1260   //------------- new
1261   if (size > 1) { /* Sync nvar at shared vertices for all processes */
1262     PetscSF        sf = network->plex->sf;
1263     const PetscInt *degree;
1264     PetscInt       i,nleaves_total,*indata,*outdata,nroots,nleaves,nsv,p,ncomp;
1265     const PetscInt *svtx;
1266     PetscBool      ghost;
1267 
1268     ierr = PetscSFGetGraph(sf,&nroots,&nleaves,NULL,NULL);CHKERRQ(ierr);
1269     ierr = PetscSFComputeDegreeBegin(sf,&degree);CHKERRQ(ierr);
1270     ierr = PetscSFComputeDegreeEnd(sf,&degree);CHKERRQ(ierr);
1271     nleaves_total=0;
1272     for (i=0; i<nroots; i++) nleaves_total += degree[i];
1273     printf("[%d] nleaves_total %d\n",rank,nleaves_total);
1274     MPI_Barrier(comm);
1275 
1276     ierr = PetscCalloc2(nleaves_total,&indata,nleaves,&outdata);CHKERRQ(ierr);
1277 
1278     /* Leaves copy user's ncomp to outdata */
1279     ierr = DMNetworkGetSharedVertices(dm,&nsv,&svtx);CHKERRQ(ierr);
1280     for (i=0; i<nsv; i++) {
1281       p = svtx[i];
1282       ierr = DMNetworkIsGhostVertex(dm,p,&ghost);CHKERRQ(ierr);
1283       if (!ghost) continue;
1284 
1285       header = &network->header[p];
1286       ncomp = header->ndata;
1287       printf("[%d] leaf has ncomp %d\n",rank,ncomp);
1288       outdata[p] = ncomp;
1289     }
1290 
1291     /* Roots gather ncomp from leaves */
1292     ierr = PetscSFGatherBegin(sf,MPIU_INT,outdata,indata);CHKERRQ(ierr);
1293     ierr = PetscSFGatherEnd(sf,MPIU_INT,outdata,indata);CHKERRQ(ierr);
1294     ierr = PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD,"## Gathered data at multi-roots from leaves\n");CHKERRQ(ierr);
1295     ierr = PetscIntView(nleaves_total,indata,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1296 
1297     ierr = PetscFree2(indata,outdata);CHKERRQ(ierr);
1298   }
1299   //----------------------
1300 #endif
1301 
1302   ierr = PetscSectionSetUp(network->DataSection);CHKERRQ(ierr);
1303   ierr = PetscSectionGetStorageSize(network->DataSection,&arr_size);CHKERRQ(ierr);
1304   ierr = PetscMalloc1(arr_size,&network->componentdataarray);CHKERRQ(ierr);
1305   componentdataarray = network->componentdataarray;
1306   for (p = network->pStart; p < network->pEnd; p++) {
1307     ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
1308     /* Copy header */
1309     header = &network->header[p];
1310     ierr = PetscMemcpy(componentdataarray+offsetp,header,network->dataheadersize*sizeof(DMNetworkComponentGenericDataType));CHKERRQ(ierr);
1311     /* Copy data */
1312     cvalue = &network->cvalue[p];
1313     ncomp = header->ndata;
1314 
1315     for (i = 0; i < ncomp; i++) {
1316       offset = offsetp + network->dataheadersize + header->offset[i];
1317       ierr = PetscMemcpy(componentdataarray+offset,cvalue->data[i],header->size[i]*sizeof(DMNetworkComponentGenericDataType));CHKERRQ(ierr);
1318     }
1319   }
1320   PetscFunctionReturn(0);
1321 }
1322 
1323 /* Sets up the section for dofs. This routine is called during DMSetUp() */
1324 static PetscErrorCode DMNetworkVariablesSetUp(DM dm)
1325 {
1326   PetscErrorCode ierr;
1327   DM_Network     *network = (DM_Network*)dm->data;
1328   MPI_Comm       comm;
1329   PetscMPIInt    size;
1330 
1331   PetscFunctionBegin;
1332   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1333   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
1334 
1335   if (size > 1) { /* Sync nvar at shared vertices for all processes */
1336     PetscSF           sf = network->plex->sf;
1337     PetscInt          *local_nvar, *remote_nvar,nroots,nleaves,p=-1,i,nsv;
1338     const PetscInt    *svtx;
1339     PetscBool         ghost;
1340     /*
1341      PetscMPIInt       rank;
1342      const PetscInt    *ilocal;
1343      const PetscSFNode *iremote;
1344      ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1345      ierr = PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
1346     */
1347     ierr = PetscSFGetGraph(sf,&nroots,&nleaves,NULL,NULL);CHKERRQ(ierr);
1348     ierr = PetscCalloc2(nroots,&local_nvar,nroots,&remote_nvar);CHKERRQ(ierr);
1349 
1350     /* Leaves copy user's nvar to local_nvar */
1351     ierr = DMNetworkGetSharedVertices(dm,&nsv,&svtx);CHKERRQ(ierr);
1352     for (i=0; i<nsv; i++) {
1353       p = svtx[i];
1354       ierr = DMNetworkIsGhostVertex(dm,p,&ghost);CHKERRQ(ierr);
1355       if (!ghost) continue;
1356       ierr = PetscSectionGetDof(network->DofSection,p,&local_nvar[p]);CHKERRQ(ierr);
1357       /* printf("[%d] Before SFReduce: leaf local_nvar[%d] = %d\n",rank,p,local_nvar[p]); */
1358     }
1359 
1360     /* Leaves add local_nvar to root remote_nvar */
1361     ierr = PetscSFReduceBegin(sf, MPIU_INT, local_nvar, remote_nvar, MPI_SUM);CHKERRQ(ierr);
1362     ierr = PetscSFReduceEnd(sf, MPIU_INT, local_nvar, remote_nvar, MPI_SUM);CHKERRQ(ierr);
1363     /* printf("[%d] remote_nvar[%d] = %d\n",rank,p,remote_nvar[p]); */
1364 
1365     /* Update roots' local_nvar */
1366     for (i=0; i<nsv; i++) {
1367       p = svtx[i];
1368       ierr = DMNetworkIsGhostVertex(dm,p,&ghost);CHKERRQ(ierr);
1369       if (ghost) continue;
1370 
1371       ierr = PetscSectionAddDof(network->DofSection,p,remote_nvar[p]);CHKERRQ(ierr);
1372       ierr = PetscSectionGetDof(network->DofSection,p,&local_nvar[p]);CHKERRQ(ierr);
1373       /* printf("[%d]  After SFReduce: root local_nvar[%d] = %d\n",rank,p,local_nvar[p]); */
1374     }
1375 
1376     /* Roots Bcast nvar to leaves */
1377     ierr = PetscSFBcastBegin(sf, MPIU_INT, local_nvar, remote_nvar);CHKERRQ(ierr);
1378     ierr = PetscSFBcastEnd(sf, MPIU_INT, local_nvar, remote_nvar);CHKERRQ(ierr);
1379 
1380     /* Leaves reset receved/remote nvar to dm */
1381     for (i=0; i<nsv; i++) {
1382       ierr = DMNetworkIsGhostVertex(dm,p,&ghost);CHKERRQ(ierr);
1383       if (!ghost) continue;
1384       p = svtx[i];
1385       /* printf("[%d] leaf reset nvar %d at p= %d \n",rank,remote_nvar[p],p); */
1386       /* DMNetworkSetNumVariables(dm,p,remote_nvar[p]) */
1387       ierr = PetscSectionSetDof(network->DofSection,p,remote_nvar[p]);CHKERRQ(ierr);
1388     }
1389 
1390     ierr = PetscFree2(local_nvar,remote_nvar);CHKERRQ(ierr);
1391   }
1392 
1393   ierr = PetscSectionSetUp(network->DofSection);CHKERRQ(ierr);
1394   PetscFunctionReturn(0);
1395 }
1396 
1397 /* Get a subsection from a range of points */
1398 static PetscErrorCode DMNetworkGetSubSection_private(PetscSection master,PetscInt pstart,PetscInt pend,PetscSection *subsection)
1399 {
1400   PetscErrorCode ierr;
1401   PetscInt       i, nvar;
1402 
1403   PetscFunctionBegin;
1404   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)master), subsection);CHKERRQ(ierr);
1405   ierr = PetscSectionSetChart(*subsection, 0, pend - pstart);CHKERRQ(ierr);
1406   for (i = pstart; i < pend; i++) {
1407     ierr = PetscSectionGetDof(master,i,&nvar);CHKERRQ(ierr);
1408     ierr = PetscSectionSetDof(*subsection, i - pstart, nvar);CHKERRQ(ierr);
1409   }
1410 
1411   ierr = PetscSectionSetUp(*subsection);CHKERRQ(ierr);
1412   PetscFunctionReturn(0);
1413 }
1414 
1415 /* Create a submap of points with a GlobalToLocal structure */
1416 static PetscErrorCode DMNetworkSetSubMap_private(PetscInt pstart, PetscInt pend, ISLocalToGlobalMapping *map)
1417 {
1418   PetscErrorCode ierr;
1419   PetscInt       i, *subpoints;
1420 
1421   PetscFunctionBegin;
1422   /* Create index sets to map from "points" to "subpoints" */
1423   ierr = PetscMalloc1(pend - pstart, &subpoints);CHKERRQ(ierr);
1424   for (i = pstart; i < pend; i++) {
1425     subpoints[i - pstart] = i;
1426   }
1427   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,pend-pstart,subpoints,PETSC_COPY_VALUES,map);CHKERRQ(ierr);
1428   ierr = PetscFree(subpoints);CHKERRQ(ierr);
1429   PetscFunctionReturn(0);
1430 }
1431 
1432 /*@
1433   DMNetworkAssembleGraphStructures - Assembles vertex and edge data structures. Must be called after DMNetworkDistribute
1434 
1435   Collective on dm
1436 
1437   Input Parameters:
1438 . dm - the DMNetworkObject
1439 
1440   Note: the routine will create alternative orderings for the vertices and edges. Assume global network points are:
1441 
1442   points = [0 1 2 3 4 5 6]
1443 
1444   where edges = [0,1,2,3] and vertices = [4,5,6]. The new orderings will be specific to the subset (i.e vertices = [0,1,2] <- [4,5,6]).
1445 
1446   With this new ordering a local PetscSection, global PetscSection and PetscSF will be created specific to the subset.
1447 
1448   Level: intermediate
1449 
1450 @*/
1451 PetscErrorCode DMNetworkAssembleGraphStructures(DM dm)
1452 {
1453   PetscErrorCode ierr;
1454   MPI_Comm       comm;
1455   PetscMPIInt    rank, size;
1456   DM_Network     *network = (DM_Network*)dm->data;
1457 
1458   PetscFunctionBegin;
1459   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1460   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1461   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1462 
1463   /* Create maps for vertices and edges */
1464   ierr = DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);CHKERRQ(ierr);
1465   ierr = DMNetworkSetSubMap_private(network->eStart,network->eEnd,&network->edge.mapping);CHKERRQ(ierr);
1466 
1467   /* Create local sub-sections */
1468   ierr = DMNetworkGetSubSection_private(network->DofSection,network->vStart,network->vEnd,&network->vertex.DofSection);CHKERRQ(ierr);
1469   ierr = DMNetworkGetSubSection_private(network->DofSection,network->eStart,network->eEnd,&network->edge.DofSection);CHKERRQ(ierr);
1470 
1471   if (size > 1) {
1472     ierr = PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);CHKERRQ(ierr);
1473 
1474     ierr = PetscSectionCreateGlobalSection(network->vertex.DofSection, network->vertex.sf, PETSC_FALSE, PETSC_FALSE, &network->vertex.GlobalDofSection);CHKERRQ(ierr);
1475     ierr = PetscSFGetSubSF(network->plex->sf, network->edge.mapping, &network->edge.sf);CHKERRQ(ierr);
1476     ierr = PetscSectionCreateGlobalSection(network->edge.DofSection, network->edge.sf, PETSC_FALSE, PETSC_FALSE, &network->edge.GlobalDofSection);CHKERRQ(ierr);
1477   } else {
1478     /* create structures for vertex */
1479     ierr = PetscSectionClone(network->vertex.DofSection,&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1480     /* create structures for edge */
1481     ierr = PetscSectionClone(network->edge.DofSection,&network->edge.GlobalDofSection);CHKERRQ(ierr);
1482   }
1483 
1484   /* Add viewers */
1485   ierr = PetscObjectSetName((PetscObject)network->edge.GlobalDofSection,"Global edge dof section");CHKERRQ(ierr);
1486   ierr = PetscObjectSetName((PetscObject)network->vertex.GlobalDofSection,"Global vertex dof section");CHKERRQ(ierr);
1487   ierr = PetscSectionViewFromOptions(network->edge.GlobalDofSection, NULL, "-edge_global_section_view");CHKERRQ(ierr);
1488   ierr = PetscSectionViewFromOptions(network->vertex.GlobalDofSection, NULL, "-vertex_global_section_view");CHKERRQ(ierr);
1489   PetscFunctionReturn(0);
1490 }
1491 
1492 /*@
1493   DMNetworkDistribute - Distributes the network and moves associated component data
1494 
1495   Collective
1496 
1497   Input Parameter:
1498 + DM - the DMNetwork object
1499 - overlap - the overlap of partitions, 0 is the default
1500 
1501   Notes:
1502   Distributes the network with <overlap>-overlapping partitioning of the edges.
1503 
1504   Level: intermediate
1505 
1506 .seealso: DMNetworkCreate()
1507 @*/
1508 PetscErrorCode DMNetworkDistribute(DM *dm,PetscInt overlap)
1509 {
1510   MPI_Comm       comm;
1511   PetscErrorCode ierr;
1512   PetscMPIInt    size;
1513   DM_Network     *oldDMnetwork = (DM_Network*)((*dm)->data);
1514   DM_Network     *newDMnetwork;
1515   PetscSF        pointsf=NULL;
1516   DM             newDM;
1517   PetscInt       j,e,v,offset,*subnetvtx,nsubnet,gidx,svtx_idx,nv;
1518   PetscInt       to_net,from_net,*svto;
1519   PetscPartitioner         part;
1520   DMNetworkComponentHeader header;
1521 
1522   PetscFunctionBegin;
1523   ierr = PetscObjectGetComm((PetscObject)*dm,&comm);CHKERRQ(ierr);
1524   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1525   if (size == 1) PetscFunctionReturn(0);
1526 
1527   /* This routine moves the component data to the appropriate processors. It makes use of the DataSection and the componentdataarray to move the component data to appropriate processors and returns a new DataSection and new componentdataarray. */
1528   ierr = DMNetworkCreate(PetscObjectComm((PetscObject)*dm),&newDM);CHKERRQ(ierr);
1529   newDMnetwork = (DM_Network*)newDM->data;
1530   newDMnetwork->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
1531 
1532   /* Enable runtime options for petscpartitioner */
1533   ierr = DMPlexGetPartitioner(oldDMnetwork->plex,&part);CHKERRQ(ierr);
1534   ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr);
1535 
1536   /* Distribute plex dm */
1537   ierr = DMPlexDistribute(oldDMnetwork->plex,overlap,&pointsf,&newDMnetwork->plex);CHKERRQ(ierr);
1538 
1539   /* Distribute dof section */
1540   ierr = PetscSectionCreate(comm,&newDMnetwork->DofSection);CHKERRQ(ierr);
1541   ierr = PetscSFDistributeSection(pointsf,oldDMnetwork->DofSection,NULL,newDMnetwork->DofSection);CHKERRQ(ierr);
1542 
1543   /* Distribute data and associated section */
1544   ierr = PetscSectionCreate(comm,&newDMnetwork->DataSection);CHKERRQ(ierr);
1545   ierr = DMPlexDistributeData(newDMnetwork->plex,pointsf,oldDMnetwork->DataSection,MPIU_INT,(void*)oldDMnetwork->componentdataarray,newDMnetwork->DataSection,(void**)&newDMnetwork->componentdataarray);CHKERRQ(ierr);
1546 
1547   ierr = PetscSectionGetChart(newDMnetwork->DataSection,&newDMnetwork->pStart,&newDMnetwork->pEnd);CHKERRQ(ierr);
1548   ierr = DMPlexGetHeightStratum(newDMnetwork->plex,0, &newDMnetwork->eStart,&newDMnetwork->eEnd);CHKERRQ(ierr);
1549   ierr = DMPlexGetHeightStratum(newDMnetwork->plex,1,&newDMnetwork->vStart,&newDMnetwork->vEnd);CHKERRQ(ierr);
1550   newDMnetwork->nEdges    = newDMnetwork->eEnd - newDMnetwork->eStart;
1551   newDMnetwork->nVertices = newDMnetwork->vEnd - newDMnetwork->vStart;
1552   newDMnetwork->NVertices = oldDMnetwork->NVertices;
1553   newDMnetwork->NEdges    = oldDMnetwork->NEdges;
1554   newDMnetwork->svtable   = oldDMnetwork->svtable;
1555   oldDMnetwork->svtable   = NULL;
1556 
1557   /* Set Dof section as the section for dm */
1558   ierr = DMSetLocalSection(newDMnetwork->plex,newDMnetwork->DofSection);CHKERRQ(ierr);
1559   ierr = DMGetGlobalSection(newDMnetwork->plex,&newDMnetwork->GlobalDofSection);CHKERRQ(ierr);
1560 
1561   /* Set up subnetwork info in the newDM */
1562   newDMnetwork->Nsubnet = oldDMnetwork->Nsubnet;
1563   newDMnetwork->Nsvtx   = oldDMnetwork->Nsvtx;
1564   oldDMnetwork->Nsvtx   = 0;
1565   newDMnetwork->svtx    = oldDMnetwork->svtx; /* global vertices! */
1566   oldDMnetwork->svtx    = NULL;
1567   ierr = PetscCalloc1(newDMnetwork->Nsubnet,&newDMnetwork->subnet);CHKERRQ(ierr);
1568 
1569   /* Copy over the global number of vertices and edges in each subnetwork.
1570      Note: these are calculated in DMNetworkLayoutSetUp()
1571   */
1572   nsubnet = newDMnetwork->Nsubnet;
1573   for (j = 0; j < nsubnet; j++) {
1574     newDMnetwork->subnet[j].Nvtx  = oldDMnetwork->subnet[j].Nvtx;
1575     newDMnetwork->subnet[j].Nedge = oldDMnetwork->subnet[j].Nedge;
1576   }
1577 
1578   /* Get local nedges and nvtx for subnetworks */
1579   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1580     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);CHKERRQ(ierr);
1581     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1582     newDMnetwork->subnet[header->subnetid].nedge++;
1583   }
1584 
1585   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1586     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);CHKERRQ(ierr);
1587     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1588 
1589     /* shared vertices: use gidx = header->index to check if v is a shared vertex */
1590     gidx = header->index;
1591     ierr = PetscTableFind(newDMnetwork->svtable,gidx+1,&svtx_idx);CHKERRQ(ierr);
1592     svtx_idx--;
1593 
1594     if (svtx_idx < 0) { /* not a shared vertex */
1595       newDMnetwork->subnet[header->subnetid].nvtx++;
1596     } else { /* a shared vertex belongs to more than one subnetworks, it is being counted by multiple subnets */
1597       from_net = newDMnetwork->svtx[svtx_idx].sv[0];
1598       newDMnetwork->subnet[from_net].nvtx++;
1599       for (j=1; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1600         svto   = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1601         to_net = svto[0];
1602         newDMnetwork->subnet[to_net].nvtx++;
1603       }
1604     }
1605   }
1606 
1607   /* Get total local nvtx for subnetworks */
1608   nv = 0;
1609   for (j=0; j<nsubnet; j++) nv += newDMnetwork->subnet[j].nvtx;
1610   nv += newDMnetwork->Nsvtx;
1611 
1612   /* Now create the vertices and edge arrays for the subnetworks */
1613   ierr = PetscCalloc1(nv,&subnetvtx);CHKERRQ(ierr);
1614   newDMnetwork->subnetvtx = subnetvtx;
1615 
1616   for (j=0; j<nsubnet; j++) {
1617     ierr = PetscCalloc1(newDMnetwork->subnet[j].nedge,&newDMnetwork->subnet[j].edges);CHKERRQ(ierr);
1618     newDMnetwork->subnet[j].vertices = subnetvtx;
1619     subnetvtx                       += newDMnetwork->subnet[j].nvtx;
1620 
1621     /* Temporarily setting nvtx and nedge to 0 so we can use them as counters in the below for loop. These get updated when the vertices and edges are added. */
1622     newDMnetwork->subnet[j].nvtx = newDMnetwork->subnet[j].nedge = 0;
1623   }
1624   newDMnetwork->svertices = subnetvtx;
1625 
1626   /* Set the edges and vertices in each subnetwork */
1627   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1628     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);CHKERRQ(ierr);
1629     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1630     newDMnetwork->subnet[header->subnetid].edges[newDMnetwork->subnet[header->subnetid].nedge++] = e;
1631   }
1632 
1633   nv = 0;
1634   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1635     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);CHKERRQ(ierr);
1636     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1637 
1638     /* coupling vertices: use gidx = header->index to check if v is a coupling vertex */
1639     ierr = PetscTableFind(newDMnetwork->svtable,header->index+1,&svtx_idx);CHKERRQ(ierr);
1640     svtx_idx--;
1641     if (svtx_idx < 0) {
1642       newDMnetwork->subnet[header->subnetid].vertices[newDMnetwork->subnet[header->subnetid].nvtx++] = v;
1643     } else { /* a shared vertex */
1644       newDMnetwork->svertices[nv++] = v;
1645 
1646       from_net = newDMnetwork->svtx[svtx_idx].sv[0];
1647       newDMnetwork->subnet[from_net].vertices[newDMnetwork->subnet[from_net].nvtx++] = v;
1648 
1649       for (j=1; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1650         svto   = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1651         to_net = svto[0];
1652         newDMnetwork->subnet[to_net].vertices[newDMnetwork->subnet[to_net].nvtx++] = v;
1653       }
1654     }
1655   }
1656   newDMnetwork->nsvtx = nv;   /* num of local shared vertices */
1657 
1658   newDM->setupcalled = (*dm)->setupcalled;
1659   newDMnetwork->distributecalled = PETSC_TRUE;
1660 
1661   /* Free spaces */
1662   ierr = PetscSFDestroy(&pointsf);CHKERRQ(ierr);
1663   ierr = DMDestroy(dm);CHKERRQ(ierr);
1664 
1665   *dm  = newDM;
1666   PetscFunctionReturn(0);
1667 }
1668 
1669 /*@C
1670   PetscSFGetSubSF - Returns an SF for a specific subset of points. Leaves are re-numbered to reflect the new ordering
1671 
1672  Collective
1673 
1674   Input Parameters:
1675 + masterSF - the original SF structure
1676 - map - a ISLocalToGlobal mapping that contains the subset of points
1677 
1678   Output Parameters:
1679 . subSF - a subset of the masterSF for the desired subset.
1680 
1681   Level: intermediate
1682 @*/
1683 PetscErrorCode PetscSFGetSubSF(PetscSF mastersf,ISLocalToGlobalMapping map,PetscSF *subSF)
1684 {
1685   PetscErrorCode        ierr;
1686   PetscInt              nroots, nleaves, *ilocal_sub;
1687   PetscInt              i, *ilocal_map, nroots_sub, nleaves_sub = 0;
1688   PetscInt              *local_points, *remote_points;
1689   PetscSFNode           *iremote_sub;
1690   const PetscInt        *ilocal;
1691   const PetscSFNode     *iremote;
1692 
1693   PetscFunctionBegin;
1694   ierr = PetscSFGetGraph(mastersf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
1695 
1696   /* Look for leaves that pertain to the subset of points. Get the local ordering */
1697   ierr = PetscMalloc1(nleaves,&ilocal_map);CHKERRQ(ierr);
1698   ierr = ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nleaves,ilocal,NULL,ilocal_map);CHKERRQ(ierr);
1699   for (i = 0; i < nleaves; i++) {
1700     if (ilocal_map[i] != -1) nleaves_sub += 1;
1701   }
1702   /* Re-number ilocal with subset numbering. Need information from roots */
1703   ierr = PetscMalloc2(nroots,&local_points,nroots,&remote_points);CHKERRQ(ierr);
1704   for (i = 0; i < nroots; i++) local_points[i] = i;
1705   ierr = ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nroots,local_points,NULL,local_points);CHKERRQ(ierr);
1706   ierr = PetscSFBcastBegin(mastersf, MPIU_INT, local_points, remote_points);CHKERRQ(ierr);
1707   ierr = PetscSFBcastEnd(mastersf, MPIU_INT, local_points, remote_points);CHKERRQ(ierr);
1708   /* Fill up graph using local (that is, local to the subset) numbering. */
1709   ierr = PetscMalloc1(nleaves_sub,&ilocal_sub);CHKERRQ(ierr);
1710   ierr = PetscMalloc1(nleaves_sub,&iremote_sub);CHKERRQ(ierr);
1711   nleaves_sub = 0;
1712   for (i = 0; i < nleaves; i++) {
1713     if (ilocal_map[i] != -1) {
1714       ilocal_sub[nleaves_sub] = ilocal_map[i];
1715       iremote_sub[nleaves_sub].rank = iremote[i].rank;
1716       iremote_sub[nleaves_sub].index = remote_points[ilocal[i]];
1717       nleaves_sub += 1;
1718     }
1719   }
1720   ierr = PetscFree2(local_points,remote_points);CHKERRQ(ierr);
1721   ierr = ISLocalToGlobalMappingGetSize(map,&nroots_sub);CHKERRQ(ierr);
1722 
1723   /* Create new subSF */
1724   ierr = PetscSFCreate(PETSC_COMM_WORLD,subSF);CHKERRQ(ierr);
1725   ierr = PetscSFSetFromOptions(*subSF);CHKERRQ(ierr);
1726   ierr = PetscSFSetGraph(*subSF,nroots_sub,nleaves_sub,ilocal_sub,PETSC_OWN_POINTER,iremote_sub,PETSC_COPY_VALUES);CHKERRQ(ierr);
1727   ierr = PetscFree(ilocal_map);CHKERRQ(ierr);
1728   ierr = PetscFree(iremote_sub);CHKERRQ(ierr);
1729   PetscFunctionReturn(0);
1730 }
1731 
1732 /*@C
1733   DMNetworkGetSupportingEdges - Return the supporting edges for this vertex point
1734 
1735   Not Collective
1736 
1737   Input Parameters:
1738 + dm - the DMNetwork object
1739 - p  - the vertex point
1740 
1741   Output Parameters:
1742 + nedges - number of edges connected to this vertex point
1743 - edges  - list of edge points
1744 
1745   Level: beginner
1746 
1747   Fortran Notes:
1748   Since it returns an array, this routine is only available in Fortran 90, and you must
1749   include petsc.h90 in your code.
1750 
1751 .seealso: DMNetworkCreate(), DMNetworkGetConnectedVertices()
1752 @*/
1753 PetscErrorCode DMNetworkGetSupportingEdges(DM dm,PetscInt vertex,PetscInt *nedges,const PetscInt *edges[])
1754 {
1755   PetscErrorCode ierr;
1756   DM_Network     *network = (DM_Network*)dm->data;
1757 
1758   PetscFunctionBegin;
1759   ierr = DMPlexGetSupportSize(network->plex,vertex,nedges);CHKERRQ(ierr);
1760   ierr = DMPlexGetSupport(network->plex,vertex,edges);CHKERRQ(ierr);
1761   PetscFunctionReturn(0);
1762 }
1763 
1764 /*@C
1765   DMNetworkGetConnectedVertices - Return the connected vertices for this edge point
1766 
1767   Not Collective
1768 
1769   Input Parameters:
1770 + dm - the DMNetwork object
1771 - p - the edge point
1772 
1773   Output Parameters:
1774 . vertices - vertices connected to this edge
1775 
1776   Level: beginner
1777 
1778   Fortran Notes:
1779   Since it returns an array, this routine is only available in Fortran 90, and you must
1780   include petsc.h90 in your code.
1781 
1782 .seealso: DMNetworkCreate(), DMNetworkGetSupportingEdges()
1783 @*/
1784 PetscErrorCode DMNetworkGetConnectedVertices(DM dm,PetscInt edge,const PetscInt *vertices[])
1785 {
1786   PetscErrorCode ierr;
1787   DM_Network     *network = (DM_Network*)dm->data;
1788 
1789   PetscFunctionBegin;
1790   ierr = DMPlexGetCone(network->plex,edge,vertices);CHKERRQ(ierr);
1791   PetscFunctionReturn(0);
1792 }
1793 
1794 /*@
1795   DMNetworkIsSharedVertex - Returns TRUE if the vertex is shared by subnetworks
1796 
1797   Not Collective
1798 
1799   Input Parameters:
1800 + dm - the DMNetwork object
1801 - p - the vertex point
1802 
1803   Output Parameter:
1804 . flag - TRUE if the vertex is shared by subnetworks
1805 
1806   Level: beginner
1807 
1808 .seealso: DMNetworkAddSharedVertices(), DMNetworkIsGhostVertex()
1809 @*/
1810 PetscErrorCode DMNetworkIsSharedVertex(DM dm,PetscInt p,PetscBool *flag)
1811 {
1812   PetscErrorCode ierr;
1813   PetscInt       i;
1814 
1815   PetscFunctionBegin;
1816   *flag = PETSC_FALSE;
1817 
1818   if (dm->setupcalled) { /* DMNetworkGetGlobalVertexIndex() requires DMSetUp() be called */
1819     DM_Network     *network = (DM_Network*)dm->data;
1820     PetscInt       gidx;
1821     ierr = DMNetworkGetGlobalVertexIndex(dm,p,&gidx);CHKERRQ(ierr);
1822     ierr = PetscTableFind(network->svtable,gidx+1,&i);CHKERRQ(ierr);
1823     if (i) *flag = PETSC_TRUE;
1824   } else { /* would be removed? */
1825     PetscInt       nv;
1826     const PetscInt *vtx;
1827     ierr = DMNetworkGetSharedVertices(dm,&nv,&vtx);CHKERRQ(ierr);
1828     for (i=0; i<nv; i++) {
1829       if (p == vtx[i]) {
1830         *flag = PETSC_TRUE;
1831         break;
1832       }
1833     }
1834   }
1835   PetscFunctionReturn(0);
1836 }
1837 
1838 /*@
1839   DMNetworkIsGhostVertex - Returns TRUE if the vertex is a ghost vertex
1840 
1841   Not Collective
1842 
1843   Input Parameters:
1844 + dm - the DMNetwork object
1845 - p - the vertex point
1846 
1847   Output Parameter:
1848 . isghost - TRUE if the vertex is a ghost point
1849 
1850   Level: beginner
1851 
1852 .seealso: DMNetworkGetConnectedVertices(), DMNetworkGetVertexRange(), DMNetworkIsSharedVertex()
1853 @*/
1854 PetscErrorCode DMNetworkIsGhostVertex(DM dm,PetscInt p,PetscBool *isghost)
1855 {
1856   PetscErrorCode ierr;
1857   DM_Network     *network = (DM_Network*)dm->data;
1858   PetscInt       offsetg;
1859   PetscSection   sectiong;
1860 
1861   PetscFunctionBegin;
1862   *isghost = PETSC_FALSE;
1863   ierr = DMGetGlobalSection(network->plex,&sectiong);CHKERRQ(ierr);
1864   ierr = PetscSectionGetOffset(sectiong,p,&offsetg);CHKERRQ(ierr);
1865   if (offsetg < 0) *isghost = PETSC_TRUE;
1866   PetscFunctionReturn(0);
1867 }
1868 
1869 PetscErrorCode DMSetUp_Network(DM dm)
1870 {
1871   PetscErrorCode ierr;
1872   DM_Network     *network=(DM_Network*)dm->data;
1873 
1874   PetscFunctionBegin;
1875   ierr = DMNetworkComponentSetUp(dm);CHKERRQ(ierr);
1876   ierr = DMNetworkVariablesSetUp(dm);CHKERRQ(ierr);
1877 
1878   ierr = DMSetLocalSection(network->plex,network->DofSection);CHKERRQ(ierr);
1879   ierr = DMGetGlobalSection(network->plex,&network->GlobalDofSection);CHKERRQ(ierr);
1880 
1881   dm->setupcalled = PETSC_TRUE;
1882   ierr = DMViewFromOptions(dm,NULL,"-dm_view");CHKERRQ(ierr);
1883   PetscFunctionReturn(0);
1884 }
1885 
1886 /*@
1887   DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
1888       -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?
1889 
1890   Collective
1891 
1892   Input Parameters:
1893 + dm - the DMNetwork object
1894 . eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
1895 - vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices
1896 
1897  Level: intermediate
1898 
1899 @*/
1900 PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
1901 {
1902   DM_Network     *network=(DM_Network*)dm->data;
1903   PetscErrorCode ierr;
1904   PetscInt       nVertices = network->nVertices;
1905 
1906   PetscFunctionBegin;
1907   network->userEdgeJacobian   = eflg;
1908   network->userVertexJacobian = vflg;
1909 
1910   if (eflg && !network->Je) {
1911     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1912   }
1913 
1914   if (vflg && !network->Jv && nVertices) {
1915     PetscInt       i,*vptr,nedges,vStart=network->vStart;
1916     PetscInt       nedges_total;
1917     const PetscInt *edges;
1918 
1919     /* count nvertex_total */
1920     nedges_total = 0;
1921     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1922 
1923     vptr[0] = 0;
1924     for (i=0; i<nVertices; i++) {
1925       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1926       nedges_total += nedges;
1927       vptr[i+1] = vptr[i] + 2*nedges + 1;
1928     }
1929 
1930     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1931     network->Jvptr = vptr;
1932   }
1933   PetscFunctionReturn(0);
1934 }
1935 
1936 /*@
1937   DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1938 
1939   Not Collective
1940 
1941   Input Parameters:
1942 + dm - the DMNetwork object
1943 . p - the edge point
1944 - J - array (size = 3) of Jacobian submatrices for this edge point:
1945         J[0]: this edge
1946         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1947 
1948   Level: advanced
1949 
1950 .seealso: DMNetworkVertexSetMatrix()
1951 @*/
1952 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1953 {
1954   DM_Network *network=(DM_Network*)dm->data;
1955 
1956   PetscFunctionBegin;
1957   if (!network->Je) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1958 
1959   if (J) {
1960     network->Je[3*p]   = J[0];
1961     network->Je[3*p+1] = J[1];
1962     network->Je[3*p+2] = J[2];
1963   }
1964   PetscFunctionReturn(0);
1965 }
1966 
1967 /*@
1968   DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1969 
1970   Not Collective
1971 
1972   Input Parameters:
1973 + dm - The DMNetwork object
1974 . p - the vertex point
1975 - J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1976         J[0]:       this vertex
1977         J[1+2*i]:   i-th supporting edge
1978         J[1+2*i+1]: i-th connected vertex
1979 
1980   Level: advanced
1981 
1982 .seealso: DMNetworkEdgeSetMatrix()
1983 @*/
1984 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1985 {
1986   PetscErrorCode ierr;
1987   DM_Network     *network=(DM_Network*)dm->data;
1988   PetscInt       i,*vptr,nedges,vStart=network->vStart;
1989   const PetscInt *edges;
1990 
1991   PetscFunctionBegin;
1992   if (!network->Jv) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1993 
1994   if (J) {
1995     vptr = network->Jvptr;
1996     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1997 
1998     /* Set Jacobian for each supporting edge and connected vertex */
1999     ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
2000     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
2001   }
2002   PetscFunctionReturn(0);
2003 }
2004 
2005 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2006 {
2007   PetscErrorCode ierr;
2008   PetscInt       j;
2009   PetscScalar    val=(PetscScalar)ncols;
2010 
2011   PetscFunctionBegin;
2012   if (!ghost) {
2013     for (j=0; j<nrows; j++) {
2014       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
2015     }
2016   } else {
2017     for (j=0; j<nrows; j++) {
2018       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
2019     }
2020   }
2021   PetscFunctionReturn(0);
2022 }
2023 
2024 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2025 {
2026   PetscErrorCode ierr;
2027   PetscInt       j,ncols_u;
2028   PetscScalar    val;
2029 
2030   PetscFunctionBegin;
2031   if (!ghost) {
2032     for (j=0; j<nrows; j++) {
2033       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
2034       val = (PetscScalar)ncols_u;
2035       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
2036       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
2037     }
2038   } else {
2039     for (j=0; j<nrows; j++) {
2040       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
2041       val = (PetscScalar)ncols_u;
2042       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
2043       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
2044     }
2045   }
2046   PetscFunctionReturn(0);
2047 }
2048 
2049 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2050 {
2051   PetscErrorCode ierr;
2052 
2053   PetscFunctionBegin;
2054   if (Ju) {
2055     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
2056   } else {
2057     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
2058   }
2059   PetscFunctionReturn(0);
2060 }
2061 
2062 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2063 {
2064   PetscErrorCode ierr;
2065   PetscInt       j,*cols;
2066   PetscScalar    *zeros;
2067 
2068   PetscFunctionBegin;
2069   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
2070   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
2071   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
2072   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2077 {
2078   PetscErrorCode ierr;
2079   PetscInt       j,M,N,row,col,ncols_u;
2080   const PetscInt *cols;
2081   PetscScalar    zero=0.0;
2082 
2083   PetscFunctionBegin;
2084   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
2085   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
2086 
2087   for (row=0; row<nrows; row++) {
2088     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
2089     for (j=0; j<ncols_u; j++) {
2090       col = cols[j] + cstart;
2091       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
2092     }
2093     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
2094   }
2095   PetscFunctionReturn(0);
2096 }
2097 
2098 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2099 {
2100   PetscErrorCode ierr;
2101 
2102   PetscFunctionBegin;
2103   if (Ju) {
2104     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
2105   } else {
2106     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
2107   }
2108   PetscFunctionReturn(0);
2109 }
2110 
2111 /* Creates a GlobalToLocal mapping with a Local and Global section. This is akin to the routine DMGetLocalToGlobalMapping but without the need of providing a dm.
2112 */
2113 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
2114 {
2115   PetscErrorCode ierr;
2116   PetscInt       i,size,dof;
2117   PetscInt       *glob2loc;
2118 
2119   PetscFunctionBegin;
2120   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
2121   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
2122 
2123   for (i = 0; i < size; i++) {
2124     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
2125     dof = (dof >= 0) ? dof : -(dof + 1);
2126     glob2loc[i] = dof;
2127   }
2128 
2129   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
2130 #if 0
2131   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2132 #endif
2133   PetscFunctionReturn(0);
2134 }
2135 
2136 #include <petsc/private/matimpl.h>
2137 
2138 PetscErrorCode DMCreateMatrix_Network_Nest(DM dm,Mat *J)
2139 {
2140   PetscErrorCode ierr;
2141   DM_Network     *network = (DM_Network*)dm->data;
2142   PetscMPIInt    rank, size;
2143   PetscInt       eDof,vDof;
2144   Mat            j11,j12,j21,j22,bA[2][2];
2145   MPI_Comm       comm;
2146   ISLocalToGlobalMapping eISMap,vISMap;
2147 
2148   PetscFunctionBegin;
2149   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2150   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
2151   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
2152 
2153   ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
2154   ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
2155 
2156   ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
2157   ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2158   ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
2159 
2160   ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
2161   ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
2162   ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
2163 
2164   ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
2165   ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2166   ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
2167 
2168   ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
2169   ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2170   ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
2171 
2172   bA[0][0] = j11;
2173   bA[0][1] = j12;
2174   bA[1][0] = j21;
2175   bA[1][1] = j22;
2176 
2177   ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
2178   ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
2179 
2180   ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
2181   ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
2182   ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
2183   ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
2184 
2185   ierr = MatSetUp(j11);CHKERRQ(ierr);
2186   ierr = MatSetUp(j12);CHKERRQ(ierr);
2187   ierr = MatSetUp(j21);CHKERRQ(ierr);
2188   ierr = MatSetUp(j22);CHKERRQ(ierr);
2189 
2190   ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
2191   ierr = MatSetUp(*J);CHKERRQ(ierr);
2192   ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
2193   ierr = MatDestroy(&j11);CHKERRQ(ierr);
2194   ierr = MatDestroy(&j12);CHKERRQ(ierr);
2195   ierr = MatDestroy(&j21);CHKERRQ(ierr);
2196   ierr = MatDestroy(&j22);CHKERRQ(ierr);
2197 
2198   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2199   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2200   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
2201 
2202   /* Free structures */
2203   ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
2204   ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
2205   PetscFunctionReturn(0);
2206 }
2207 
2208 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
2209 {
2210   PetscErrorCode ierr;
2211   DM_Network     *network = (DM_Network*)dm->data;
2212   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
2213   PetscInt       cstart,ncols,j,e,v;
2214   PetscBool      ghost,ghost_vc,ghost2,isNest;
2215   Mat            Juser;
2216   PetscSection   sectionGlobal;
2217   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
2218   const PetscInt *edges,*cone;
2219   MPI_Comm       comm;
2220   MatType        mtype;
2221   Vec            vd_nz,vo_nz;
2222   PetscInt       *dnnz,*onnz;
2223   PetscScalar    *vdnz,*vonz;
2224 
2225   PetscFunctionBegin;
2226   mtype = dm->mattype;
2227   ierr = PetscStrcmp(mtype,MATNEST,&isNest);CHKERRQ(ierr);
2228   if (isNest) {
2229     ierr = DMCreateMatrix_Network_Nest(dm,J);CHKERRQ(ierr);
2230     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
2231     PetscFunctionReturn(0);
2232   }
2233 
2234   if (!network->userEdgeJacobian && !network->userVertexJacobian) {
2235     /* user does not provide Jacobian blocks */
2236     ierr = DMCreateMatrix_Plex(network->plex,J);CHKERRQ(ierr);
2237     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
2238     PetscFunctionReturn(0);
2239   }
2240 
2241   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
2242   ierr = DMGetGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
2243   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
2244   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
2245 
2246   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
2247   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
2248 
2249   /* (1) Set matrix preallocation */
2250   /*------------------------------*/
2251   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2252   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
2253   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
2254   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
2255   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
2256   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
2257 
2258   /* Set preallocation for edges */
2259   /*-----------------------------*/
2260   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
2261 
2262   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
2263   for (e=eStart; e<eEnd; e++) {
2264     /* Get row indices */
2265     ierr = DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart);CHKERRQ(ierr);
2266     ierr = PetscSectionGetDof(network->DofSection,e,&nrows);CHKERRQ(ierr);
2267     if (nrows) {
2268       for (j=0; j<nrows; j++) rows[j] = j + rstart;
2269 
2270       /* Set preallocation for conntected vertices */
2271       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
2272       for (v=0; v<2; v++) {
2273         ierr = PetscSectionGetDof(network->DofSection,cone[v],&ncols);CHKERRQ(ierr);
2274 
2275         if (network->Je) {
2276           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2277         } else Juser = NULL;
2278         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
2279         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
2280       }
2281 
2282       /* Set preallocation for edge self */
2283       cstart = rstart;
2284       if (network->Je) {
2285         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2286       } else Juser = NULL;
2287       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
2288     }
2289   }
2290 
2291   /* Set preallocation for vertices */
2292   /*--------------------------------*/
2293   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
2294   if (vEnd - vStart) vptr = network->Jvptr;
2295 
2296   for (v=vStart; v<vEnd; v++) {
2297     /* Get row indices */
2298     ierr = DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart);CHKERRQ(ierr);
2299     ierr = PetscSectionGetDof(network->DofSection,v,&nrows);CHKERRQ(ierr);
2300     if (!nrows) continue;
2301 
2302     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
2303     if (ghost) {
2304       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
2305     } else {
2306       rows_v = rows;
2307     }
2308 
2309     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
2310 
2311     /* Get supporting edges and connected vertices */
2312     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
2313 
2314     for (e=0; e<nedges; e++) {
2315       /* Supporting edges */
2316       ierr = DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2317       ierr = PetscSectionGetDof(network->DofSection,edges[e],&ncols);CHKERRQ(ierr);
2318 
2319       if (network->Jv) {
2320         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2321       } else Juser = NULL;
2322       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
2323 
2324       /* Connected vertices */
2325       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
2326       vc = (v == cone[0]) ? cone[1]:cone[0];
2327       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
2328 
2329       ierr = PetscSectionGetDof(network->DofSection,vc,&ncols);CHKERRQ(ierr);
2330 
2331       if (network->Jv) {
2332         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2333       } else Juser = NULL;
2334       if (ghost_vc||ghost) {
2335         ghost2 = PETSC_TRUE;
2336       } else {
2337         ghost2 = PETSC_FALSE;
2338       }
2339       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
2340     }
2341 
2342     /* Set preallocation for vertex self */
2343     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
2344     if (!ghost) {
2345       ierr = DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2346       if (network->Jv) {
2347         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2348       } else Juser = NULL;
2349       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
2350     }
2351     if (ghost) {
2352       ierr = PetscFree(rows_v);CHKERRQ(ierr);
2353     }
2354   }
2355 
2356   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
2357   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
2358 
2359   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
2360 
2361   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
2362   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
2363 
2364   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
2365   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
2366   for (j=0; j<localSize; j++) {
2367     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
2368     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
2369   }
2370   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
2371   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
2372   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
2373   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
2374 
2375   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
2376   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
2377   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
2378 
2379   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
2380 
2381   /* (2) Set matrix entries for edges */
2382   /*----------------------------------*/
2383   for (e=eStart; e<eEnd; e++) {
2384     /* Get row indices */
2385     ierr = DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart);CHKERRQ(ierr);
2386     ierr = PetscSectionGetDof(network->DofSection,e,&nrows);CHKERRQ(ierr);
2387     if (nrows) {
2388       for (j=0; j<nrows; j++) rows[j] = j + rstart;
2389 
2390       /* Set matrix entries for conntected vertices */
2391       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
2392       for (v=0; v<2; v++) {
2393         ierr = DMNetworkGetGlobalVecOffset(dm,cone[v],ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2394         ierr = PetscSectionGetDof(network->DofSection,cone[v],&ncols);CHKERRQ(ierr);
2395 
2396         if (network->Je) {
2397           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2398         } else Juser = NULL;
2399         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
2400       }
2401 
2402       /* Set matrix entries for edge self */
2403       cstart = rstart;
2404       if (network->Je) {
2405         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2406       } else Juser = NULL;
2407       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
2408     }
2409   }
2410 
2411   /* Set matrix entries for vertices */
2412   /*---------------------------------*/
2413   for (v=vStart; v<vEnd; v++) {
2414     /* Get row indices */
2415     ierr = DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart);CHKERRQ(ierr);
2416     ierr = PetscSectionGetDof(network->DofSection,v,&nrows);CHKERRQ(ierr);
2417     if (!nrows) continue;
2418 
2419     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
2420     if (ghost) {
2421       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
2422     } else {
2423       rows_v = rows;
2424     }
2425     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
2426 
2427     /* Get supporting edges and connected vertices */
2428     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
2429 
2430     for (e=0; e<nedges; e++) {
2431       /* Supporting edges */
2432       ierr = DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2433       ierr = PetscSectionGetDof(network->DofSection,edges[e],&ncols);CHKERRQ(ierr);
2434 
2435       if (network->Jv) {
2436         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2437       } else Juser = NULL;
2438       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
2439 
2440       /* Connected vertices */
2441       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
2442       vc = (v == cone[0]) ? cone[1]:cone[0];
2443 
2444       ierr = DMNetworkGetGlobalVecOffset(dm,vc,ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2445       ierr = PetscSectionGetDof(network->DofSection,vc,&ncols);CHKERRQ(ierr);
2446 
2447       if (network->Jv) {
2448         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2449       } else Juser = NULL;
2450       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
2451     }
2452 
2453     /* Set matrix entries for vertex self */
2454     if (!ghost) {
2455       ierr = DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart);CHKERRQ(ierr);
2456       if (network->Jv) {
2457         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2458       } else Juser = NULL;
2459       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
2460     }
2461     if (ghost) {
2462       ierr = PetscFree(rows_v);CHKERRQ(ierr);
2463     }
2464   }
2465   ierr = PetscFree(rows);CHKERRQ(ierr);
2466 
2467   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2468   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2469 
2470   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
2471   PetscFunctionReturn(0);
2472 }
2473 
2474 PetscErrorCode DMDestroy_Network(DM dm)
2475 {
2476   PetscErrorCode ierr;
2477   DM_Network     *network = (DM_Network*)dm->data;
2478   PetscInt       j;
2479 
2480   PetscFunctionBegin;
2481   if (--network->refct > 0) PetscFunctionReturn(0);
2482   if (network->Je) {
2483     ierr = PetscFree(network->Je);CHKERRQ(ierr);
2484   }
2485   if (network->Jv) {
2486     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
2487     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
2488   }
2489 
2490   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
2491   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
2492   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
2493   if (network->vltog) {
2494     ierr = PetscFree(network->vltog);CHKERRQ(ierr);
2495   }
2496   if (network->vertex.sf) {
2497     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
2498   }
2499   /* edge */
2500   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
2501   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
2502   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
2503   if (network->edge.sf) {
2504     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
2505   }
2506   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
2507   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
2508   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
2509 
2510   for (j=0; j<network->Nsvtx; j++) {
2511     ierr = PetscFree(network->svtx[j].sv);CHKERRQ(ierr);
2512   }
2513   if (network->svtx) {ierr = PetscFree(network->svtx);CHKERRQ(ierr);}
2514 
2515   for (j=0; j<network->Nsubnet; j++) {
2516     ierr = PetscFree(network->subnet[j].edges);CHKERRQ(ierr);
2517   }
2518   if (network->subnetvtx) {ierr = PetscFree(network->subnetvtx);CHKERRQ(ierr);}
2519 
2520   ierr = PetscTableDestroy(&network->svtable);CHKERRQ(ierr);
2521   ierr = PetscFree(network->subnet);CHKERRQ(ierr);
2522   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
2523   ierr = PetscFree2(network->header,network->cvalue);CHKERRQ(ierr);
2524   ierr = PetscFree(network);CHKERRQ(ierr);
2525   PetscFunctionReturn(0);
2526 }
2527 
2528 PetscErrorCode DMView_Network(DM dm,PetscViewer viewer)
2529 {
2530   PetscErrorCode ierr;
2531   PetscBool      iascii;
2532   PetscMPIInt    rank;
2533 
2534   PetscFunctionBegin;
2535   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE,"Must call DMSetUp() first");
2536   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRMPI(ierr);
2537   PetscValidHeaderSpecific(dm,DM_CLASSID, 1);
2538   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2539   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
2540   if (iascii) {
2541     const PetscInt *cone,*vtx,*edges;
2542     PetscInt       vfrom,vto,i,j,nv,ne,ncv,p,nsubnet;
2543     DM_Network     *network = (DM_Network*)dm->data;
2544 
2545     nsubnet = network->Nsubnet; /* num of subnetworks */
2546     if (!rank) {
2547       ierr = PetscPrintf(PETSC_COMM_SELF,"  NSubnets: %D; NEdges: %D; NVertices: %D; NSharedVertices: %D.\n",nsubnet,network->NEdges,network->NVertices,network->Nsvtx);CHKERRQ(ierr);
2548     }
2549 
2550     ierr = DMNetworkGetSharedVertices(dm,&ncv,&vtx);CHKERRQ(ierr);
2551     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
2552     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nEdges: %D; nVertices: %D; nSharedVertices: %D\n",rank,network->nEdges,network->nVertices,ncv);CHKERRQ(ierr);
2553 
2554     for (i=0; i<nsubnet; i++) {
2555       ierr = DMNetworkGetSubnetwork(dm,i,&nv,&ne,&vtx,&edges);CHKERRQ(ierr);
2556       if (ne) {
2557         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %D: nEdges %D, nVertices(include shared vertices) %D\n",i,ne,nv);CHKERRQ(ierr);
2558         for (j=0; j<ne; j++) {
2559           p = edges[j];
2560           ierr = DMNetworkGetConnectedVertices(dm,p,&cone);CHKERRQ(ierr);
2561           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[0],&vfrom);CHKERRQ(ierr);
2562           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[1],&vto);CHKERRQ(ierr);
2563           ierr = DMNetworkGetGlobalEdgeIndex(dm,edges[j],&p);CHKERRQ(ierr);
2564           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "       edge %D: %D ----> %D\n",p,vfrom,vto);CHKERRQ(ierr);
2565         }
2566       }
2567     }
2568 
2569     /* Shared vertices */
2570     ierr = DMNetworkGetSharedVertices(dm,&ncv,&vtx);CHKERRQ(ierr);
2571     if (ncv) {
2572       SVtx       *svtx = network->svtx;
2573       PetscInt    gidx,svtx_idx,nvto,vfrom_net,vfrom_idx,*svto;
2574       PetscBool   ghost;
2575       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "     SharedVertices:\n");CHKERRQ(ierr);
2576       for (i=0; i<ncv; i++) {
2577         ierr = DMNetworkIsGhostVertex(dm,vtx[i],&ghost);CHKERRQ(ierr);
2578         if (ghost) continue;
2579 
2580         ierr = DMNetworkGetGlobalVertexIndex(dm,vtx[i],&gidx);CHKERRQ(ierr);
2581         ierr = PetscTableFind(network->svtable,gidx+1,&svtx_idx);CHKERRQ(ierr);
2582         svtx_idx--;
2583         nvto = svtx[svtx_idx].n;
2584 
2585         vfrom_net = svtx[svtx_idx].sv[0];
2586         vfrom_idx = svtx[svtx_idx].sv[1];
2587         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "       svtx %D: global index %D, subnet[%D].%D ---->\n",i,gidx,vfrom_net,vfrom_idx);CHKERRQ(ierr);
2588         for (j=1; j<nvto; j++) {
2589           svto = svtx[svtx_idx].sv + 2*j;
2590           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "                                           ----> subnet[%D].%D\n",svto[0],svto[1]);CHKERRQ(ierr);
2591         }
2592       }
2593     }
2594     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
2595     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
2596   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMNetwork writing", ((PetscObject)viewer)->type_name);
2597   PetscFunctionReturn(0);
2598 }
2599 
2600 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
2601 {
2602   PetscErrorCode ierr;
2603   DM_Network     *network = (DM_Network*)dm->data;
2604 
2605   PetscFunctionBegin;
2606   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
2607   PetscFunctionReturn(0);
2608 }
2609 
2610 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
2611 {
2612   PetscErrorCode ierr;
2613   DM_Network     *network = (DM_Network*)dm->data;
2614 
2615   PetscFunctionBegin;
2616   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
2617   PetscFunctionReturn(0);
2618 }
2619 
2620 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
2621 {
2622   PetscErrorCode ierr;
2623   DM_Network     *network = (DM_Network*)dm->data;
2624 
2625   PetscFunctionBegin;
2626   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
2627   PetscFunctionReturn(0);
2628 }
2629 
2630 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
2631 {
2632   PetscErrorCode ierr;
2633   DM_Network     *network = (DM_Network*)dm->data;
2634 
2635   PetscFunctionBegin;
2636   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
2637   PetscFunctionReturn(0);
2638 }
2639 
2640 /*@
2641   DMNetworkGetVertexLocalToGlobalOrdering - Get vertex global index
2642 
2643   Not collective
2644 
2645   Input Parameters:
2646 + dm - the dm object
2647 - vloc - local vertex ordering, start from 0
2648 
2649   Output Parameters:
2650 .  vg  - global vertex ordering, start from 0
2651 
2652   Level: advanced
2653 
2654 .seealso: DMNetworkSetVertexLocalToGlobalOrdering()
2655 @*/
2656 PetscErrorCode DMNetworkGetVertexLocalToGlobalOrdering(DM dm,PetscInt vloc,PetscInt *vg)
2657 {
2658   DM_Network  *network = (DM_Network*)dm->data;
2659   PetscInt    *vltog = network->vltog;
2660 
2661   PetscFunctionBegin;
2662   if (!vltog) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkSetVertexLocalToGlobalOrdering() first");
2663   *vg = vltog[vloc];
2664   PetscFunctionReturn(0);
2665 }
2666 
2667 /*@
2668   DMNetworkSetVertexLocalToGlobalOrdering - Create and setup vertex local to global map
2669 
2670   Collective
2671 
2672   Input Parameters:
2673 . dm - the dm object
2674 
2675   Level: advanced
2676 
2677 .seealso: DMNetworkGetGlobalVertexIndex()
2678 @*/
2679 PetscErrorCode DMNetworkSetVertexLocalToGlobalOrdering(DM dm)
2680 {
2681   PetscErrorCode    ierr;
2682   DM_Network        *network=(DM_Network*)dm->data;
2683   MPI_Comm          comm;
2684   PetscMPIInt       rank,size,*displs=NULL,*recvcounts=NULL,remoterank;
2685   PetscBool         ghost;
2686   PetscInt          *vltog,nroots,nleaves,i,*vrange,k,N,lidx;
2687   const PetscSFNode *iremote;
2688   PetscSF           vsf;
2689   Vec               Vleaves,Vleaves_seq;
2690   VecScatter        ctx;
2691   PetscScalar       *varr,val;
2692   const PetscScalar *varr_read;
2693 
2694   PetscFunctionBegin;
2695   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2696   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
2697   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
2698 
2699   if (size == 1) {
2700     nroots = network->vEnd - network->vStart;
2701     ierr = PetscMalloc1(nroots, &vltog);CHKERRQ(ierr);
2702     for (i=0; i<nroots; i++) vltog[i] = i;
2703     network->vltog = vltog;
2704     PetscFunctionReturn(0);
2705   }
2706 
2707   if (!network->distributecalled) SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkDistribute() first");
2708   if (network->vltog) {
2709     ierr = PetscFree(network->vltog);CHKERRQ(ierr);
2710   }
2711 
2712   ierr = DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);CHKERRQ(ierr);
2713   ierr = PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);CHKERRQ(ierr);
2714   vsf = network->vertex.sf;
2715 
2716   ierr = PetscMalloc3(size+1,&vrange,size,&displs,size,&recvcounts);CHKERRQ(ierr);
2717   ierr = PetscSFGetGraph(vsf,&nroots,&nleaves,NULL,&iremote);CHKERRQ(ierr);
2718 
2719   for (i=0; i<size; i++) { displs[i] = i; recvcounts[i] = 1;}
2720 
2721   i         = nroots - nleaves; /* local number of vertices, excluding ghosts */
2722   vrange[0] = 0;
2723   ierr = MPI_Allgatherv(&i,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm);CHKERRMPI(ierr);
2724   for (i=2; i<size+1; i++) {vrange[i] += vrange[i-1];}
2725 
2726   ierr = PetscMalloc1(nroots, &vltog);CHKERRQ(ierr);
2727   network->vltog = vltog;
2728 
2729   /* Set vltog for non-ghost vertices */
2730   k = 0;
2731   for (i=0; i<nroots; i++) {
2732     ierr = DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost);CHKERRQ(ierr);
2733     if (ghost) continue;
2734     vltog[i] = vrange[rank] + k++;
2735   }
2736   ierr = PetscFree3(vrange,displs,recvcounts);CHKERRQ(ierr);
2737 
2738   /* Set vltog for ghost vertices */
2739   /* (a) create parallel Vleaves and sequential Vleaves_seq to convert local iremote[*].index to global index */
2740   ierr = VecCreate(comm,&Vleaves);CHKERRQ(ierr);
2741   ierr = VecSetSizes(Vleaves,2*nleaves,PETSC_DETERMINE);CHKERRQ(ierr);
2742   ierr = VecSetFromOptions(Vleaves);CHKERRQ(ierr);
2743   ierr = VecGetArray(Vleaves,&varr);CHKERRQ(ierr);
2744   for (i=0; i<nleaves; i++) {
2745     varr[2*i]   = (PetscScalar)(iremote[i].rank);  /* rank of remote process */
2746     varr[2*i+1] = (PetscScalar)(iremote[i].index); /* local index in remote process */
2747   }
2748   ierr = VecRestoreArray(Vleaves,&varr);CHKERRQ(ierr);
2749 
2750   /* (b) scatter local info to remote processes via VecScatter() */
2751   ierr = VecScatterCreateToAll(Vleaves,&ctx,&Vleaves_seq);CHKERRQ(ierr);
2752   ierr = VecScatterBegin(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2753   ierr = VecScatterEnd(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2754 
2755   /* (c) convert local indices to global indices in parallel vector Vleaves */
2756   ierr = VecGetSize(Vleaves_seq,&N);CHKERRQ(ierr);
2757   ierr = VecGetArrayRead(Vleaves_seq,&varr_read);CHKERRQ(ierr);
2758   for (i=0; i<N; i+=2) {
2759     remoterank = (PetscMPIInt)PetscRealPart(varr_read[i]);
2760     if (remoterank == rank) {
2761       k = i+1; /* row number */
2762       lidx = (PetscInt)PetscRealPart(varr_read[i+1]);
2763       val  = (PetscScalar)vltog[lidx]; /* global index for non-ghost vertex computed above */
2764       ierr = VecSetValues(Vleaves,1,&k,&val,INSERT_VALUES);CHKERRQ(ierr);
2765     }
2766   }
2767   ierr = VecRestoreArrayRead(Vleaves_seq,&varr_read);CHKERRQ(ierr);
2768   ierr = VecAssemblyBegin(Vleaves);CHKERRQ(ierr);
2769   ierr = VecAssemblyEnd(Vleaves);CHKERRQ(ierr);
2770 
2771   /* (d) Set vltog for ghost vertices by copying local values of Vleaves */
2772   ierr = VecGetArrayRead(Vleaves,&varr_read);CHKERRQ(ierr);
2773   k = 0;
2774   for (i=0; i<nroots; i++) {
2775     ierr = DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost);CHKERRQ(ierr);
2776     if (!ghost) continue;
2777     vltog[i] = (PetscInt)PetscRealPart(varr_read[2*k+1]); k++;
2778   }
2779   ierr = VecRestoreArrayRead(Vleaves,&varr_read);CHKERRQ(ierr);
2780 
2781   ierr = VecDestroy(&Vleaves);CHKERRQ(ierr);
2782   ierr = VecDestroy(&Vleaves_seq);CHKERRQ(ierr);
2783   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
2784   PetscFunctionReturn(0);
2785 }
2786