Actual source code: network.c

  1: #include <petsc/private/dmnetworkimpl.h>

  3: /*
  4:   Creates the component header and value objects for a network point
  5: */
  6: static PetscErrorCode SetUpNetworkHeaderComponentValue(DM dm,DMNetworkComponentHeader header,DMNetworkComponentValue cvalue)
  7: {

 11:   /* Allocate arrays for component information */
 12:   PetscCalloc5(header->maxcomps,&header->size,header->maxcomps,&header->key,header->maxcomps,&header->offset,header->maxcomps,&header->nvar,header->maxcomps,&header->offsetvarrel);
 13:   PetscCalloc1(header->maxcomps,&cvalue->data);

 15:   /* The size of the header is the size of struct _p_DMNetworkComponentHeader. Since the struct contains PetscInt pointers we cannot use sizeof(struct). So, we need to explicitly calculate the size.
 16:    If the data header struct changes then this header size calculation needs to be updated. */
 17:   header->hsize = sizeof(struct _p_DMNetworkComponentHeader) + 5*header->maxcomps*sizeof(PetscInt);
 18:   header->hsize /= sizeof(DMNetworkComponentGenericDataType);
 19:   return(0);
 20: }

 22: /*@
 23:   DMNetworkGetPlex - Gets the Plex DM associated with this network DM

 25:   Not collective

 27:   Input Parameters:
 28: . dm - the dm object

 30:   Output Parameters:
 31: . plexdm - the plex dm object

 33:   Level: Advanced

 35: .seealso: DMNetworkCreate()
 36: @*/
 37: PetscErrorCode DMNetworkGetPlex(DM dm,DM *plexdm)
 38: {
 39:   DM_Network *network = (DM_Network*)dm->data;

 42:   *plexdm = network->plex;
 43:   return(0);
 44: }

 46: /*@
 47:   DMNetworkGetNumSubNetworks - Gets the the number of subnetworks

 49:   Not collective

 51:   Input Parameter:
 52: . dm - the dm object

 54:   Output Parameters:
 55: + nsubnet - local number of subnetworks
 56: - Nsubnet - global number of subnetworks

 58:   Level: beginner

 60: .seealso: DMNetworkCreate(), DMNetworkSetNumSubNetworks()
 61: @*/
 62: PetscErrorCode DMNetworkGetNumSubNetworks(DM dm,PetscInt *nsubnet,PetscInt *Nsubnet)
 63: {
 64:   DM_Network *network = (DM_Network*)dm->data;

 67:   if (nsubnet) *nsubnet = network->nsubnet;
 68:   if (Nsubnet) *Nsubnet = network->Nsubnet;
 69:   return(0);
 70: }

 72: /*@
 73:   DMNetworkSetNumSubNetworks - Sets the number of subnetworks

 75:   Collective on dm

 77:   Input Parameters:
 78: + dm - the dm object
 79: . nsubnet - local number of subnetworks
 80: - Nsubnet - global number of subnetworks

 82:    Level: beginner

 84: .seealso: DMNetworkCreate(), DMNetworkGetNumSubNetworks()
 85: @*/
 86: PetscErrorCode DMNetworkSetNumSubNetworks(DM dm,PetscInt nsubnet,PetscInt Nsubnet)
 87: {
 89:   DM_Network     *network = (DM_Network*)dm->data;

 92:   if (network->Nsubnet != 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Network sizes alread set, cannot resize the network");


 98:   if (Nsubnet == PETSC_DECIDE) {
 99:     if (nsubnet < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of local subnetworks %D cannot be less than 0",nsubnet);
100:     MPIU_Allreduce(&nsubnet,&Nsubnet,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));
101:   }
102:   if (Nsubnet < 1) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Number of global subnetworks %D cannot be less than 1",Nsubnet);

104:   network->Nsubnet  = Nsubnet;
105:   network->nsubnet  = 0;       /* initia value; will be determind by DMNetworkAddSubnetwork() */
106:   PetscCalloc1(Nsubnet,&network->subnet);

108:   /* num of shared vertices */
109:   network->nsvtx = 0;
110:   network->Nsvtx = 0;
111:   return(0);
112: }

114: /*@
115:   DMNetworkAddSubnetwork - Add a subnetwork

117:   Collective on dm

119:   Input Parameters:
120: + dm - the dm object
121: . name - name of the subnetwork
122: . ne - number of local edges of this subnetwork
123: - edgelist - list of edges for this subnetwork, this is a one dimensional array with pairs of entries being the two vertices (in global numbering of the vertices) of each edge,
124: $            [first vertex of first edge, second vertex of first edge, first vertex of second edge, second vertex of second edge, etc]

126:   Output Parameters:
127: . netnum - global index of the subnetwork

129:   Notes:
130:   There is no copy involved in this operation, only the pointer is referenced. The edgelist should
131:   not be destroyed before the call to DMNetworkLayoutSetUp()

133:   A network can comprise of a single subnetwork OR multiple subnetworks. For a single subnetwork, the subnetwork can be read either in serial or parallel. For a multiple subnetworks,
134:   each subnetwork topology needs to be set on a unique rank and the communicator size needs to be at least equal to the number of subnetworks.

136:   Level: beginner

138:   Example usage:
139:   Consider the following networks:
140:   1) A sigle subnetwork:
141: .vb
142:  network 0:
143:  rank[0]:
144:    v0 --> v2; v1 --> v2
145:  rank[1]:
146:    v3 --> v5; v4 --> v5
147: .ve

149:  The resulting input
150:  network 0:
151:  rank[0]:
152:    ne = 2
153:    edgelist = [0 2 | 1 2]
154:  rank[1]:
155:    ne = 2
156:    edgelist = [3 5 | 4 5]

158:   2) Two subnetworks:
159: .vb
160:  subnetwork 0:
161:  rank[0]:
162:    v0 --> v2; v2 --> v1; v1 --> v3;
163:  subnetwork 1:
164:  rank[1]:
165:    v0 --> v3; v3 --> v2; v2 --> v1;
166: .ve

168:  The resulting input
169:  subnetwork 0:
170:  rank[0]:
171:    ne = 3
172:    edgelist = [0 2 | 2 1 | 1 3]
173:  rank[1]:
174:    ne = 0
175:    edgelist = NULL

177:  subnetwork 1:
178:  rank[0]:
179:    ne = 0
180:    edgelist = NULL
181:  rank[1]:
182:    edgelist = [0 3 | 3 2 | 2 1]

184: .seealso: DMNetworkCreate(), DMNetworkSetNumSubnetworks()
185: @*/
186: PetscErrorCode DMNetworkAddSubnetwork(DM dm,const char* name,PetscInt ne,PetscInt edgelist[],PetscInt *netnum)
187: {
189:   DM_Network     *network = (DM_Network*)dm->data;
190:   PetscInt       i,Nedge,j,Nvtx,nvtx;
191:   PetscBT        table;

194:   for (i=0; i<ne; i++) {
195:     if (edgelist[2*i] == edgelist[2*i+1]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Edge %D has the same vertex %D at each endpoint",i,edgelist[2*i]);
196:   }
197:   /* Get global total Nvtx = max(edgelist[])+1 for this subnet */
198:   nvtx = -1; i = 0;
199:   for (j=0; j<ne; j++) {
200:     nvtx = PetscMax(nvtx, edgelist[i]); i++;
201:     nvtx = PetscMax(nvtx, edgelist[i]); i++;
202:   }
203:   nvtx++;
204:   MPIU_Allreduce(&nvtx,&Nvtx,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));

206:   /* Get local nvtx for this subnet */
207:   PetscBTCreate(Nvtx,&table);
208:   PetscBTMemzero(Nvtx,table);
209:   i = 0;
210:   for (j=0; j<ne; j++) {
211:     PetscBTSet(table,edgelist[i]);
212:     i++;
213:     PetscBTSet(table,edgelist[i]);
214:     i++;
215:   }
216:   nvtx = 0;
217:   for (j=0; j<Nvtx; j++) {
218:     if (PetscBTLookup(table,j)) nvtx++;
219:   }
220:   PetscBTDestroy(&table);

222:   /* Get global total Nedge for this subnet */
223:   MPIU_Allreduce(&ne,&Nedge,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));

225:   i = network->nsubnet;
226:   if (name) {
227:     PetscStrcpy(network->subnet[i].name,name);
228:   }
229:   network->subnet[i].nvtx     = nvtx; /* include ghost vertices */
230:   network->subnet[i].nedge    = ne;
231:   network->subnet[i].edgelist = edgelist;
232:   network->subnet[i].Nvtx     = Nvtx;
233:   network->subnet[i].Nedge    = Nedge;

235:   /* ----------------------------------------------------------
236:    p=v or e;
237:    subnet[0].pStart   = 0
238:    subnet[i+1].pStart = subnet[i].pEnd = subnet[i].pStart + (nE[i] or NV[i])
239:    ----------------------------------------------------------------------- */
240:   /* GLOBAL subnet[].vStart and vEnd, used by DMNetworkLayoutSetUp() */
241:   network->subnet[i].vStart = network->NVertices;
242:   network->subnet[i].vEnd   = network->subnet[i].vStart + network->subnet[i].Nvtx; /* global vEnd of subnet[i] */

244:   network->nVertices += nvtx; /* include ghost vertices */
245:   network->NVertices += network->subnet[i].Nvtx;

247:   /* LOCAL subnet[].eStart and eEnd, used by DMNetworkLayoutSetUp() */
248:   network->subnet[i].eStart = network->nEdges;
249:   network->subnet[i].eEnd   = network->subnet[i].eStart + ne;
250:   network->nEdges += ne;
251:   network->NEdges += network->subnet[i].Nedge;

253:   PetscStrcpy(network->subnet[i].name,name);
254:   if (netnum) *netnum = network->nsubnet;
255:   network->nsubnet++;
256:   return(0);
257: }

259: /*
260:   SetUp a single svtx struct. See SVtx defined in dmnetworkimpl.h
261:   Set gidx and type if input v=(net,idx) is a from_vertex;
262:   Get gid, type and index in the svtx array if input v=(net,idx) is a to_vertex.

264:   Input:  Nsvtx, svtx, net, idx, gidx
265:   Output: gidx, svtype, svtx_idx
266:  */
267: static PetscErrorCode SVtxSetUp(PetscInt Nsvtx,SVtx *svtx,PetscInt net,PetscInt idx,PetscInt *gidx,SVtxType *svtype,PetscInt *svtx_idx)
268: {
269:   PetscInt i,j,*svto;
270:   SVtxType vtype;

273:   if (!Nsvtx) return(0);

275:   vtype = SVNONE;
276:   for (i=0; i<Nsvtx; i++) {
277:     if (net == svtx[i].sv[0] && idx == svtx[i].sv[1]) {
278:       /* (1) input vertex net.idx is a shared from_vertex, set its global index and output its svtype */
279:       svtx[i].gidx = *gidx; /* set gidx */
280:       vtype        = SVFROM;
281:     } else { /* loop over svtx[i].n */
282:       for (j=1; j<svtx[i].n; j++) {
283:         svto = svtx[i].sv + 2*j;
284:         if (net == svto[0] && idx == svto[1]) {
285:           /* input vertex net.idx is a shared to_vertex, output its global index and its svtype */
286:           *gidx = svtx[i].gidx; /* output gidx for to_vertex */
287:           vtype = SVTO;
288:         }
289:       }
290:     }
291:     if (vtype != SVNONE) break;
292:   }
293:   if (svtype)   *svtype   = vtype;
294:   if (svtx_idx) *svtx_idx = i;
295:   return(0);
296: }

298: /*
299:  Add a new shared vertex sv=(net,idx) to table svtas[ita]
300: */
301: static PetscErrorCode TableAddSVtx(PetscTable *svtas,PetscInt ita,PetscInt* tdata,PetscInt *sv_wk,PetscInt *ii,PetscInt *sedgelist,PetscInt k,DM_Network *network,PetscInt **ta2sv)
302: {
303:   PetscInt       net,idx,gidx,i=*ii;

307:   net = sv_wk[2*i]   = sedgelist[k];
308:   idx = sv_wk[2*i+1] = sedgelist[k+1];
309:   gidx = network->subnet[net].vStart + idx;
310:   PetscTableAdd(svtas[ita],gidx+1,tdata[ita]+1,INSERT_VALUES);
311:   *(ta2sv[ita] + tdata[ita]) = i; /* maps tdata to index of sv_wk; sv_wk keeps (net,idx) info */
312:   tdata[ita]++; (*ii)++;
313:   return(0);
314: }

316: /*
317:   Create an array of shared vertices. See SVtx and SVtxType in dmnetworkimpl.h

319:   Input:  dm, Nsedgelist, sedgelist
320:   Output: Nsvtx,svtx

322:   Note: Output svtx is organized as
323:         sv(net[0],idx[0]) --> sv(net[1],idx[1])
324:                           --> sv(net[1],idx[1])
325:                           ...
326:                           --> sv(net[n-1],idx[n-1])
327:         and net[0] < net[1] < ... < net[n-1]
328:         where sv[0] has SVFROM type, sv[i], i>0, has SVTO type.
329:  */
330: static PetscErrorCode SVtxCreate(DM dm,PetscInt Nsedgelist,PetscInt *sedgelist,PetscInt *Nsvtx,SVtx **svtx)
331: {
333:   SVtx           *sedges = NULL;
334:   PetscInt       *sv,k,j,nsv,*tdata,**ta2sv;
335:   PetscTable     *svtas;
336:   PetscInt       gidx,net,idx,i,nta,ita,idx_from,idx_to,n,*sv_wk;
337:   DM_Network     *network = (DM_Network*)dm->data;
338:   PetscTablePosition ppos;

341:   /* (1) Crete ctables svtas */
342:   PetscCalloc4(Nsedgelist,&svtas,Nsedgelist,&tdata,4*Nsedgelist,&sv_wk,2*Nsedgelist,&ta2sv);

344:   j   = 0;   /* sedgelist counter */
345:   k   = 0;   /* sedgelist vertex counter j = 4*k */
346:   i   = 0;   /* sv_wk (vertices added to the ctables) counter */
347:   nta = 0;   /* num of sv tables created */

349:   /* for j=0 */
350:   PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]);
351:   PetscMalloc1(2*Nsedgelist,&ta2sv[nta]);

353:   TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);
354:   TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);
355:   nta++; k += 4;

357:   for (j = 1; j < Nsedgelist; j++) {
358:     for (ita = 0; ita < nta; ita++) {
359:       /* vfrom */
360:       net = sedgelist[k]; idx = sedgelist[k+1];
361:       gidx = network->subnet[net].vStart + idx; /* global index of the vertex net.idx before merging shared vertices */
362:       PetscTableFind(svtas[ita],gidx+1,&idx_from);

364:       /* vto */
365:       net = sedgelist[k+2]; idx = sedgelist[k+3];
366:       gidx = network->subnet[net].vStart + idx;
367:       PetscTableFind(svtas[ita],gidx+1,&idx_to);

369:       if (idx_from || idx_to) { /* vfrom or vto is on table svtas[ita] */
370:         idx_from--; idx_to--;
371:         if (idx_from < 0) { /* vto is on svtas[ita] */
372:           TableAddSVtx(svtas,ita,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);
373:           break;
374:         } else if (idx_to < 0) {
375:           TableAddSVtx(svtas,ita,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);
376:           break;
377:         }
378:       }
379:     }

381:     if (ita == nta) {
382:       PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]);
383:       PetscMalloc1(2*Nsedgelist, &ta2sv[nta]);

385:       TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k,network,ta2sv);
386:       TableAddSVtx(svtas,nta,tdata,sv_wk,&i,sedgelist,k+2,network,ta2sv);
387:       nta++;
388:     }
389:     k += 4;
390:   }

392:   /* (2) Construct sedges from ctable
393:      sedges: edges connect vertex sv[0]=(net[0],idx[0]) to vertices sv[k], k=1,...,n-1;
394:      net[k], k=0, ...,n-1, are in ascending order */
395:   PetscMalloc1(nta,&sedges);
396:   for (nsv = 0; nsv < nta; nsv++) {
397:     /* for a single svtx, put shared vertices in ascending order of gidx */
398:     PetscTableGetCount(svtas[nsv],&n);
399:     PetscCalloc1(2*n,&sv);
400:     sedges[nsv].sv   = sv;
401:     sedges[nsv].n    = n;
402:     sedges[nsv].gidx = -1; /* initialization */

404:     PetscTableGetHeadPosition(svtas[nsv],&ppos);
405:     for (k=0; k<n; k++) { /* gidx is sorted in ascending order */
406:       PetscTableGetNext(svtas[nsv],&ppos,&gidx,&i);
407:       gidx--; i--;

409:       j = ta2sv[nsv][i]; /* maps i to index of sv_wk */
410:       sv[2*k]   = sv_wk[2*j];
411:       sv[2*k+1] = sv_wk[2*j + 1];
412:     }
413:   }

415:   for (j=0; j<nta; j++) {
416:     PetscTableDestroy(&svtas[j]);
417:     PetscFree(ta2sv[j]);
418:   }
419:   PetscFree4(svtas,tdata,sv_wk,ta2sv);

421:   *Nsvtx = nta;
422:   *svtx  = sedges;
423:   return(0);
424: }

426: static PetscErrorCode DMNetworkLayoutSetUp_Coupling(DM dm)
427: {
429:   DM_Network     *network = (DM_Network*)dm->data;
430:   PetscInt       i,j,ctr,np,*edges,*subnetvtx,*subnetedge,vStart;
431:   PetscInt       k,*vidxlTog,Nsv=0,Nsubnet=network->Nsubnet;
432:   PetscInt       *sedgelist=network->sedgelist;
433:   const PetscInt *cone;
434:   MPI_Comm       comm;
435:   PetscMPIInt    size,rank,*recvcounts=NULL,*displs=NULL;
436:   PetscInt       net,idx,gidx,nmerged,e,v,vfrom,vto,*vrange,*eowners,gidx_from,net_from,sv_idx;
437:   SVtxType       svtype = SVNONE;
438:   SVtx           *svtx=NULL;
439:   PetscSection   sectiong;

442:   /* This implementation requires user input each subnet by a single processor, thus subnet[net].nvtx=subnet[net].Nvtx */
443:   for (net=0; net<Nsubnet; net++) {
444:     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);
445:   }

447:   PetscObjectGetComm((PetscObject)dm,&comm);
448:   MPI_Comm_rank(comm,&rank);
449:   MPI_Comm_size(comm,&size);

451:   /* (1) Create svtx[] from sedgelist */
452:   /* -------------------------------- */
453:   /* Nsv: global number of SVtx; svtx: shared vertices, see SVtx in dmnetworkimpl.h */
454:   SVtxCreate(dm,network->Nsvtx,sedgelist,&Nsv,&svtx);

456:   /* (2) Setup svtx; Shared vto vertices are merged to their vfrom vertex with same global vetex index (gidx) */
457:   /* -------------------------------------------------------------------------------------------------------- */
458:   /* (2.1) compute vrage[rank]: global index of 1st local vertex in proc[rank] */
459:   PetscMalloc3(size+1,&vrange,size,&displs,size,&recvcounts);
460:   for (i=0; i<size; i++) {displs[i] = i; recvcounts[i] = 1;}

462:   vrange[0] = 0;
463:   MPI_Allgatherv(&network->nVertices,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm);
464:   for (i=2; i<size+1; i++) {
465:     vrange[i] += vrange[i-1];
466:   }

468:   /* (2.2) Create vidxlTog: maps UN-MERGED local vertex index i to global index gidx (plex, excluding ghost vertices) */
469:   PetscMalloc1(network->nVertices,&vidxlTog);
470:   i = 0; gidx = 0;
471:   nmerged = 0; /* local num of merged vertices */
472:   network->nsvtx = 0;
473:   for (net=0; net<Nsubnet; net++) {
474:     for (idx=0; idx<network->subnet[net].Nvtx; idx++) {
475:       gidx_from = gidx;
476:       sv_idx    = -1;

478:       SVtxSetUp(Nsv,svtx,net,idx,&gidx_from,&svtype,&sv_idx);
479:       if (svtype == SVTO) {
480:         if (network->subnet[net].nvtx) {/* this proc owns sv_to */
481:           net_from = svtx[sv_idx].sv[0]; /* subnet num of its shared vertex */
482:           if (network->subnet[net_from].nvtx == 0) {
483:             /* this proc does not own v_from, thus a new local coupling vertex */
484:             network->nsvtx++;
485:           }
486:           vidxlTog[i++] = gidx_from;
487:           nmerged++; /* a coupling vertex -- merged */
488:         }
489:       } else {
490:         if (svtype == SVFROM) {
491:           if (network->subnet[net].nvtx) {
492:             /* this proc owns this v_from, a new local coupling vertex */
493:             network->nsvtx++;
494:           }
495:         }
496:         if (network->subnet[net].nvtx) vidxlTog[i++] = gidx;
497:         gidx++;
498:       }
499:     }
500:   }
501: #if defined(PETSC_USE_DEBUG)
502:   if (i != network->nVertices) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"%D != %D nVertices",i,network->nVertices);
503: #endif

505:   /* (2.3) Setup svtable for querry shared vertices */
506:   for (v=0; v<Nsv; v++) {
507:     gidx = svtx[v].gidx;
508:     PetscTableAdd(network->svtable,gidx+1,v+1,INSERT_VALUES);
509:   }

511:   /* (2.4) Shared vertices in the subnetworks are merged, update global NVertices: np = sum(local nmerged) */
512:   MPI_Allreduce(&nmerged,&np,1,MPIU_INT,MPI_SUM,comm);
513:   network->NVertices -= np;

515:   PetscCalloc1(2*network->nEdges,&edges);

517:   ctr = 0;
518:   for (net=0; net<Nsubnet; net++) {
519:     for (j = 0; j < network->subnet[net].nedge; j++) {
520:       /* vfrom: */
521:       i = network->subnet[net].edgelist[2*j] + (network->subnet[net].vStart - vrange[rank]);
522:       edges[2*ctr] = vidxlTog[i];

524:       /* vto */
525:       i = network->subnet[net].edgelist[2*j+1] + (network->subnet[net].vStart - vrange[rank]);
526:       edges[2*ctr+1] = vidxlTog[i];
527:       ctr++;
528:     }
529:   }
530:   PetscFree3(vrange,displs,recvcounts);
531:   PetscFree(vidxlTog);

533:   /* (3) Create network->plex */
534:   DMCreate(comm,&network->plex);
535:   DMSetType(network->plex,DMPLEX);
536:   DMSetDimension(network->plex,1);
537:   if (size == 1) {
538:     DMPlexBuildFromCellList(network->plex,network->nEdges,network->nVertices-nmerged,2,edges);
539:   } else {
540:     DMPlexBuildFromCellListParallel(network->plex,network->nEdges,network->nVertices-nmerged,PETSC_DECIDE,2,edges,NULL);
541:   }

543:   DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);
544:   DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);
545:   DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);
546:   vStart = network->vStart;

548:   PetscSectionCreate(comm,&network->DataSection);
549:   PetscSectionCreate(comm,&network->DofSection);
550:   PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);
551:   PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);

553:   np = network->pEnd - network->pStart;
554:   PetscCalloc2(np,&network->header,np,&network->cvalue);
555:   for (i=0; i<np; i++) {
556:     network->header[i].maxcomps = 1;
557:     SetUpNetworkHeaderComponentValue(dm,&network->header[i],&network->cvalue[i]);
558:   }

560:   /* (4) Create edge and vertex arrays for the subnetworks */
561:   PetscCalloc2(network->nEdges,&subnetedge,network->nVertices+network->nsvtx,&subnetvtx); /* Maps local edge/vertex to local subnetwork's edge/vertex */
562:   network->subnetedge = subnetedge;
563:   network->subnetvtx  = subnetvtx;
564:   for (j=0; j < Nsubnet; j++) {
565:     network->subnet[j].edges = subnetedge;
566:     subnetedge              += network->subnet[j].nedge;

568:     network->subnet[j].vertices = subnetvtx;
569:     subnetvtx                  += network->subnet[j].nvtx;
570:   }
571:   network->svertices = subnetvtx;

573:   /* Get edge ownership */
574:   PetscMalloc1(size+1,&eowners);
575:   np = network->eEnd - network->eStart; /* num of local edges */
576:   MPI_Allgather(&np,1,MPIU_INT,eowners+1,1,MPIU_INT,comm);
577:   eowners[0] = 0;
578:   for (i=2; i<=size; i++) eowners[i] += eowners[i-1];

580:   /* Setup edge and vertex arrays for subnetworks */
581:   e = 0;
582:   for (i=0; i < Nsubnet; i++) {
583:     ctr = 0;
584:     for (j = 0; j < network->subnet[i].nedge; j++) {
585:       /* edge e */
586:       network->header[e].index    = e + eowners[rank]; /* Global edge index */
587:       network->header[e].subnetid = i;                 /* Subnetwork id */
588:       network->subnet[i].edges[j] = e;
589:       network->header[e].ndata           = 0;
590:       network->header[e].offset[0]       = 0;
591:       network->header[e].offsetvarrel[0] = 0;
592:       PetscSectionAddDof(network->DataSection,e,network->header[e].hsize);

594:       /* connected vertices */
595:       DMPlexGetCone(network->plex,e,&cone);

597:       /* vertex cone[0] */
598:       v = cone[0];
599:       network->header[v].index    = edges[2*e];   /* Global vertex index */
600:       network->header[v].subnetid = i;            /* Subnetwork id */
601:       vfrom = network->subnet[i].edgelist[2*ctr];
602:       network->subnet[i].vertices[vfrom] = v;     /* user's subnet[].dix = petsc's v */

604:       /* vertex cone[1] */
605:       v = cone[1];
606:       network->header[v].index    = edges[2*e+1]; /* Global vertex index */
607:       network->header[v].subnetid = i;
608:       vto = network->subnet[i].edgelist[2*ctr+1];
609:       network->subnet[i].vertices[vto]= v;

611:       e++; ctr++;
612:     }
613:   }
614:   PetscFree(eowners);
615:   PetscFree(edges);

617:   /* Set vertex array for the subnetworks */
618:   k = 0;
619:   for (v=vStart; v<network->vEnd; v++) { /* local vertices, including ghosts */
620:     network->header[v].ndata           = 0;
621:     network->header[v].offset[0]       = 0;
622:     network->header[v].offsetvarrel[0] = 0;
623:     PetscSectionAddDof(network->DataSection,v,network->header[v].hsize);

625:     /* shared vertex */
626:     PetscTableFind(network->svtable,network->header[v].index+1,&i);
627:     if (i) network->svertices[k++] = v;
628:   }
629: #if defined(PETSC_USE_DEBUG)
630:   if (k != network->nsvtx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"k %D != %D nsvtx",k,network->nsvtx);
631: #endif

633:   network->svtx  = svtx;
634:   network->Nsvtx = Nsv;
635:   PetscFree(sedgelist);

637:   /* Create a global section to be used by DMNetworkIsGhostVertex() which is a non-collective routine */
638:   /* see snes_tutorials_network-ex1_4 */
639:   DMGetGlobalSection(network->plex,&sectiong);
640:   return(0);
641: }

643: /*@
644:   DMNetworkLayoutSetUp - Sets up the bare layout (graph) for the network

646:   Collective on dm

648:   Input Parameters:
649: . dm - the dmnetwork object

651:   Notes:
652:   This routine should be called after the network sizes and edgelists have been provided. It creates
653:   the bare layout of the network and sets up the network to begin insertion of components.

655:   All the components should be registered before calling this routine.

657:   Level: beginner

659: .seealso: DMNetworkSetNumSubNetworks(), DMNetworkAddSubnetwork()
660: @*/
661: PetscErrorCode DMNetworkLayoutSetUp(DM dm)
662: {
664:   DM_Network     *network = (DM_Network*)dm->data;
665:   PetscInt       i,j,ctr,Nsubnet=network->Nsubnet,*eowners,np,*edges,*subnetvtx,*subnetedge,e,v,vfrom,vto;
666:   const PetscInt *cone;
667:   MPI_Comm       comm;
668:   PetscMPIInt    size,rank;

671:   if (network->nsubnet != network->Nsubnet) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Must call DMNetworkAddSubnetwork() %D times",network->Nsubnet);

673:   /* Create svtable for querry shared vertices */
674:   PetscTableCreate(network->Nsvtx,network->NVertices+1,&network->svtable);

676:   if (network->Nsvtx) {
677:     DMNetworkLayoutSetUp_Coupling(dm);
678:     return(0);
679:   }

681:   PetscObjectGetComm((PetscObject)dm,&comm);
682:   MPI_Comm_rank(comm,&rank);
683:   MPI_Comm_size(comm,&size);

685:   /* Create LOCAL edgelist in global vertex ordering for the network by concatenating local input edgelists of the subnetworks */
686:   PetscCalloc1(2*network->nEdges,&edges);
687:   ctr = 0;
688:   for (i=0; i < Nsubnet; i++) {
689:     for (j = 0; j < network->subnet[i].nedge; j++) {
690:       edges[2*ctr]   = network->subnet[i].vStart + network->subnet[i].edgelist[2*j];
691:       edges[2*ctr+1] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j+1];
692:       ctr++;
693:     }
694:   }

696:   /* Create network->plex; One dimensional network, numCorners=2 */
697:   DMCreate(comm,&network->plex);
698:   DMSetType(network->plex,DMPLEX);
699:   DMSetDimension(network->plex,1);
700:   if (size == 1) {
701:     DMPlexBuildFromCellList(network->plex,network->nEdges,network->nVertices,2,edges);
702:   } else {
703:     DMPlexBuildFromCellListParallel(network->plex,network->nEdges,network->nVertices,PETSC_DECIDE,2,edges,NULL);
704:   }

706:   DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);
707:   DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);
708:   DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);

710:   PetscSectionCreate(comm,&network->DataSection);
711:   PetscSectionCreate(comm,&network->DofSection);
712:   PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);
713:   PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);

715:   np = network->pEnd - network->pStart;
716:   PetscCalloc2(np,&network->header,np,&network->cvalue);
717:   for (i=0; i < np; i++) {
718:     network->header[i].maxcomps = 1;
719:     SetUpNetworkHeaderComponentValue(dm,&network->header[i],&network->cvalue[i]);
720:   }

722:   /* Create edge and vertex arrays for the subnetworks
723:      This implementation assumes that DMNetwork reads
724:      (1) a single subnetwork in parallel; or
725:      (2) n subnetworks using n processors, one subnetwork/processor.
726:    */
727:   PetscCalloc2(network->nEdges,&subnetedge,network->nVertices,&subnetvtx); /* Maps local edge/vertex to local subnetwork's edge/vertex */

729:   network->subnetedge = subnetedge;
730:   network->subnetvtx  = subnetvtx;
731:   for (j=0; j < network->Nsubnet; j++) {
732:     network->subnet[j].edges = subnetedge;
733:     subnetedge              += network->subnet[j].nedge;

735:     network->subnet[j].vertices = subnetvtx;
736:     subnetvtx                  += network->subnet[j].nvtx;
737:   }

739:   /* Get edge ownership */
740:   PetscMalloc1(size+1,&eowners);
741:   np = network->eEnd - network->eStart;
742:   MPI_Allgather(&np,1,MPIU_INT,eowners+1,1,MPIU_INT,comm);
743:   eowners[0] = 0;
744:   for (i=2; i<=size; i++) eowners[i] += eowners[i-1];

746:   /* Setup edge and vertex arrays for subnetworks */
747:   e = 0;
748:   for (i=0; i < Nsubnet; i++) {
749:     ctr = 0;
750:     for (j = 0; j < network->subnet[i].nedge; j++) {
751:       /* edge e */
752:       network->header[e].index    = e + eowners[rank];   /* Global edge index */
753:       network->header[e].subnetid = i;
754:       network->subnet[i].edges[j] = e;

756:       network->header[e].ndata           = 0;
757:       network->header[e].offset[0]       = 0;
758:       network->header[e].offsetvarrel[0] = 0;
759:       PetscSectionAddDof(network->DataSection,e,network->header[e].hsize);

761:       /* connected vertices */
762:       DMPlexGetCone(network->plex,e,&cone);

764:       /* vertex cone[0] */
765:       v = cone[0];
766:       network->header[v].index     = edges[2*e];  /* Global vertex index */
767:       network->header[v].subnetid  = i;           /* Subnetwork id */
768:       if (Nsubnet == 1) {
769:         network->subnet[i].vertices[v - network->vStart] = v; /* user's subnet[].idx = petsc's v */
770:       } else {
771:         vfrom = network->subnet[i].edgelist[2*ctr];     /* =subnet[i].idx, Global index! */
772:         network->subnet[i].vertices[vfrom] = v; /* user's subnet[].dix = petsc's v */
773:       }

775:       /* vertex cone[1] */
776:       v = cone[1];
777:       network->header[v].index    = edges[2*e+1];   /* Global vertex index */
778:       network->header[v].subnetid = i;              /* Subnetwork id */
779:       if (Nsubnet == 1) {
780:         network->subnet[i].vertices[v - network->vStart] = v; /* user's subnet[].idx = petsc's v */
781:       } else {
782:         vto = network->subnet[i].edgelist[2*ctr+1];     /* =subnet[i].idx, Global index! */
783:         network->subnet[i].vertices[vto] = v; /* user's subnet[].dix = petsc's v */
784:       }

786:       e++; ctr++;
787:     }
788:   }
789:   PetscFree(eowners);
790:   PetscFree(edges); /* local edge list with global idx used by DMPlexBuildFromCellList() */

792:   for (v = network->vStart; v < network->vEnd; v++) {
793:     network->header[v].ndata           = 0;
794:     network->header[v].offset[0]       = 0;
795:     network->header[v].offsetvarrel[0] = 0;
796:     PetscSectionAddDof(network->DataSection,v,network->header[e].hsize);
797:   }
798:   return(0);
799: }

801: /*@C
802:   DMNetworkGetSubnetwork - Returns the information about a requested subnetwork

804:   Not collective

806:   Input Parameters:
807: + dm - the DM object
808: - netnum - the global index of the subnetwork

810:   Output Parameters:
811: + nv - number of vertices (local)
812: . ne - number of edges (local)
813: . vtx - local vertices of the subnetwork
814: - edge - local edges of the subnetwork

816:   Notes:
817:   Cannot call this routine before DMNetworkLayoutSetup()

819:   Level: intermediate

821: .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkLayoutSetUp()
822: @*/
823: PetscErrorCode DMNetworkGetSubnetwork(DM dm,PetscInt netnum,PetscInt *nv,PetscInt *ne,const PetscInt **vtx,const PetscInt **edge)
824: {
825:   DM_Network *network = (DM_Network*)dm->data;

828:   if (netnum >= network->Nsubnet) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Subnet index %D exceeds the num of subnets %D",netnum,network->Nsubnet);
829:   if (nv) *nv     = network->subnet[netnum].nvtx;
830:   if (ne) *ne     = network->subnet[netnum].nedge;
831:   if (vtx) *vtx   = network->subnet[netnum].vertices;
832:   if (edge) *edge = network->subnet[netnum].edges;
833:   return(0);
834: }

836: /*@
837:   DMNetworkAddSharedVertices - Add shared vertices that connect two given subnetworks

839:   Collective on dm

841:   Input Parameters:
842: + dm - the dm object
843: . anetnum - first subnetwork global numbering returned by DMNetworkAddSubnetwork()
844: . bnetnum - second subnetwork global numbering returned by DMNetworkAddSubnetwork()
845: . nsvtx - number of vertices that are shared by the two subnetworks
846: . asvtx - vertex index in the first subnetwork
847: - bsvtx - vertex index in the second subnetwork

849:   Level: beginner

851: .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkGetSharedVertices()
852: @*/
853: PetscErrorCode DMNetworkAddSharedVertices(DM dm,PetscInt anetnum,PetscInt bnetnum,PetscInt nsvtx,PetscInt asvtx[],PetscInt bsvtx[])
854: {
856:   DM_Network     *network = (DM_Network*)dm->data;
857:   PetscInt       i,nsubnet = network->Nsubnet,*sedgelist,Nsvtx=network->Nsvtx;

860:   if (anetnum == bnetnum) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Subnetworks must have different netnum");
861:   if (anetnum < 0 || bnetnum < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"netnum cannot be negative");
862:   if (!Nsvtx) {
863:     /* allocate network->sedgelist to hold at most 2*nsubnet pairs of shared vertices */
864:     PetscMalloc1(2*4*nsubnet,&network->sedgelist);
865:   }

867:   sedgelist = network->sedgelist;
868:   for (i=0; i<nsvtx; i++) {
869:     sedgelist[4*Nsvtx]   = anetnum; sedgelist[4*Nsvtx+1] = asvtx[i];
870:     sedgelist[4*Nsvtx+2] = bnetnum; sedgelist[4*Nsvtx+3] = bsvtx[i];
871:     Nsvtx++;
872:   }
873:   if (Nsvtx > 2*nsubnet) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"allocate more space for coupling edgelist");
874:   network->Nsvtx = Nsvtx;
875:   return(0);
876: }

878: /*@C
879:   DMNetworkGetSharedVertices - Returns the info for the shared vertices

881:   Not collective

883:   Input Parameter:
884: . dm - the DM object

886:   Output Parameters:
887: + nsv - number of local shared vertices
888: - svtx - local shared vertices

890:   Notes:
891:   Cannot call this routine before DMNetworkLayoutSetup()

893:   Level: intermediate

895: .seealso: DMNetworkGetSubnetwork(), DMNetworkLayoutSetUp(), DMNetworkAddSharedVertices()
896: @*/
897: PetscErrorCode DMNetworkGetSharedVertices(DM dm,PetscInt *nsv,const PetscInt **svtx)
898: {
899:   DM_Network *net = (DM_Network*)dm->data;

902:   if (net->Nsvtx) {
903:     *nsv  = net->nsvtx;
904:     *svtx = net->svertices;
905:   } else {
906:     *nsv  = 0;
907:     *svtx = NULL;
908:   }
909:   return(0);
910: }

912: /*@C
913:   DMNetworkRegisterComponent - Registers the network component

915:   Logically collective on dm

917:   Input Parameters:
918: + dm - the network object
919: . name - the component name
920: - size - the storage size in bytes for this component data

922:    Output Parameters:
923: .  key - an integer key that defines the component

925:    Notes
926:    This routine should be called by all processors before calling DMNetworkLayoutSetup().

928:    Level: beginner

930: .seealso: DMNetworkCreate(), DMNetworkLayoutSetUp()
931: @*/
932: PetscErrorCode DMNetworkRegisterComponent(DM dm,const char *name,size_t size,PetscInt *key)
933: {
934:   PetscErrorCode        ierr;
935:   DM_Network            *network = (DM_Network*) dm->data;
936:   DMNetworkComponent    *component=NULL,*newcomponent=NULL;
937:   PetscBool             flg=PETSC_FALSE;
938:   PetscInt              i;

941:   if (!network->component) {
942:     PetscCalloc1(network->max_comps_registered,&network->component);
943:   }

945:   for (i=0; i < network->ncomponent; i++) {
946:     PetscStrcmp(network->component[i].name,name,&flg);
947:     if (flg) {
948:       *key = i;
949:       return(0);
950:     }
951:   }

953:   if (network->ncomponent == network->max_comps_registered) {
954:     /* Reached max allowed so resize component */
955:     network->max_comps_registered += 2;
956:     PetscCalloc1(network->max_comps_registered,&newcomponent);
957:     /* Copy over the previous component info */
958:     for (i=0; i < network->ncomponent; i++) {
959:       PetscStrcpy(newcomponent[i].name,network->component[i].name);
960:       newcomponent[i].size = network->component[i].size;
961:     }
962:     /* Free old one */
963:     PetscFree(network->component);
964:     /* Update pointer */
965:     network->component = newcomponent;
966:   }

968:   component = &network->component[network->ncomponent];

970:   PetscStrcpy(component->name,name);
971:   component->size = size/sizeof(DMNetworkComponentGenericDataType);
972:   *key = network->ncomponent;
973:   network->ncomponent++;
974:   return(0);
975: }

977: /*@
978:   DMNetworkGetVertexRange - Get the bounds [start, end) for the local vertices

980:   Not Collective

982:   Input Parameter:
983: . dm - the DMNetwork object

985:   Output Parameters:
986: + vStart - the first vertex point
987: - vEnd - one beyond the last vertex point

989:   Level: beginner

991: .seealso: DMNetworkGetEdgeRange()
992: @*/
993: PetscErrorCode DMNetworkGetVertexRange(DM dm,PetscInt *vStart,PetscInt *vEnd)
994: {
995:   DM_Network *network = (DM_Network*)dm->data;

998:   if (vStart) *vStart = network->vStart;
999:   if (vEnd) *vEnd = network->vEnd;
1000:   return(0);
1001: }

1003: /*@
1004:   DMNetworkGetEdgeRange - Get the bounds [start, end) for the local edges

1006:   Not Collective

1008:   Input Parameter:
1009: . dm - the DMNetwork object

1011:   Output Parameters:
1012: + eStart - The first edge point
1013: - eEnd - One beyond the last edge point

1015:   Level: beginner

1017: .seealso: DMNetworkGetVertexRange()
1018: @*/
1019: PetscErrorCode DMNetworkGetEdgeRange(DM dm,PetscInt *eStart,PetscInt *eEnd)
1020: {
1021:   DM_Network *network = (DM_Network*)dm->data;

1024:   if (eStart) *eStart = network->eStart;
1025:   if (eEnd) *eEnd = network->eEnd;
1026:   return(0);
1027: }

1029: static PetscErrorCode DMNetworkGetIndex(DM dm,PetscInt p,PetscInt *index)
1030: {
1031:   PetscErrorCode    ierr;
1032:   DM_Network        *network = (DM_Network*)dm->data;
1033:   PetscInt          offsetp;
1034:   DMNetworkComponentHeader header;

1037:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE,"Must call DMSetUp() first");
1038:   PetscSectionGetOffset(network->DataSection,p,&offsetp);
1039:   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
1040:   *index = header->index;
1041:   return(0);
1042: }

1044: /*@
1045:   DMNetworkGetGlobalEdgeIndex - Get the global numbering for the edge on the network

1047:   Not Collective

1049:   Input Parameters:
1050: + dm - DMNetwork object
1051: - p - edge point

1053:   Output Parameters:
1054: . index - the global numbering for the edge

1056:   Level: intermediate

1058: .seealso: DMNetworkGetGlobalVertexIndex()
1059: @*/
1060: PetscErrorCode DMNetworkGetGlobalEdgeIndex(DM dm,PetscInt p,PetscInt *index)
1061: {

1065:   DMNetworkGetIndex(dm,p,index);
1066:   return(0);
1067: }

1069: /*@
1070:   DMNetworkGetGlobalVertexIndex - Get the global numbering for the vertex on the network

1072:   Not Collective

1074:   Input Parameters:
1075: + dm - DMNetwork object
1076: - p  - vertex point

1078:   Output Parameters:
1079: . index - the global numbering for the vertex

1081:   Level: intermediate

1083: .seealso: DMNetworkGetGlobalEdgeIndex()
1084: @*/
1085: PetscErrorCode DMNetworkGetGlobalVertexIndex(DM dm,PetscInt p,PetscInt *index)
1086: {

1090:   DMNetworkGetIndex(dm,p,index);
1091:   return(0);
1092: }

1094: /*@
1095:   DMNetworkGetNumComponents - Get the number of components at a vertex/edge

1097:   Not Collective

1099:   Input Parameters:
1100: + dm - the DMNetwork object
1101: - p - vertex/edge point

1103:   Output Parameters:
1104: . numcomponents - Number of components at the vertex/edge

1106:   Level: beginner

1108: .seealso: DMNetworkRegisterComponent(), DMNetworkAddComponent()
1109: @*/
1110: PetscErrorCode DMNetworkGetNumComponents(DM dm,PetscInt p,PetscInt *numcomponents)
1111: {
1113:   PetscInt       offset;
1114:   DM_Network     *network = (DM_Network*)dm->data;

1117:   PetscSectionGetOffset(network->DataSection,p,&offset);
1118:   *numcomponents = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
1119:   return(0);
1120: }

1122: /*@
1123:   DMNetworkGetLocalVecOffset - Get the offset for accessing the variables associated with a component at the given vertex/edge from the local vector

1125:   Not Collective

1127:   Input Parameters:
1128: + dm - the DMNetwork object
1129: . p - the edge/vertex point
1130: - compnum - component number; use ALL_COMPONENTS if no specific component is requested

1132:   Output Parameters:
1133: . offset - the local offset

1135:   Level: intermediate

1137: .seealso: DMGetLocalVector(), DMNetworkGetComponent(), DMNetworkGetGlobalVecOffset()
1138: @*/
1139: PetscErrorCode DMNetworkGetLocalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offset)
1140: {
1142:   DM_Network     *network = (DM_Network*)dm->data;
1143:   PetscInt       offsetp,offsetd;
1144:   DMNetworkComponentHeader header;

1147:   PetscSectionGetOffset(network->plex->localSection,p,&offsetp);
1148:   if (compnum == ALL_COMPONENTS) {
1149:     *offset = offsetp;
1150:     return(0);
1151:   }

1153:   PetscSectionGetOffset(network->DataSection,p,&offsetd);
1154:   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1155:   *offset = offsetp + header->offsetvarrel[compnum];
1156:   return(0);
1157: }

1159: /*@
1160:   DMNetworkGetGlobalVecOffset - Get the global offset for accessing the variables associated with a component for the given vertex/edge from the global vector

1162:   Not Collective

1164:   Input Parameters:
1165: + dm - the DMNetwork object
1166: . p - the edge/vertex point
1167: - compnum - component number; use ALL_COMPONENTS if no specific component is requested

1169:   Output Parameters:
1170: . offsetg - the global offset

1172:   Level: intermediate

1174: .seealso: DMNetworkGetLocalVecOffset(), DMGetGlobalVector(), DMNetworkGetComponent()
1175: @*/
1176: PetscErrorCode DMNetworkGetGlobalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offsetg)
1177: {
1179:   DM_Network     *network = (DM_Network*)dm->data;
1180:   PetscInt       offsetp,offsetd;
1181:   DMNetworkComponentHeader header;

1184:   PetscSectionGetOffset(network->plex->globalSection,p,&offsetp);
1185:   if (offsetp < 0) offsetp = -(offsetp + 1); /* Convert to actual global offset for ghost vertex */

1187:   if (compnum == ALL_COMPONENTS) {
1188:     *offsetg = offsetp;
1189:     return(0);
1190:   }
1191:   PetscSectionGetOffset(network->DataSection,p,&offsetd);
1192:   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1193:   *offsetg = offsetp + header->offsetvarrel[compnum];
1194:   return(0);
1195: }

1197: /*@
1198:   DMNetworkGetEdgeOffset - Get the offset for accessing the variables associated with the given edge from the local subvector

1200:   Not Collective

1202:   Input Parameters:
1203: + dm - the DMNetwork object
1204: - p - the edge point

1206:   Output Parameters:
1207: . offset - the offset

1209:   Level: intermediate

1211: .seealso: DMNetworkGetLocalVecOffset(), DMGetLocalVector()
1212: @*/
1213: PetscErrorCode DMNetworkGetEdgeOffset(DM dm,PetscInt p,PetscInt *offset)
1214: {
1216:   DM_Network     *network = (DM_Network*)dm->data;

1219:   PetscSectionGetOffset(network->edge.DofSection,p,offset);
1220:   return(0);
1221: }

1223: /*@
1224:   DMNetworkGetVertexOffset - Get the offset for accessing the variables associated with the given vertex from the local subvector

1226:   Not Collective

1228:   Input Parameters:
1229: + dm - the DMNetwork object
1230: - p - the vertex point

1232:   Output Parameters:
1233: . offset - the offset

1235:   Level: intermediate

1237: .seealso: DMNetworkGetEdgeOffset(), DMGetLocalVector()
1238: @*/
1239: PetscErrorCode DMNetworkGetVertexOffset(DM dm,PetscInt p,PetscInt *offset)
1240: {
1242:   DM_Network     *network = (DM_Network*)dm->data;

1245:   p -= network->vStart;
1246:   PetscSectionGetOffset(network->vertex.DofSection,p,offset);
1247:   return(0);
1248: }

1250: /*@
1251:   DMNetworkAddComponent - Adds a network component and number of variables at the given point (vertex/edge)

1253:   Not Collective

1255:   Input Parameters:
1256: + dm - the DMNetwork
1257: . p - the vertex/edge point
1258: . componentkey - component key returned while registering the component; ignored if compvalue=NULL
1259: . compvalue - pointer to the data structure for the component, or NULL if not required.
1260: - nvar - number of variables for the component at the vertex/edge point

1262:   Level: beginner

1264: .seealso: DMNetworkGetComponent()
1265: @*/
1266: PetscErrorCode DMNetworkAddComponent(DM dm,PetscInt p,PetscInt componentkey,void* compvalue,PetscInt nvar)
1267: {
1268:   PetscErrorCode           ierr;
1269:   DM_Network               *network = (DM_Network*)dm->data;
1270:   DMNetworkComponent       *component = &network->component[componentkey];
1271:   DMNetworkComponentHeader header;
1272:   DMNetworkComponentValue  cvalue;
1273:   PetscBool                sharedv=PETSC_FALSE;
1274:   PetscInt                 compnum;
1275:   PetscInt                 *compsize,*compkey,*compoffset,*compnvar,*compoffsetvarrel;
1276:   void*                    *compdata;

1279:   PetscSectionAddDof(network->DofSection,p,nvar);
1280:   if (!compvalue) return(0);

1282:   DMNetworkIsSharedVertex(dm,p,&sharedv);
1283:   if (sharedv) {
1284:     PetscBool ghost;
1285:     DMNetworkIsGhostVertex(dm,p,&ghost);
1286:     if (ghost) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Adding a component at a leaf(ghost) shared vertex is not supported");
1287:   }

1289:   header = &network->header[p];
1290:   cvalue = &network->cvalue[p];
1291:   if (header->ndata == header->maxcomps) {
1292:     PetscInt additional_size;

1294:     /* Reached limit so resize header component arrays */
1295:     header->maxcomps += 2;

1297:     /* Allocate arrays for component information and value */
1298:     PetscCalloc5(header->maxcomps,&compsize,header->maxcomps,&compkey,header->maxcomps,&compoffset,header->maxcomps,&compnvar,header->maxcomps,&compoffsetvarrel);
1299:     PetscMalloc1(header->maxcomps,&compdata);

1301:     /* Recalculate header size */
1302:     header->hsize = sizeof(struct _p_DMNetworkComponentHeader) + 5*header->maxcomps*sizeof(PetscInt);

1304:     header->hsize /= sizeof(DMNetworkComponentGenericDataType);

1306:     /* Copy over component info */
1307:     PetscMemcpy(compsize,header->size,header->ndata*sizeof(PetscInt));
1308:     PetscMemcpy(compkey,header->key,header->ndata*sizeof(PetscInt));
1309:     PetscMemcpy(compoffset,header->offset,header->ndata*sizeof(PetscInt));
1310:     PetscMemcpy(compnvar,header->nvar,header->ndata*sizeof(PetscInt));
1311:     PetscMemcpy(compoffsetvarrel,header->offsetvarrel,header->ndata*sizeof(PetscInt));

1313:     /* Copy over component data pointers */
1314:     PetscMemcpy(compdata,cvalue->data,header->ndata*sizeof(void*));

1316:     /* Free old arrays */
1317:     PetscFree5(header->size,header->key,header->offset,header->nvar,header->offsetvarrel);
1318:     PetscFree(cvalue->data);

1320:     /* Update pointers */
1321:     header->size = compsize;
1322:     header->key  = compkey;
1323:     header->offset = compoffset;
1324:     header->nvar = compnvar;
1325:     header->offsetvarrel = compoffsetvarrel;

1327:     cvalue->data = compdata;

1329:     /* Update DataSection Dofs */
1330:     /* The dofs for datasection point p equals sizeof the header (i.e. header->hsize) + sizes of the components added at point p. With the resizing of the header, we need to update the dofs for point p. Hence, we add the extra size added for the header */
1331:     additional_size = (5*(header->maxcomps - header->ndata)*sizeof(PetscInt))/sizeof(DMNetworkComponentGenericDataType);
1332:     PetscSectionAddDof(network->DataSection,p,additional_size);
1333:   }
1334:   header = &network->header[p];
1335:   cvalue = &network->cvalue[p];

1337:   compnum = header->ndata;

1339:   header->size[compnum] = component->size;
1340:   PetscSectionAddDof(network->DataSection,p,component->size);
1341:   header->key[compnum] = componentkey;
1342:   if (compnum != 0) header->offset[compnum] = header->offset[compnum-1] + header->size[compnum-1];
1343:   cvalue->data[compnum] = (void*)compvalue;

1345:   /* variables */
1346:   header->nvar[compnum] += nvar;
1347:   if (compnum != 0) header->offsetvarrel[compnum] = header->offsetvarrel[compnum-1] + header->nvar[compnum-1];

1349:   header->ndata++;
1350:   return(0);
1351: }

1353: /*@
1354:   DMNetworkGetComponent - Gets the component key, the component data, and the number of variables at a given network point

1356:   Not Collective

1358:   Input Parameters:
1359: + dm - the DMNetwork object
1360: . p - vertex/edge point
1361: - compnum - component number; use ALL_COMPONENTS if sum up all the components

1363:   Output Parameters:
1364: + compkey - the key obtained when registering the component (use NULL if not required)
1365: . component - the component data (use NULL if not required)
1366: - nvar  - number of variables (use NULL if not required)

1368:   Level: beginner

1370: .seealso: DMNetworkAddComponent(), DMNetworkGetNumComponents()
1371: @*/
1372: PetscErrorCode DMNetworkGetComponent(DM dm,PetscInt p,PetscInt compnum,PetscInt *compkey,void **component,PetscInt *nvar)
1373: {
1375:   DM_Network     *network = (DM_Network*)dm->data;
1376:   PetscInt       offset = 0;
1377:   DMNetworkComponentHeader header;

1380:   if (compnum == ALL_COMPONENTS) {
1381:     PetscSectionGetDof(network->DofSection,p,nvar);
1382:     return(0);
1383:   }

1385:   PetscSectionGetOffset(network->DataSection,p,&offset);
1386:   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);

1388:   if (compnum >= 0) {
1389:     if (compkey) *compkey = header->key[compnum];
1390:     if (component) {
1391:       offset += header->hsize+header->offset[compnum];
1392:       *component = network->componentdataarray+offset;
1393:     }
1394:   }

1396:   if (nvar) *nvar = header->nvar[compnum];

1398:   return(0);
1399: }

1401: /*
1402:  Sets up the array that holds the data for all components and its associated section.
1403:  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.
1404: */
1405: PetscErrorCode DMNetworkComponentSetUp(DM dm)
1406: {
1407:   PetscErrorCode           ierr;
1408:   DM_Network               *network = (DM_Network*)dm->data;
1409:   PetscInt                 arr_size,p,offset,offsetp,ncomp,i,*headerarr;
1410:   DMNetworkComponentHeader header;
1411:   DMNetworkComponentValue  cvalue;
1412:   DMNetworkComponentHeader headerinfo;
1413:   DMNetworkComponentGenericDataType *componentdataarray;

1416:   PetscSectionSetUp(network->DataSection);
1417:   PetscSectionGetStorageSize(network->DataSection,&arr_size);
1418:   /* arr_size+1 fixes pipeline test of opensolaris-misc for src/dm/tests/ex10.c -- Do not know why */
1419:   PetscCalloc1(arr_size+1,&network->componentdataarray);
1420:   componentdataarray = network->componentdataarray;
1421:   for (p = network->pStart; p < network->pEnd; p++) {
1422:     PetscSectionGetOffset(network->DataSection,p,&offsetp);
1423:     /* Copy header */
1424:     header = &network->header[p];
1425:     headerinfo = (DMNetworkComponentHeader)(componentdataarray+offsetp);
1426:     PetscMemcpy(headerinfo,header,sizeof(struct _p_DMNetworkComponentHeader));
1427:     headerarr = (PetscInt*)(headerinfo+1);
1428:     PetscMemcpy(headerarr,header->size,header->maxcomps*sizeof(PetscInt));
1429:     headerarr += header->maxcomps;
1430:     PetscMemcpy(headerarr,header->key,header->maxcomps*sizeof(PetscInt));
1431:     headerarr += header->maxcomps;
1432:     PetscMemcpy(headerarr,header->offset,header->maxcomps*sizeof(PetscInt));
1433:     headerarr += header->maxcomps;
1434:     PetscMemcpy(headerarr,header->nvar,header->maxcomps*sizeof(PetscInt));
1435:     headerarr += header->maxcomps;
1436:     PetscMemcpy(headerarr,header->offsetvarrel,header->maxcomps*sizeof(PetscInt));

1438:     /* Copy data */
1439:     cvalue = &network->cvalue[p];
1440:     ncomp  = header->ndata;

1442:     for (i = 0; i < ncomp; i++) {
1443:       offset = offsetp + header->hsize + header->offset[i];
1444:       PetscMemcpy(componentdataarray+offset,cvalue->data[i],header->size[i]*sizeof(DMNetworkComponentGenericDataType));
1445:     }
1446:   }
1447:   return(0);
1448: }

1450: /* Sets up the section for dofs. This routine is called during DMSetUp() */
1451: static PetscErrorCode DMNetworkVariablesSetUp(DM dm)
1452: {
1454:   DM_Network     *network = (DM_Network*)dm->data;
1455:   MPI_Comm       comm;
1456:   PetscMPIInt    size;

1459:   PetscObjectGetComm((PetscObject)dm,&comm);
1460:   MPI_Comm_size(comm,&size);

1462:   if (size > 1) { /* Sync nvar at shared vertices for all processes */
1463:     PetscSF           sf = network->plex->sf;
1464:     PetscInt          *local_nvar, *remote_nvar,nroots,nleaves,p=-1,i,nsv;
1465:     const PetscInt    *svtx;
1466:     PetscBool         ghost;
1467:     /*
1468:      PetscMPIInt       rank;
1469:      const PetscInt    *ilocal;
1470:      const PetscSFNode *iremote;
1471:      MPI_Comm_rank(comm,&rank);
1472:      PetscSFGetGraph(sf,&nroots,&nleaves,&ilocal,&iremote);
1473:     */
1474:     PetscSFGetGraph(sf,&nroots,&nleaves,NULL,NULL);
1475:     PetscCalloc2(nroots,&local_nvar,nroots,&remote_nvar);

1477:     /* Leaves copy user's nvar to local_nvar */
1478:     DMNetworkGetSharedVertices(dm,&nsv,&svtx);
1479:     for (i=0; i<nsv; i++) {
1480:       p = svtx[i];
1481:       DMNetworkIsGhostVertex(dm,p,&ghost);
1482:       if (!ghost) continue;
1483:       PetscSectionGetDof(network->DofSection,p,&local_nvar[p]);
1484:       /* printf("[%d] Before SFReduce: leaf local_nvar[%d] = %d\n",rank,p,local_nvar[p]); */
1485:     }

1487:     /* Leaves add local_nvar to root remote_nvar */
1488:     PetscSFReduceBegin(sf, MPIU_INT, local_nvar, remote_nvar, MPI_SUM);
1489:     PetscSFReduceEnd(sf, MPIU_INT, local_nvar, remote_nvar, MPI_SUM);
1490:     /* printf("[%d] remote_nvar[%d] = %d\n",rank,p,remote_nvar[p]); */

1492:     /* Update roots' local_nvar */
1493:     for (i=0; i<nsv; i++) {
1494:       p = svtx[i];
1495:       DMNetworkIsGhostVertex(dm,p,&ghost);
1496:       if (ghost) continue;

1498:       PetscSectionAddDof(network->DofSection,p,remote_nvar[p]);
1499:       PetscSectionGetDof(network->DofSection,p,&local_nvar[p]);
1500:       /* printf("[%d]  After SFReduce: root local_nvar[%d] = %d\n",rank,p,local_nvar[p]); */
1501:     }

1503:     /* Roots Bcast nvar to leaves */
1504:     PetscSFBcastBegin(sf, MPIU_INT, local_nvar, remote_nvar,MPI_REPLACE);
1505:     PetscSFBcastEnd(sf, MPIU_INT, local_nvar, remote_nvar,MPI_REPLACE);

1507:     /* Leaves reset receved/remote nvar to dm */
1508:     for (i=0; i<nsv; i++) {
1509:       DMNetworkIsGhostVertex(dm,p,&ghost);
1510:       if (!ghost) continue;
1511:       p = svtx[i];
1512:       /* printf("[%d] leaf reset nvar %d at p= %d \n",rank,remote_nvar[p],p); */
1513:       /* DMNetworkSetNumVariables(dm,p,remote_nvar[p]) */
1514:       PetscSectionSetDof(network->DofSection,p,remote_nvar[p]);
1515:     }

1517:     PetscFree2(local_nvar,remote_nvar);
1518:   }

1520:   PetscSectionSetUp(network->DofSection);
1521:   return(0);
1522: }

1524: /* Get a subsection from a range of points */
1525: static PetscErrorCode DMNetworkGetSubSection_private(PetscSection main,PetscInt pstart,PetscInt pend,PetscSection *subsection)
1526: {
1528:   PetscInt       i, nvar;

1531:   PetscSectionCreate(PetscObjectComm((PetscObject)main), subsection);
1532:   PetscSectionSetChart(*subsection, 0, pend - pstart);
1533:   for (i = pstart; i < pend; i++) {
1534:     PetscSectionGetDof(main,i,&nvar);
1535:     PetscSectionSetDof(*subsection, i - pstart, nvar);
1536:   }

1538:   PetscSectionSetUp(*subsection);
1539:   return(0);
1540: }

1542: /* Create a submap of points with a GlobalToLocal structure */
1543: static PetscErrorCode DMNetworkSetSubMap_private(PetscInt pstart, PetscInt pend, ISLocalToGlobalMapping *map)
1544: {
1546:   PetscInt       i, *subpoints;

1549:   /* Create index sets to map from "points" to "subpoints" */
1550:   PetscMalloc1(pend - pstart, &subpoints);
1551:   for (i = pstart; i < pend; i++) {
1552:     subpoints[i - pstart] = i;
1553:   }
1554:   ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,pend-pstart,subpoints,PETSC_COPY_VALUES,map);
1555:   PetscFree(subpoints);
1556:   return(0);
1557: }

1559: /*@
1560:   DMNetworkAssembleGraphStructures - Assembles vertex and edge data structures. Must be called after DMNetworkDistribute

1562:   Collective on dm

1564:   Input Parameters:
1565: . dm - the DMNetworkObject

1567:   Note: the routine will create alternative orderings for the vertices and edges. Assume global network points are:

1569:   points = [0 1 2 3 4 5 6]

1571:   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]).

1573:   With this new ordering a local PetscSection, global PetscSection and PetscSF will be created specific to the subset.

1575:   Level: intermediate

1577: @*/
1578: PetscErrorCode DMNetworkAssembleGraphStructures(DM dm)
1579: {
1581:   MPI_Comm       comm;
1582:   PetscMPIInt    size;
1583:   DM_Network     *network = (DM_Network*)dm->data;

1586:   PetscObjectGetComm((PetscObject)dm,&comm);
1587:   MPI_Comm_size(comm, &size);

1589:   /* Create maps for vertices and edges */
1590:   DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);
1591:   DMNetworkSetSubMap_private(network->eStart,network->eEnd,&network->edge.mapping);

1593:   /* Create local sub-sections */
1594:   DMNetworkGetSubSection_private(network->DofSection,network->vStart,network->vEnd,&network->vertex.DofSection);
1595:   DMNetworkGetSubSection_private(network->DofSection,network->eStart,network->eEnd,&network->edge.DofSection);

1597:   if (size > 1) {
1598:     PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);

1600:     PetscSectionCreateGlobalSection(network->vertex.DofSection, network->vertex.sf, PETSC_FALSE, PETSC_FALSE, &network->vertex.GlobalDofSection);
1601:     PetscSFGetSubSF(network->plex->sf, network->edge.mapping, &network->edge.sf);
1602:     PetscSectionCreateGlobalSection(network->edge.DofSection, network->edge.sf, PETSC_FALSE, PETSC_FALSE, &network->edge.GlobalDofSection);
1603:   } else {
1604:     /* create structures for vertex */
1605:     PetscSectionClone(network->vertex.DofSection,&network->vertex.GlobalDofSection);
1606:     /* create structures for edge */
1607:     PetscSectionClone(network->edge.DofSection,&network->edge.GlobalDofSection);
1608:   }

1610:   /* Add viewers */
1611:   PetscObjectSetName((PetscObject)network->edge.GlobalDofSection,"Global edge dof section");
1612:   PetscObjectSetName((PetscObject)network->vertex.GlobalDofSection,"Global vertex dof section");
1613:   PetscSectionViewFromOptions(network->edge.GlobalDofSection, NULL, "-edge_global_section_view");
1614:   PetscSectionViewFromOptions(network->vertex.GlobalDofSection, NULL, "-vertex_global_section_view");
1615:   return(0);
1616: }

1618: /*
1619:    Add all subnetid for the input vertex v in this process to the btable
1620:    vertex_subnetid = supportingedge_subnetid
1621: */
1622: PETSC_STATIC_INLINE PetscErrorCode SetSubnetIdLookupBT(DM dm,PetscInt v,PetscInt Nsubnet,PetscBT btable)
1623: {
1625:   PetscInt       e,nedges,offset;
1626:   const PetscInt *edges;
1627:   DM_Network     *newDMnetwork = (DM_Network*)dm->data;
1628:   DMNetworkComponentHeader header;

1631:   DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);
1632:   PetscBTMemzero(Nsubnet,btable);
1633:   for (e=0; e<nedges; e++) {
1634:     PetscSectionGetOffset(newDMnetwork->DataSection,edges[e],&offset);
1635:     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1636:     PetscBTSet(btable,header->subnetid);
1637:   }
1638:   return(0);
1639: }

1641: /*@
1642:   DMNetworkDistribute - Distributes the network and moves associated component data

1644:   Collective

1646:   Input Parameters:
1647: + DM - the DMNetwork object
1648: - overlap - the overlap of partitions, 0 is the default

1650:   Options Database Key:
1651: + -dmnetwork_view - Calls DMView() at the conclusion of DMSetUp()
1652: - -dmnetwork_view_distributed - Calls DMView() at the conclusion of DMNetworkDistribute()

1654:   Notes:
1655:   Distributes the network with <overlap>-overlapping partitioning of the edges.

1657:   Level: intermediate

1659: .seealso: DMNetworkCreate()
1660: @*/
1661: PetscErrorCode DMNetworkDistribute(DM *dm,PetscInt overlap)
1662: {
1663:   MPI_Comm       comm;
1665:   PetscMPIInt    size;
1666:   DM_Network     *oldDMnetwork = (DM_Network*)((*dm)->data);
1667:   DM_Network     *newDMnetwork;
1668:   PetscSF        pointsf=NULL;
1669:   DM             newDM;
1670:   PetscInt       j,e,v,offset,*subnetvtx,*subnetedge,Nsubnet,gidx,svtx_idx,nv;
1671:   PetscInt       to_net,from_net,*svto;
1672:   PetscBT        btable;
1673:   PetscPartitioner         part;
1674:   DMNetworkComponentHeader header;

1677:   PetscObjectGetComm((PetscObject)*dm,&comm);
1678:   MPI_Comm_size(comm, &size);
1679:   if (size == 1) return(0);

1681:   if (overlap) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"overlap %D != 0 is not supported yet",overlap);

1683:   /* 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. */
1684:   DMNetworkCreate(PetscObjectComm((PetscObject)*dm),&newDM);
1685:   newDMnetwork = (DM_Network*)newDM->data;
1686:   newDMnetwork->max_comps_registered = oldDMnetwork->max_comps_registered;
1687:   PetscMalloc1(newDMnetwork->max_comps_registered,&newDMnetwork->component);

1689:   /* Enable runtime options for petscpartitioner */
1690:   DMPlexGetPartitioner(oldDMnetwork->plex,&part);
1691:   PetscPartitionerSetFromOptions(part);

1693:   /* Distribute plex dm */
1694:   DMPlexDistribute(oldDMnetwork->plex,overlap,&pointsf,&newDMnetwork->plex);

1696:   /* Distribute dof section */
1697:   PetscSectionCreate(comm,&newDMnetwork->DofSection);
1698:   PetscSFDistributeSection(pointsf,oldDMnetwork->DofSection,NULL,newDMnetwork->DofSection);

1700:   /* Distribute data and associated section */
1701:   PetscSectionCreate(comm,&newDMnetwork->DataSection);
1702:   DMPlexDistributeData(newDMnetwork->plex,pointsf,oldDMnetwork->DataSection,MPIU_INT,(void*)oldDMnetwork->componentdataarray,newDMnetwork->DataSection,(void**)&newDMnetwork->componentdataarray);

1704:   PetscSectionGetChart(newDMnetwork->DataSection,&newDMnetwork->pStart,&newDMnetwork->pEnd);
1705:   DMPlexGetHeightStratum(newDMnetwork->plex,0, &newDMnetwork->eStart,&newDMnetwork->eEnd);
1706:   DMPlexGetHeightStratum(newDMnetwork->plex,1,&newDMnetwork->vStart,&newDMnetwork->vEnd);
1707:   newDMnetwork->nEdges    = newDMnetwork->eEnd - newDMnetwork->eStart;
1708:   newDMnetwork->nVertices = newDMnetwork->vEnd - newDMnetwork->vStart;
1709:   newDMnetwork->NVertices = oldDMnetwork->NVertices;
1710:   newDMnetwork->NEdges    = oldDMnetwork->NEdges;
1711:   newDMnetwork->svtable   = oldDMnetwork->svtable; /* global table! */
1712:   oldDMnetwork->svtable   = NULL;

1714:   /* Set Dof section as the section for dm */
1715:   DMSetLocalSection(newDMnetwork->plex,newDMnetwork->DofSection);
1716:   DMGetGlobalSection(newDMnetwork->plex,&newDMnetwork->GlobalDofSection);

1718:   /* Setup subnetwork info in the newDM */
1719:   newDMnetwork->Nsubnet = oldDMnetwork->Nsubnet;
1720:   newDMnetwork->Nsvtx   = oldDMnetwork->Nsvtx;
1721:   oldDMnetwork->Nsvtx   = 0;
1722:   newDMnetwork->svtx    = oldDMnetwork->svtx; /* global vertices! */
1723:   oldDMnetwork->svtx    = NULL;
1724:   PetscCalloc1(newDMnetwork->Nsubnet,&newDMnetwork->subnet);

1726:   /* Copy over the global number of vertices and edges in each subnetwork.
1727:      Note: these are calculated in DMNetworkLayoutSetUp()
1728:   */
1729:   Nsubnet = newDMnetwork->Nsubnet;
1730:   for (j = 0; j < Nsubnet; j++) {
1731:     newDMnetwork->subnet[j].Nvtx  = oldDMnetwork->subnet[j].Nvtx;
1732:     newDMnetwork->subnet[j].Nedge = oldDMnetwork->subnet[j].Nedge;
1733:   }

1735:   /* Count local nedges for subnetworks */
1736:   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1737:     PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);
1738:     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1739:     /* Update pointers */
1740:     header->size          = (PetscInt*)(header + 1);
1741:     header->key           = header->size   + header->maxcomps;
1742:     header->offset        = header->key    + header->maxcomps;
1743:     header->nvar          = header->offset + header->maxcomps;
1744:     header->offsetvarrel  = header->nvar   + header->maxcomps;

1746:     newDMnetwork->subnet[header->subnetid].nedge++;
1747:   }

1749:   /* Count local nvtx for subnetworks */
1750:   PetscBTCreate(Nsubnet,&btable);
1751:   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1752:     PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);
1753:     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1754:     /* Update pointers */
1755:     header->size          = (PetscInt*)(header + 1);
1756:     header->key           = header->size   + header->maxcomps;
1757:     header->offset        = header->key    + header->maxcomps;
1758:     header->nvar          = header->offset + header->maxcomps;
1759:     header->offsetvarrel  = header->nvar   + header->maxcomps;

1761:     /* shared vertices: use gidx=header->index to check if v is a shared vertex */
1762:     gidx = header->index;
1763:     PetscTableFind(newDMnetwork->svtable,gidx+1,&svtx_idx);
1764:     svtx_idx--;

1766:     if (svtx_idx < 0) { /* not a shared vertex */
1767:       newDMnetwork->subnet[header->subnetid].nvtx++;
1768:     } else { /* a shared vertex belongs to more than one subnetworks, it is being counted by multiple subnets */
1769:       SetSubnetIdLookupBT(newDM,v,Nsubnet,btable);

1771:       from_net = newDMnetwork->svtx[svtx_idx].sv[0];
1772:       if (PetscBTLookup(btable,from_net)) newDMnetwork->subnet[from_net].nvtx++; /* sv is on from_net */

1774:       for (j=1; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1775:         svto   = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1776:         to_net = svto[0];
1777:         if (PetscBTLookup(btable,to_net)) newDMnetwork->subnet[to_net].nvtx++; /* sv is on to_net */
1778:       }
1779:     }
1780:   }

1782:   /* Get total local nvtx for subnetworks */
1783:   nv = 0;
1784:   for (j=0; j<Nsubnet; j++) nv += newDMnetwork->subnet[j].nvtx;
1785:   nv += newDMnetwork->Nsvtx;

1787:   /* Now create the vertices and edge arrays for the subnetworks */
1788:   PetscCalloc2(newDMnetwork->nEdges,&subnetedge,nv,&subnetvtx); /* Maps local vertex to local subnetwork's vertex */
1789:   newDMnetwork->subnetedge = subnetedge;
1790:   newDMnetwork->subnetvtx  = subnetvtx;
1791:   for (j=0; j < newDMnetwork->Nsubnet; j++) {
1792:     newDMnetwork->subnet[j].edges = subnetedge;
1793:     subnetedge                   += newDMnetwork->subnet[j].nedge;

1795:     newDMnetwork->subnet[j].vertices = subnetvtx;
1796:     subnetvtx                       += newDMnetwork->subnet[j].nvtx;

1798:     /* 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. */
1799:     newDMnetwork->subnet[j].nvtx = newDMnetwork->subnet[j].nedge = 0;
1800:   }
1801:   newDMnetwork->svertices = subnetvtx;

1803:   /* Set the edges and vertices in each subnetwork */
1804:   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1805:     PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);
1806:     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1807:     newDMnetwork->subnet[header->subnetid].edges[newDMnetwork->subnet[header->subnetid].nedge++] = e;
1808:   }

1810:   nv = 0;
1811:   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1812:     PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);
1813:     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);

1815:     /* coupling vertices: use gidx = header->index to check if v is a coupling vertex */
1816:     PetscTableFind(newDMnetwork->svtable,header->index+1,&svtx_idx);
1817:     svtx_idx--;
1818:     if (svtx_idx < 0) {
1819:       newDMnetwork->subnet[header->subnetid].vertices[newDMnetwork->subnet[header->subnetid].nvtx++] = v;
1820:     } else { /* a shared vertex */
1821:       newDMnetwork->svertices[nv++] = v;

1823:       /* add all subnetid for this shared vertex in this process to btable */
1824:       SetSubnetIdLookupBT(newDM,v,Nsubnet,btable);

1826:       from_net = newDMnetwork->svtx[svtx_idx].sv[0];
1827:       if (PetscBTLookup(btable,from_net))
1828:         newDMnetwork->subnet[from_net].vertices[newDMnetwork->subnet[from_net].nvtx++] = v;

1830:       for (j=1; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1831:         svto   = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1832:         to_net = svto[0];
1833:         if (PetscBTLookup(btable,to_net))
1834:           newDMnetwork->subnet[to_net].vertices[newDMnetwork->subnet[to_net].nvtx++] = v;
1835:       }
1836:     }
1837:   }
1838:   newDMnetwork->nsvtx = nv;   /* num of local shared vertices */

1840:   newDM->setupcalled = (*dm)->setupcalled;
1841:   newDMnetwork->distributecalled = PETSC_TRUE;

1843:   /* Free spaces */
1844:   PetscSFDestroy(&pointsf);
1845:   DMDestroy(dm);
1846:   PetscBTDestroy(&btable);

1848:   /* View distributed dmnetwork */
1849:   DMViewFromOptions(newDM,NULL,"-dmnetwork_view_distributed");

1851:   *dm  = newDM;
1852:   return(0);
1853: }

1855: /*@C
1856:   PetscSFGetSubSF - Returns an SF for a specific subset of points. Leaves are re-numbered to reflect the new ordering

1858:  Collective

1860:   Input Parameters:
1861: + mainSF - the original SF structure
1862: - map - a ISLocalToGlobal mapping that contains the subset of points

1864:   Output Parameter:
1865: . subSF - a subset of the mainSF for the desired subset.

1867:   Level: intermediate
1868: @*/
1869: PetscErrorCode PetscSFGetSubSF(PetscSF mainsf,ISLocalToGlobalMapping map,PetscSF *subSF)
1870: {
1871:   PetscErrorCode        ierr;
1872:   PetscInt              nroots, nleaves, *ilocal_sub;
1873:   PetscInt              i, *ilocal_map, nroots_sub, nleaves_sub = 0;
1874:   PetscInt              *local_points, *remote_points;
1875:   PetscSFNode           *iremote_sub;
1876:   const PetscInt        *ilocal;
1877:   const PetscSFNode     *iremote;

1880:   PetscSFGetGraph(mainsf,&nroots,&nleaves,&ilocal,&iremote);

1882:   /* Look for leaves that pertain to the subset of points. Get the local ordering */
1883:   PetscMalloc1(nleaves,&ilocal_map);
1884:   ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nleaves,ilocal,NULL,ilocal_map);
1885:   for (i = 0; i < nleaves; i++) {
1886:     if (ilocal_map[i] != -1) nleaves_sub += 1;
1887:   }
1888:   /* Re-number ilocal with subset numbering. Need information from roots */
1889:   PetscMalloc2(nroots,&local_points,nroots,&remote_points);
1890:   for (i = 0; i < nroots; i++) local_points[i] = i;
1891:   ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nroots,local_points,NULL,local_points);
1892:   PetscSFBcastBegin(mainsf, MPIU_INT, local_points, remote_points,MPI_REPLACE);
1893:   PetscSFBcastEnd(mainsf, MPIU_INT, local_points, remote_points,MPI_REPLACE);
1894:   /* Fill up graph using local (that is, local to the subset) numbering. */
1895:   PetscMalloc1(nleaves_sub,&ilocal_sub);
1896:   PetscMalloc1(nleaves_sub,&iremote_sub);
1897:   nleaves_sub = 0;
1898:   for (i = 0; i < nleaves; i++) {
1899:     if (ilocal_map[i] != -1) {
1900:       ilocal_sub[nleaves_sub] = ilocal_map[i];
1901:       iremote_sub[nleaves_sub].rank = iremote[i].rank;
1902:       iremote_sub[nleaves_sub].index = remote_points[ilocal[i]];
1903:       nleaves_sub += 1;
1904:     }
1905:   }
1906:   PetscFree2(local_points,remote_points);
1907:   ISLocalToGlobalMappingGetSize(map,&nroots_sub);

1909:   /* Create new subSF */
1910:   PetscSFCreate(PETSC_COMM_WORLD,subSF);
1911:   PetscSFSetFromOptions(*subSF);
1912:   PetscSFSetGraph(*subSF,nroots_sub,nleaves_sub,ilocal_sub,PETSC_OWN_POINTER,iremote_sub,PETSC_COPY_VALUES);
1913:   PetscFree(ilocal_map);
1914:   PetscFree(iremote_sub);
1915:   return(0);
1916: }

1918: /*@C
1919:   DMNetworkGetSupportingEdges - Return the supporting edges for this vertex point

1921:   Not Collective

1923:   Input Parameters:
1924: + dm - the DMNetwork object
1925: - p  - the vertex point

1927:   Output Parameters:
1928: + nedges - number of edges connected to this vertex point
1929: - edges  - list of edge points

1931:   Level: beginner

1933:   Fortran Notes:
1934:   Since it returns an array, this routine is only available in Fortran 90, and you must
1935:   include petsc.h90 in your code.

1937: .seealso: DMNetworkCreate(), DMNetworkGetConnectedVertices()
1938: @*/
1939: PetscErrorCode DMNetworkGetSupportingEdges(DM dm,PetscInt vertex,PetscInt *nedges,const PetscInt *edges[])
1940: {
1942:   DM_Network     *network = (DM_Network*)dm->data;

1945:   DMPlexGetSupportSize(network->plex,vertex,nedges);
1946:   if (edges) {DMPlexGetSupport(network->plex,vertex,edges);}
1947:   return(0);
1948: }

1950: /*@C
1951:   DMNetworkGetConnectedVertices - Return the connected vertices for this edge point

1953:   Not Collective

1955:   Input Parameters:
1956: + dm - the DMNetwork object
1957: - p - the edge point

1959:   Output Parameters:
1960: . vertices - vertices connected to this edge

1962:   Level: beginner

1964:   Fortran Notes:
1965:   Since it returns an array, this routine is only available in Fortran 90, and you must
1966:   include petsc.h90 in your code.

1968: .seealso: DMNetworkCreate(), DMNetworkGetSupportingEdges()
1969: @*/
1970: PetscErrorCode DMNetworkGetConnectedVertices(DM dm,PetscInt edge,const PetscInt *vertices[])
1971: {
1973:   DM_Network     *network = (DM_Network*)dm->data;

1976:   DMPlexGetCone(network->plex,edge,vertices);
1977:   return(0);
1978: }

1980: /*@
1981:   DMNetworkIsSharedVertex - Returns TRUE if the vertex is shared by subnetworks

1983:   Not Collective

1985:   Input Parameters:
1986: + dm - the DMNetwork object
1987: - p - the vertex point

1989:   Output Parameter:
1990: . flag - TRUE if the vertex is shared by subnetworks

1992:   Level: beginner

1994: .seealso: DMNetworkAddSharedVertices(), DMNetworkIsGhostVertex()
1995: @*/
1996: PetscErrorCode DMNetworkIsSharedVertex(DM dm,PetscInt p,PetscBool *flag)
1997: {
1999:   PetscInt       i;

2002:   *flag = PETSC_FALSE;

2004:   if (dm->setupcalled) { /* DMNetworkGetGlobalVertexIndex() requires DMSetUp() be called */
2005:     DM_Network     *network = (DM_Network*)dm->data;
2006:     PetscInt       gidx;
2007:     DMNetworkGetGlobalVertexIndex(dm,p,&gidx);
2008:     PetscTableFind(network->svtable,gidx+1,&i);
2009:     if (i) *flag = PETSC_TRUE;
2010:   } else { /* would be removed? */
2011:     PetscInt       nv;
2012:     const PetscInt *vtx;
2013:     DMNetworkGetSharedVertices(dm,&nv,&vtx);
2014:     for (i=0; i<nv; i++) {
2015:       if (p == vtx[i]) {
2016:         *flag = PETSC_TRUE;
2017:         break;
2018:       }
2019:     }
2020:   }
2021:   return(0);
2022: }

2024: /*@
2025:   DMNetworkIsGhostVertex - Returns TRUE if the vertex is a ghost vertex

2027:   Not Collective

2029:   Input Parameters:
2030: + dm - the DMNetwork object
2031: - p - the vertex point

2033:   Output Parameter:
2034: . isghost - TRUE if the vertex is a ghost point

2036:   Level: beginner

2038: .seealso: DMNetworkGetConnectedVertices(), DMNetworkGetVertexRange(), DMNetworkIsSharedVertex()
2039: @*/
2040: PetscErrorCode DMNetworkIsGhostVertex(DM dm,PetscInt p,PetscBool *isghost)
2041: {
2043:   DM_Network     *network = (DM_Network*)dm->data;
2044:   PetscInt       offsetg;
2045:   PetscSection   sectiong;

2048:   *isghost = PETSC_FALSE;
2049:   DMGetGlobalSection(network->plex,&sectiong);
2050:   PetscSectionGetOffset(sectiong,p,&offsetg);
2051:   if (offsetg < 0) *isghost = PETSC_TRUE;
2052:   return(0);
2053: }

2055: PetscErrorCode DMSetUp_Network(DM dm)
2056: {
2058:   DM_Network     *network=(DM_Network*)dm->data;

2061:   DMNetworkComponentSetUp(dm);
2062:   DMNetworkVariablesSetUp(dm);

2064:   DMSetLocalSection(network->plex,network->DofSection);
2065:   DMGetGlobalSection(network->plex,&network->GlobalDofSection);

2067:   dm->setupcalled = PETSC_TRUE;

2069:   /* View dmnetwork */
2070:   DMViewFromOptions(dm,NULL,"-dmnetwork_view");
2071:   return(0);
2072: }

2074: /*@
2075:   DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
2076:       -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?

2078:   Collective

2080:   Input Parameters:
2081: + dm - the DMNetwork object
2082: . eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
2083: - vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices

2085:  Level: intermediate

2087: @*/
2088: PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
2089: {
2090:   DM_Network     *network=(DM_Network*)dm->data;
2092:   PetscInt       nVertices = network->nVertices;

2095:   network->userEdgeJacobian   = eflg;
2096:   network->userVertexJacobian = vflg;

2098:   if (eflg && !network->Je) {
2099:     PetscCalloc1(3*network->nEdges,&network->Je);
2100:   }

2102:   if (vflg && !network->Jv && nVertices) {
2103:     PetscInt       i,*vptr,nedges,vStart=network->vStart;
2104:     PetscInt       nedges_total;
2105:     const PetscInt *edges;

2107:     /* count nvertex_total */
2108:     nedges_total = 0;
2109:     PetscMalloc1(nVertices+1,&vptr);

2111:     vptr[0] = 0;
2112:     for (i=0; i<nVertices; i++) {
2113:       DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);
2114:       nedges_total += nedges;
2115:       vptr[i+1] = vptr[i] + 2*nedges + 1;
2116:     }

2118:     PetscCalloc1(2*nedges_total+nVertices,&network->Jv);
2119:     network->Jvptr = vptr;
2120:   }
2121:   return(0);
2122: }

2124: /*@
2125:   DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network

2127:   Not Collective

2129:   Input Parameters:
2130: + dm - the DMNetwork object
2131: . p - the edge point
2132: - J - array (size = 3) of Jacobian submatrices for this edge point:
2133:         J[0]: this edge
2134:         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()

2136:   Level: advanced

2138: .seealso: DMNetworkVertexSetMatrix()
2139: @*/
2140: PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
2141: {
2142:   DM_Network *network=(DM_Network*)dm->data;

2145:   if (!network->Je) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");

2147:   if (J) {
2148:     network->Je[3*p]   = J[0];
2149:     network->Je[3*p+1] = J[1];
2150:     network->Je[3*p+2] = J[2];
2151:   }
2152:   return(0);
2153: }

2155: /*@
2156:   DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network

2158:   Not Collective

2160:   Input Parameters:
2161: + dm - The DMNetwork object
2162: . p - the vertex point
2163: - J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
2164:         J[0]:       this vertex
2165:         J[1+2*i]:   i-th supporting edge
2166:         J[1+2*i+1]: i-th connected vertex

2168:   Level: advanced

2170: .seealso: DMNetworkEdgeSetMatrix()
2171: @*/
2172: PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
2173: {
2175:   DM_Network     *network=(DM_Network*)dm->data;
2176:   PetscInt       i,*vptr,nedges,vStart=network->vStart;
2177:   const PetscInt *edges;

2180:   if (!network->Jv) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");

2182:   if (J) {
2183:     vptr = network->Jvptr;
2184:     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */

2186:     /* Set Jacobian for each supporting edge and connected vertex */
2187:     DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);
2188:     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
2189:   }
2190:   return(0);
2191: }

2193: PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2194: {
2196:   PetscInt       j;
2197:   PetscScalar    val=(PetscScalar)ncols;

2200:   if (!ghost) {
2201:     for (j=0; j<nrows; j++) {
2202:       VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);
2203:     }
2204:   } else {
2205:     for (j=0; j<nrows; j++) {
2206:       VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);
2207:     }
2208:   }
2209:   return(0);
2210: }

2212: PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2213: {
2215:   PetscInt       j,ncols_u;
2216:   PetscScalar    val;

2219:   if (!ghost) {
2220:     for (j=0; j<nrows; j++) {
2221:       MatGetRow(Ju,j,&ncols_u,NULL,NULL);
2222:       val = (PetscScalar)ncols_u;
2223:       VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);
2224:       MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);
2225:     }
2226:   } else {
2227:     for (j=0; j<nrows; j++) {
2228:       MatGetRow(Ju,j,&ncols_u,NULL,NULL);
2229:       val = (PetscScalar)ncols_u;
2230:       VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);
2231:       MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);
2232:     }
2233:   }
2234:   return(0);
2235: }

2237: PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2238: {

2242:   if (Ju) {
2243:     MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);
2244:   } else {
2245:     MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);
2246:   }
2247:   return(0);
2248: }

2250: PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2251: {
2253:   PetscInt       j,*cols;
2254:   PetscScalar    *zeros;

2257:   PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);
2258:   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
2259:   MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);
2260:   PetscFree2(cols,zeros);
2261:   return(0);
2262: }

2264: PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2265: {
2267:   PetscInt       j,M,N,row,col,ncols_u;
2268:   const PetscInt *cols;
2269:   PetscScalar    zero=0.0;

2272:   MatGetSize(Ju,&M,&N);
2273:   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);

2275:   for (row=0; row<nrows; row++) {
2276:     MatGetRow(Ju,row,&ncols_u,&cols,NULL);
2277:     for (j=0; j<ncols_u; j++) {
2278:       col = cols[j] + cstart;
2279:       MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);
2280:     }
2281:     MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);
2282:   }
2283:   return(0);
2284: }

2286: PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2287: {

2291:   if (Ju) {
2292:     MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);
2293:   } else {
2294:     MatSetDenseblock_private(nrows,rows,ncols,cstart,J);
2295:   }
2296:   return(0);
2297: }

2299: /* 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.
2300: */
2301: PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
2302: {
2304:   PetscInt       i,size,dof;
2305:   PetscInt       *glob2loc;

2308:   PetscSectionGetStorageSize(localsec,&size);
2309:   PetscMalloc1(size,&glob2loc);

2311:   for (i = 0; i < size; i++) {
2312:     PetscSectionGetOffset(globalsec,i,&dof);
2313:     dof = (dof >= 0) ? dof : -(dof + 1);
2314:     glob2loc[i] = dof;
2315:   }

2317:   ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);
2318: #if 0
2319:   PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);
2320: #endif
2321:   return(0);
2322: }

2324: #include <petsc/private/matimpl.h>

2326: PetscErrorCode DMCreateMatrix_Network_Nest(DM dm,Mat *J)
2327: {
2329:   DM_Network     *network = (DM_Network*)dm->data;
2330:   PetscInt       eDof,vDof;
2331:   Mat            j11,j12,j21,j22,bA[2][2];
2332:   MPI_Comm       comm;
2333:   ISLocalToGlobalMapping eISMap,vISMap;

2336:   PetscObjectGetComm((PetscObject)dm,&comm);

2338:   PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);
2339:   PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);

2341:   MatCreate(comm, &j11);
2342:   MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);
2343:   MatSetType(j11, MATMPIAIJ);

2345:   MatCreate(comm, &j12);
2346:   MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);
2347:   MatSetType(j12, MATMPIAIJ);

2349:   MatCreate(comm, &j21);
2350:   MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);
2351:   MatSetType(j21, MATMPIAIJ);

2353:   MatCreate(comm, &j22);
2354:   MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);
2355:   MatSetType(j22, MATMPIAIJ);

2357:   bA[0][0] = j11;
2358:   bA[0][1] = j12;
2359:   bA[1][0] = j21;
2360:   bA[1][1] = j22;

2362:   CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);
2363:   CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);

2365:   MatSetLocalToGlobalMapping(j11,eISMap,eISMap);
2366:   MatSetLocalToGlobalMapping(j12,eISMap,vISMap);
2367:   MatSetLocalToGlobalMapping(j21,vISMap,eISMap);
2368:   MatSetLocalToGlobalMapping(j22,vISMap,vISMap);

2370:   MatSetUp(j11);
2371:   MatSetUp(j12);
2372:   MatSetUp(j21);
2373:   MatSetUp(j22);

2375:   MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);
2376:   MatSetUp(*J);
2377:   MatNestSetVecType(*J,VECNEST);
2378:   MatDestroy(&j11);
2379:   MatDestroy(&j12);
2380:   MatDestroy(&j21);
2381:   MatDestroy(&j22);

2383:   MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
2384:   MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
2385:   MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);

2387:   /* Free structures */
2388:   ISLocalToGlobalMappingDestroy(&eISMap);
2389:   ISLocalToGlobalMappingDestroy(&vISMap);
2390:   return(0);
2391: }

2393: PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
2394: {
2396:   DM_Network     *network = (DM_Network*)dm->data;
2397:   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
2398:   PetscInt       cstart,ncols,j,e,v;
2399:   PetscBool      ghost,ghost_vc,ghost2,isNest;
2400:   Mat            Juser;
2401:   PetscSection   sectionGlobal;
2402:   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
2403:   const PetscInt *edges,*cone;
2404:   MPI_Comm       comm;
2405:   MatType        mtype;
2406:   Vec            vd_nz,vo_nz;
2407:   PetscInt       *dnnz,*onnz;
2408:   PetscScalar    *vdnz,*vonz;

2411:   mtype = dm->mattype;
2412:   PetscStrcmp(mtype,MATNEST,&isNest);
2413:   if (isNest) {
2414:     DMCreateMatrix_Network_Nest(dm,J);
2415:     MatSetDM(*J,dm);
2416:     return(0);
2417:   }

2419:   if (!network->userEdgeJacobian && !network->userVertexJacobian) {
2420:     /* user does not provide Jacobian blocks */
2421:     DMCreateMatrix_Plex(network->plex,J);
2422:     MatSetDM(*J,dm);
2423:     return(0);
2424:   }

2426:   MatCreate(PetscObjectComm((PetscObject)dm),J);
2427:   DMGetGlobalSection(network->plex,&sectionGlobal);
2428:   PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);
2429:   MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);

2431:   MatSetType(*J,MATAIJ);
2432:   MatSetFromOptions(*J);

2434:   /* (1) Set matrix preallocation */
2435:   /*------------------------------*/
2436:   PetscObjectGetComm((PetscObject)dm,&comm);
2437:   VecCreate(comm,&vd_nz);
2438:   VecSetSizes(vd_nz,localSize,PETSC_DECIDE);
2439:   VecSetFromOptions(vd_nz);
2440:   VecSet(vd_nz,0.0);
2441:   VecDuplicate(vd_nz,&vo_nz);

2443:   /* Set preallocation for edges */
2444:   /*-----------------------------*/
2445:   DMNetworkGetEdgeRange(dm,&eStart,&eEnd);

2447:   PetscMalloc1(localSize,&rows);
2448:   for (e=eStart; e<eEnd; e++) {
2449:     /* Get row indices */
2450:     DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart);
2451:     PetscSectionGetDof(network->DofSection,e,&nrows);
2452:     if (nrows) {
2453:       for (j=0; j<nrows; j++) rows[j] = j + rstart;

2455:       /* Set preallocation for connected vertices */
2456:       DMNetworkGetConnectedVertices(dm,e,&cone);
2457:       for (v=0; v<2; v++) {
2458:         PetscSectionGetDof(network->DofSection,cone[v],&ncols);

2460:         if (network->Je) {
2461:           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2462:         } else Juser = NULL;
2463:         DMNetworkIsGhostVertex(dm,cone[v],&ghost);
2464:         MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);
2465:       }

2467:       /* Set preallocation for edge self */
2468:       cstart = rstart;
2469:       if (network->Je) {
2470:         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2471:       } else Juser = NULL;
2472:       MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);
2473:     }
2474:   }

2476:   /* Set preallocation for vertices */
2477:   /*--------------------------------*/
2478:   DMNetworkGetVertexRange(dm,&vStart,&vEnd);
2479:   if (vEnd - vStart) vptr = network->Jvptr;

2481:   for (v=vStart; v<vEnd; v++) {
2482:     /* Get row indices */
2483:     DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart);
2484:     PetscSectionGetDof(network->DofSection,v,&nrows);
2485:     if (!nrows) continue;

2487:     DMNetworkIsGhostVertex(dm,v,&ghost);
2488:     if (ghost) {
2489:       PetscMalloc1(nrows,&rows_v);
2490:     } else {
2491:       rows_v = rows;
2492:     }

2494:     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;

2496:     /* Get supporting edges and connected vertices */
2497:     DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);

2499:     for (e=0; e<nedges; e++) {
2500:       /* Supporting edges */
2501:       DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart);
2502:       PetscSectionGetDof(network->DofSection,edges[e],&ncols);

2504:       if (network->Jv) {
2505:         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2506:       } else Juser = NULL;
2507:       MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);

2509:       /* Connected vertices */
2510:       DMNetworkGetConnectedVertices(dm,edges[e],&cone);
2511:       vc = (v == cone[0]) ? cone[1]:cone[0];
2512:       DMNetworkIsGhostVertex(dm,vc,&ghost_vc);

2514:       PetscSectionGetDof(network->DofSection,vc,&ncols);

2516:       if (network->Jv) {
2517:         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2518:       } else Juser = NULL;
2519:       if (ghost_vc||ghost) {
2520:         ghost2 = PETSC_TRUE;
2521:       } else {
2522:         ghost2 = PETSC_FALSE;
2523:       }
2524:       MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);
2525:     }

2527:     /* Set preallocation for vertex self */
2528:     DMNetworkIsGhostVertex(dm,v,&ghost);
2529:     if (!ghost) {
2530:       DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart);
2531:       if (network->Jv) {
2532:         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2533:       } else Juser = NULL;
2534:       MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);
2535:     }
2536:     if (ghost) {
2537:       PetscFree(rows_v);
2538:     }
2539:   }

2541:   VecAssemblyBegin(vd_nz);
2542:   VecAssemblyBegin(vo_nz);

2544:   PetscMalloc2(localSize,&dnnz,localSize,&onnz);

2546:   VecAssemblyEnd(vd_nz);
2547:   VecAssemblyEnd(vo_nz);

2549:   VecGetArray(vd_nz,&vdnz);
2550:   VecGetArray(vo_nz,&vonz);
2551:   for (j=0; j<localSize; j++) {
2552:     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
2553:     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
2554:   }
2555:   VecRestoreArray(vd_nz,&vdnz);
2556:   VecRestoreArray(vo_nz,&vonz);
2557:   VecDestroy(&vd_nz);
2558:   VecDestroy(&vo_nz);

2560:   MatSeqAIJSetPreallocation(*J,0,dnnz);
2561:   MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);
2562:   MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);

2564:   PetscFree2(dnnz,onnz);

2566:   /* (2) Set matrix entries for edges */
2567:   /*----------------------------------*/
2568:   for (e=eStart; e<eEnd; e++) {
2569:     /* Get row indices */
2570:     DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart);
2571:     PetscSectionGetDof(network->DofSection,e,&nrows);
2572:     if (nrows) {
2573:       for (j=0; j<nrows; j++) rows[j] = j + rstart;

2575:       /* Set matrix entries for connected vertices */
2576:       DMNetworkGetConnectedVertices(dm,e,&cone);
2577:       for (v=0; v<2; v++) {
2578:         DMNetworkGetGlobalVecOffset(dm,cone[v],ALL_COMPONENTS,&cstart);
2579:         PetscSectionGetDof(network->DofSection,cone[v],&ncols);

2581:         if (network->Je) {
2582:           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2583:         } else Juser = NULL;
2584:         MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);
2585:       }

2587:       /* Set matrix entries for edge self */
2588:       cstart = rstart;
2589:       if (network->Je) {
2590:         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2591:       } else Juser = NULL;
2592:       MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);
2593:     }
2594:   }

2596:   /* Set matrix entries for vertices */
2597:   /*---------------------------------*/
2598:   for (v=vStart; v<vEnd; v++) {
2599:     /* Get row indices */
2600:     DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart);
2601:     PetscSectionGetDof(network->DofSection,v,&nrows);
2602:     if (!nrows) continue;

2604:     DMNetworkIsGhostVertex(dm,v,&ghost);
2605:     if (ghost) {
2606:       PetscMalloc1(nrows,&rows_v);
2607:     } else {
2608:       rows_v = rows;
2609:     }
2610:     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;

2612:     /* Get supporting edges and connected vertices */
2613:     DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);

2615:     for (e=0; e<nedges; e++) {
2616:       /* Supporting edges */
2617:       DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart);
2618:       PetscSectionGetDof(network->DofSection,edges[e],&ncols);

2620:       if (network->Jv) {
2621:         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2622:       } else Juser = NULL;
2623:       MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);

2625:       /* Connected vertices */
2626:       DMNetworkGetConnectedVertices(dm,edges[e],&cone);
2627:       vc = (v == cone[0]) ? cone[1]:cone[0];

2629:       DMNetworkGetGlobalVecOffset(dm,vc,ALL_COMPONENTS,&cstart);
2630:       PetscSectionGetDof(network->DofSection,vc,&ncols);

2632:       if (network->Jv) {
2633:         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2634:       } else Juser = NULL;
2635:       MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);
2636:     }

2638:     /* Set matrix entries for vertex self */
2639:     if (!ghost) {
2640:       DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart);
2641:       if (network->Jv) {
2642:         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2643:       } else Juser = NULL;
2644:       MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);
2645:     }
2646:     if (ghost) {
2647:       PetscFree(rows_v);
2648:     }
2649:   }
2650:   PetscFree(rows);

2652:   MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
2653:   MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);

2655:   MatSetDM(*J,dm);
2656:   return(0);
2657: }

2659: PetscErrorCode DMDestroy_Network(DM dm)
2660: {
2662:   DM_Network     *network = (DM_Network*)dm->data;
2663:   PetscInt       j,np;

2666:   if (--network->refct > 0) return(0);
2667:   if (network->Je) {
2668:     PetscFree(network->Je);
2669:   }
2670:   if (network->Jv) {
2671:     PetscFree(network->Jvptr);
2672:     PetscFree(network->Jv);
2673:   }

2675:   ISLocalToGlobalMappingDestroy(&network->vertex.mapping);
2676:   PetscSectionDestroy(&network->vertex.DofSection);
2677:   PetscSectionDestroy(&network->vertex.GlobalDofSection);
2678:   if (network->vltog) {
2679:     PetscFree(network->vltog);
2680:   }
2681:   if (network->vertex.sf) {
2682:     PetscSFDestroy(&network->vertex.sf);
2683:   }
2684:   /* edge */
2685:   ISLocalToGlobalMappingDestroy(&network->edge.mapping);
2686:   PetscSectionDestroy(&network->edge.DofSection);
2687:   PetscSectionDestroy(&network->edge.GlobalDofSection);
2688:   if (network->edge.sf) {
2689:     PetscSFDestroy(&network->edge.sf);
2690:   }
2691:   DMDestroy(&network->plex);
2692:   PetscSectionDestroy(&network->DataSection);
2693:   PetscSectionDestroy(&network->DofSection);

2695:   for (j=0; j<network->Nsvtx; j++) {
2696:     PetscFree(network->svtx[j].sv);
2697:   }
2698:   if (network->svtx) {PetscFree(network->svtx);}
2699:   PetscFree2(network->subnetedge,network->subnetvtx);

2701:   PetscTableDestroy(&network->svtable);
2702:   PetscFree(network->subnet);
2703:   PetscFree(network->component);
2704:   PetscFree(network->componentdataarray);

2706:   if (network->header) {
2707:     np = network->pEnd - network->pStart;
2708:     for (j=0; j < np; j++) {
2709:       PetscFree5(network->header[j].size,network->header[j].key,network->header[j].offset,network->header[j].nvar,network->header[j].offsetvarrel);
2710:       PetscFree(network->cvalue[j].data);
2711:     }
2712:     PetscFree2(network->header,network->cvalue);
2713:   }
2714:   PetscFree(network);
2715:   return(0);
2716: }

2718: PetscErrorCode DMView_Network(DM dm,PetscViewer viewer)
2719: {
2721:   PetscBool      iascii;
2722:   PetscMPIInt    rank;

2725:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE,"Must call DMSetUp() first");
2726:   MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);
2729:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
2730:   if (iascii) {
2731:     const PetscInt *cone,*vtx,*edges;
2732:     PetscInt       vfrom,vto,i,j,nv,ne,ncv,p,nsubnet;
2733:     DM_Network     *network = (DM_Network*)dm->data;

2735:     nsubnet = network->Nsubnet; /* num of subnetworks */
2736:     if (rank == 0) {
2737:       PetscPrintf(PETSC_COMM_SELF,"  NSubnets: %D; NEdges: %D; NVertices: %D; NSharedVertices: %D.\n",nsubnet,network->NEdges,network->NVertices,network->Nsvtx);
2738:     }

2740:     DMNetworkGetSharedVertices(dm,&ncv,&vtx);
2741:     PetscViewerASCIIPushSynchronized(viewer);
2742:     PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nEdges: %D; nVertices: %D; nSharedVertices: %D\n",rank,network->nEdges,network->nVertices,ncv);

2744:     for (i=0; i<nsubnet; i++) {
2745:       DMNetworkGetSubnetwork(dm,i,&nv,&ne,&vtx,&edges);
2746:       if (ne) {
2747:         PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %D: nEdges %D, nVertices(include shared vertices) %D\n",i,ne,nv);
2748:         for (j=0; j<ne; j++) {
2749:           p = edges[j];
2750:           DMNetworkGetConnectedVertices(dm,p,&cone);
2751:           DMNetworkGetGlobalVertexIndex(dm,cone[0],&vfrom);
2752:           DMNetworkGetGlobalVertexIndex(dm,cone[1],&vto);
2753:           DMNetworkGetGlobalEdgeIndex(dm,edges[j],&p);
2754:           PetscViewerASCIISynchronizedPrintf(viewer, "       edge %D: %D ----> %D\n",p,vfrom,vto);
2755:         }
2756:       }
2757:     }

2759:     /* Shared vertices */
2760:     DMNetworkGetSharedVertices(dm,&ncv,&vtx);
2761:     if (ncv) {
2762:       SVtx       *svtx = network->svtx;
2763:       PetscInt    gidx,svtx_idx,nvto,vfrom_net,vfrom_idx,*svto;
2764:       PetscBool   ghost;
2765:       PetscViewerASCIISynchronizedPrintf(viewer, "     SharedVertices:\n");
2766:       for (i=0; i<ncv; i++) {
2767:         DMNetworkIsGhostVertex(dm,vtx[i],&ghost);
2768:         if (ghost) continue;

2770:         DMNetworkGetGlobalVertexIndex(dm,vtx[i],&gidx);
2771:         PetscTableFind(network->svtable,gidx+1,&svtx_idx);
2772:         svtx_idx--;
2773:         nvto = svtx[svtx_idx].n;

2775:         vfrom_net = svtx[svtx_idx].sv[0];
2776:         vfrom_idx = svtx[svtx_idx].sv[1];
2777:         PetscViewerASCIISynchronizedPrintf(viewer, "       svtx %D: global index %D, subnet[%D].%D ---->\n",i,gidx,vfrom_net,vfrom_idx);
2778:         for (j=1; j<nvto; j++) {
2779:           svto = svtx[svtx_idx].sv + 2*j;
2780:           PetscViewerASCIISynchronizedPrintf(viewer, "                                           ----> subnet[%D].%D\n",svto[0],svto[1]);
2781:         }
2782:       }
2783:     }
2784:     PetscViewerFlush(viewer);
2785:     PetscViewerASCIIPopSynchronized(viewer);
2786:   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMNetwork writing", ((PetscObject)viewer)->type_name);
2787:   return(0);
2788: }

2790: PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
2791: {
2793:   DM_Network     *network = (DM_Network*)dm->data;

2796:   DMGlobalToLocalBegin(network->plex,g,mode,l);
2797:   return(0);
2798: }

2800: PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
2801: {
2803:   DM_Network     *network = (DM_Network*)dm->data;

2806:   DMGlobalToLocalEnd(network->plex,g,mode,l);
2807:   return(0);
2808: }

2810: PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
2811: {
2813:   DM_Network     *network = (DM_Network*)dm->data;

2816:   DMLocalToGlobalBegin(network->plex,l,mode,g);
2817:   return(0);
2818: }

2820: PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
2821: {
2823:   DM_Network     *network = (DM_Network*)dm->data;

2826:   DMLocalToGlobalEnd(network->plex,l,mode,g);
2827:   return(0);
2828: }

2830: /*@
2831:   DMNetworkGetVertexLocalToGlobalOrdering - Get vertex global index

2833:   Not collective

2835:   Input Parameters:
2836: + dm - the dm object
2837: - vloc - local vertex ordering, start from 0

2839:   Output Parameters:
2840: .  vg  - global vertex ordering, start from 0

2842:   Level: advanced

2844: .seealso: DMNetworkSetVertexLocalToGlobalOrdering()
2845: @*/
2846: PetscErrorCode DMNetworkGetVertexLocalToGlobalOrdering(DM dm,PetscInt vloc,PetscInt *vg)
2847: {
2848:   DM_Network  *network = (DM_Network*)dm->data;
2849:   PetscInt    *vltog = network->vltog;

2852:   if (!vltog) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkSetVertexLocalToGlobalOrdering() first");
2853:   *vg = vltog[vloc];
2854:   return(0);
2855: }

2857: /*@
2858:   DMNetworkSetVertexLocalToGlobalOrdering - Create and setup vertex local to global map

2860:   Collective

2862:   Input Parameters:
2863: . dm - the dm object

2865:   Level: advanced

2867: .seealso: DMNetworkGetGlobalVertexIndex()
2868: @*/
2869: PetscErrorCode DMNetworkSetVertexLocalToGlobalOrdering(DM dm)
2870: {
2871:   PetscErrorCode    ierr;
2872:   DM_Network        *network=(DM_Network*)dm->data;
2873:   MPI_Comm          comm;
2874:   PetscMPIInt       rank,size,*displs=NULL,*recvcounts=NULL,remoterank;
2875:   PetscBool         ghost;
2876:   PetscInt          *vltog,nroots,nleaves,i,*vrange,k,N,lidx;
2877:   const PetscSFNode *iremote;
2878:   PetscSF           vsf;
2879:   Vec               Vleaves,Vleaves_seq;
2880:   VecScatter        ctx;
2881:   PetscScalar       *varr,val;
2882:   const PetscScalar *varr_read;

2885:   PetscObjectGetComm((PetscObject)dm,&comm);
2886:   MPI_Comm_size(comm,&size);
2887:   MPI_Comm_rank(comm,&rank);

2889:   if (size == 1) {
2890:     nroots = network->vEnd - network->vStart;
2891:     PetscMalloc1(nroots, &vltog);
2892:     for (i=0; i<nroots; i++) vltog[i] = i;
2893:     network->vltog = vltog;
2894:     return(0);
2895:   }

2897:   if (!network->distributecalled) SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkDistribute() first");
2898:   if (network->vltog) {
2899:     PetscFree(network->vltog);
2900:   }

2902:   DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);
2903:   PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);
2904:   vsf = network->vertex.sf;

2906:   PetscMalloc3(size+1,&vrange,size,&displs,size,&recvcounts);
2907:   PetscSFGetGraph(vsf,&nroots,&nleaves,NULL,&iremote);

2909:   for (i=0; i<size; i++) { displs[i] = i; recvcounts[i] = 1;}

2911:   i         = nroots - nleaves; /* local number of vertices, excluding ghosts */
2912:   vrange[0] = 0;
2913:   MPI_Allgatherv(&i,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm);
2914:   for (i=2; i<size+1; i++) {vrange[i] += vrange[i-1];}

2916:   PetscMalloc1(nroots, &vltog);
2917:   network->vltog = vltog;

2919:   /* Set vltog for non-ghost vertices */
2920:   k = 0;
2921:   for (i=0; i<nroots; i++) {
2922:     DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost);
2923:     if (ghost) continue;
2924:     vltog[i] = vrange[rank] + k++;
2925:   }
2926:   PetscFree3(vrange,displs,recvcounts);

2928:   /* Set vltog for ghost vertices */
2929:   /* (a) create parallel Vleaves and sequential Vleaves_seq to convert local iremote[*].index to global index */
2930:   VecCreate(comm,&Vleaves);
2931:   VecSetSizes(Vleaves,2*nleaves,PETSC_DETERMINE);
2932:   VecSetFromOptions(Vleaves);
2933:   VecGetArray(Vleaves,&varr);
2934:   for (i=0; i<nleaves; i++) {
2935:     varr[2*i]   = (PetscScalar)(iremote[i].rank);  /* rank of remote process */
2936:     varr[2*i+1] = (PetscScalar)(iremote[i].index); /* local index in remote process */
2937:   }
2938:   VecRestoreArray(Vleaves,&varr);

2940:   /* (b) scatter local info to remote processes via VecScatter() */
2941:   VecScatterCreateToAll(Vleaves,&ctx,&Vleaves_seq);
2942:   VecScatterBegin(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD);
2943:   VecScatterEnd(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD);

2945:   /* (c) convert local indices to global indices in parallel vector Vleaves */
2946:   VecGetSize(Vleaves_seq,&N);
2947:   VecGetArrayRead(Vleaves_seq,&varr_read);
2948:   for (i=0; i<N; i+=2) {
2949:     remoterank = (PetscMPIInt)PetscRealPart(varr_read[i]);
2950:     if (remoterank == rank) {
2951:       k = i+1; /* row number */
2952:       lidx = (PetscInt)PetscRealPart(varr_read[i+1]);
2953:       val  = (PetscScalar)vltog[lidx]; /* global index for non-ghost vertex computed above */
2954:       VecSetValues(Vleaves,1,&k,&val,INSERT_VALUES);
2955:     }
2956:   }
2957:   VecRestoreArrayRead(Vleaves_seq,&varr_read);
2958:   VecAssemblyBegin(Vleaves);
2959:   VecAssemblyEnd(Vleaves);

2961:   /* (d) Set vltog for ghost vertices by copying local values of Vleaves */
2962:   VecGetArrayRead(Vleaves,&varr_read);
2963:   k = 0;
2964:   for (i=0; i<nroots; i++) {
2965:     DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost);
2966:     if (!ghost) continue;
2967:     vltog[i] = (PetscInt)PetscRealPart(varr_read[2*k+1]); k++;
2968:   }
2969:   VecRestoreArrayRead(Vleaves,&varr_read);

2971:   VecDestroy(&Vleaves);
2972:   VecDestroy(&Vleaves_seq);
2973:   VecScatterDestroy(&ctx);
2974:   return(0);
2975: }

2977: PETSC_STATIC_INLINE PetscErrorCode DMISAddSize_private(DM_Network *network,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *nidx)
2978: {
2979:   PetscErrorCode           ierr;
2980:   PetscInt                 i,j,ncomps,nvar,key,offset=0;
2981:   DMNetworkComponentHeader header;

2984:   PetscSectionGetOffset(network->DataSection,p,&offset);
2985:   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
2986:   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);

2988:   for (i=0; i<ncomps; i++) {
2989:     key  = header->key[i];
2990:     nvar = header->nvar[i];
2991:     for (j=0; j<numkeys; j++) {
2992:       if (key == keys[j]) {
2993:         if (!blocksize || blocksize[j] == -1) {
2994:           *nidx += nvar;
2995:         } else {
2996:           *nidx += nselectedvar[j]*nvar/blocksize[j];
2997:         }
2998:       }
2999:     }
3000:   }
3001:   return(0);
3002: }

3004: PETSC_STATIC_INLINE PetscErrorCode DMISComputeIdx_private(DM dm,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],PetscInt *ii,PetscInt *idx)
3005: {
3006:   PetscErrorCode           ierr;
3007:   PetscInt                 i,j,ncomps,nvar,key,offsetg,k,k1,offset=0;
3008:   DM_Network               *network = (DM_Network*)dm->data;
3009:   DMNetworkComponentHeader header;

3012:   PetscSectionGetOffset(network->DataSection,p,&offset);
3013:   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
3014:   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);

3016:   for (i=0; i<ncomps; i++) {
3017:     key  = header->key[i];
3018:     nvar = header->nvar[i];
3019:     for (j=0; j<numkeys; j++) {
3020:       if (key != keys[j]) continue;

3022:       DMNetworkGetGlobalVecOffset(dm,p,i,&offsetg);
3023:       if (!blocksize || blocksize[j] == -1) {
3024:         for (k=0; k<nvar; k++) idx[(*ii)++] = offsetg + k;
3025:       } else {
3026:         for (k=0; k<nvar; k+=blocksize[j]) {
3027:           for (k1=0; k1<nselectedvar[j]; k1++) idx[(*ii)++] = offsetg + k + selectedvar[j][k1];
3028:         }
3029:       }
3030:     }
3031:   }
3032:   return(0);
3033: }

3035: /*@
3036:   DMNetworkCreateIS - Create an index set object from the global vector of the network

3038:   Collective

3040:   Input Parameters:
3041: + dm - DMNetwork object
3042: . numkeys - number of keys
3043: . keys - array of keys that define the components of the variables you wish to extract
3044: . blocksize - block size of the variables associated to the component
3045: . nselectedvar - number of variables in each block to select
3046: - selectedvar - the offset into the block of each variable in each block to select

3048:   Output Parameters:
3049: . is - the index set

3051:   Level: Advanced

3053:   Notes:
3054:     Use blocksize[i] of -1 to indicate select all the variables of the i-th component, for which nselectvar[i] and selectedvar[i] are ignored. Use NULL, NULL, NULL to indicate for all selected components one wishes to obtain all the values of that component. For example, DMNetworkCreateIS(dm,1,&key,NULL,NULL,NULL,&is) will return an is that extracts all the variables for the 0-th component.

3056: .seealso: DMNetworkCreate(), ISCreateGeneral(), DMNetworkCreateLocalIS()
3057: @*/
3058: PetscErrorCode DMNetworkCreateIS(DM dm,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],IS *is)
3059: {
3061:   MPI_Comm       comm;
3062:   DM_Network     *network = (DM_Network*)dm->data;
3063:   PetscInt       i,p,estart,eend,vstart,vend,nidx,*idx;
3064:   PetscBool      ghost;

3067:   PetscObjectGetComm((PetscObject)dm,&comm);

3069:   /* Check input parameters */
3070:   for (i=0; i<numkeys; i++) {
3071:     if (!blocksize || blocksize[i] == -1) continue;
3072:     if (nselectedvar[i] > blocksize[i]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"number of selectedvariables %D cannot be larger than blocksize %D",nselectedvar[i],blocksize[i]);
3073:   }

3075:   DMNetworkGetEdgeRange(dm,&estart,&eend);
3076:   DMNetworkGetVertexRange(dm,&vstart,&vend);

3078:   /* Get local number of idx */
3079:   nidx = 0;
3080:   for (p=estart; p<eend; p++) {
3081:     DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx);
3082:   }
3083:   for (p=vstart; p<vend; p++) {
3084:     DMNetworkIsGhostVertex(dm,p,&ghost);
3085:     if (ghost) continue;
3086:     DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx);
3087:   }

3089:   /* Compute idx */
3090:   PetscMalloc1(nidx,&idx);
3091:   i = 0;
3092:   for (p=estart; p<eend; p++) {
3093:     DMISComputeIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx);
3094:   }
3095:   for (p=vstart; p<vend; p++) {
3096:     DMNetworkIsGhostVertex(dm,p,&ghost);
3097:     if (ghost) continue;
3098:     DMISComputeIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx);
3099:   }

3101:   /* Create is */
3102:   ISCreateGeneral(comm,nidx,idx,PETSC_COPY_VALUES,is);
3103:   PetscFree(idx);
3104:   return(0);
3105: }

3107: PETSC_STATIC_INLINE PetscErrorCode DMISComputeLocalIdx_private(DM dm,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],PetscInt *ii,PetscInt *idx)
3108: {
3109:   PetscErrorCode           ierr;
3110:   PetscInt                 i,j,ncomps,nvar,key,offsetl,k,k1,offset=0;
3111:   DM_Network               *network = (DM_Network*)dm->data;
3112:   DMNetworkComponentHeader header;

3115:   PetscSectionGetOffset(network->DataSection,p,&offset);
3116:   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
3117:   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);

3119:   for (i=0; i<ncomps; i++) {
3120:     key  = header->key[i];
3121:     nvar = header->nvar[i];
3122:     for (j=0; j<numkeys; j++) {
3123:       if (key != keys[j]) continue;

3125:       DMNetworkGetLocalVecOffset(dm,p,i,&offsetl);
3126:       if (!blocksize || blocksize[j] == -1) {
3127:         for (k=0; k<nvar; k++) idx[(*ii)++] = offsetl + k;
3128:       } else {
3129:         for (k=0; k<nvar; k+=blocksize[j]) {
3130:           for (k1=0; k1<nselectedvar[j]; k1++) idx[(*ii)++] = offsetl + k + selectedvar[j][k1];
3131:         }
3132:       }
3133:     }
3134:   }
3135:   return(0);
3136: }

3138: /*@
3139:   DMNetworkCreateLocalIS - Create an index set object from the local vector of the network

3141:   Not collective

3143:   Input Parameters:
3144: + dm - DMNetwork object
3145: . numkeys - number of keys
3146: . keys - array of keys that define the components of the variables you wish to extract
3147: . blocksize - block size of the variables associated to the component
3148: . nselectedvar - number of variables in each block to select
3149: - selectedvar - the offset into the block of each variable in each block to select

3151:   Output Parameters:
3152: . is - the index set

3154:   Level: Advanced

3156:   Notes:
3157:     Use blocksize[i] of -1 to indicate select all the variables of the i-th component, for which nselectvar[i] and selectedvar[i] are ignored. Use NULL, NULL, NULL to indicate for all selected components one wishes to obtain all the values of that component. For example, DMNetworkCreateLocalIS(dm,1,&key,NULL,NULL,NULL,&is) will return an is that extracts all the variables for the 0-th component.

3159: .seealso: DMNetworkCreate(), DMNetworkCreateIS, ISCreateGeneral()
3160: @*/
3161: PetscErrorCode DMNetworkCreateLocalIS(DM dm,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],IS *is)
3162: {
3164:   DM_Network     *network = (DM_Network*)dm->data;
3165:   PetscInt       i,p,pstart,pend,nidx,*idx;

3168:   /* Check input parameters */
3169:   for (i=0; i<numkeys; i++) {
3170:     if (!blocksize || blocksize[i] == -1) continue;
3171:     if (nselectedvar[i] > blocksize[i]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"number of selectedvariables %D cannot be larger than blocksize %D",nselectedvar[i],blocksize[i]);
3172:   }

3174:   pstart = network->pStart;
3175:   pend   = network->pEnd;

3177:   /* Get local number of idx */
3178:   nidx = 0;
3179:   for (p=pstart; p<pend; p++) {
3180:     DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx);
3181:   }

3183:   /* Compute local idx */
3184:   PetscMalloc1(nidx,&idx);
3185:   i = 0;
3186:   for (p=pstart; p<pend; p++) {
3187:     DMISComputeLocalIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx);
3188:   }

3190:   /* Create is */
3191:   ISCreateGeneral(PETSC_COMM_SELF,nidx,idx,PETSC_COPY_VALUES,is);
3192:   PetscFree(idx);
3193:   return(0);
3194: }