xref: /petsc/src/dm/impls/network/networkview.c (revision 375d23e45bc7f27f90f326da17aaea364b3bd8d3)
1 #include <petscconf.h>
2 // We need to define this ahead of any other includes to make sure mkstemp is actually defined
3 #if defined(PETSC_HAVE_MKSTEMP)
4   #if !defined(_XOPEN_SOURCE)
5     #define _XOPEN_SOURCE 600
6   #endif
7 #endif
8 #include "petsc/private/petscimpl.h"
9 #include "petscerror.h"
10 #include "petscis.h"
11 #include "petscstring.h"
12 #include "petscsys.h"
13 #include "petscsystypes.h"
14 #include <petsc/private/dmnetworkimpl.h> /*I  "petscdmnetwork.h"  I*/
15 #include <petscdraw.h>
16 
17 static PetscErrorCode DMView_Network_CSV(DM dm, PetscViewer viewer)
18 {
19   DM              dmcoords;
20   PetscInt        nsubnets, i, subnet, nvertices, nedges, vertex, edge, gidx, ncomp;
21   PetscInt        vertexOffsets[2], globalEdgeVertices[2];
22   PetscScalar     vertexCoords[2], *color_ptr, color;
23   const PetscInt *vertices, *edges, *edgeVertices;
24   Vec             allVertexCoords;
25   PetscMPIInt     rank;
26   MPI_Comm        comm;
27 
28   PetscFunctionBegin;
29   // Get the coordinate information from dmcoords
30   PetscCheck(dm->coordinates[0].dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "CoordinateDM not created");
31   PetscCall(DMGetCoordinateDM(dm, &dmcoords));
32 
33   PetscCall(DMGetCoordinateDim(dmcoords, &i));
34   PetscCheck(i == 2, PETSC_COMM_WORLD, PETSC_ERR_SUP, "dim %" PetscInt_FMT " != 2 is not supported yet", i);
35 
36   // Get the coordinate vector from dm
37   PetscCall(DMGetCoordinatesLocal(dm, &allVertexCoords));
38 
39   // Get the MPI communicator and this process' rank
40   PetscCall(PetscObjectGetComm((PetscObject)dmcoords, &comm));
41   PetscCallMPI(MPI_Comm_rank(comm, &rank));
42 
43   // Start synchronized printing
44   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
45 
46   // Write the header
47   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Type,Rank,ID,X,Y,Z,Name,Color\n"));
48 
49   // Iterate each subnetwork (Note: We need to get the global number of subnets apparently)
50   PetscCall(DMNetworkGetNumSubNetworks(dmcoords, NULL, &nsubnets));
51   for (subnet = 0; subnet < nsubnets; subnet++) {
52     // Get the subnetwork's vertices and edges
53     PetscCall(DMNetworkGetSubnetwork(dmcoords, subnet, &nvertices, &nedges, &vertices, &edges));
54 
55     // Write out each vertex
56     for (i = 0; i < nvertices; i++) {
57       vertex = vertices[i];
58 
59       // Get the offset into the coordinate vector for the vertex
60       PetscCall(DMNetworkGetLocalVecOffset(dmcoords, vertex, ALL_COMPONENTS, vertexOffsets));
61       vertexOffsets[1] = vertexOffsets[0] + 1;
62       // Remap vertex to the global value
63       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, vertex, &gidx));
64       // Get the vertex position from the coordinate vector
65       PetscCall(VecGetValues(allVertexCoords, 2, vertexOffsets, vertexCoords));
66 
67       // Get vertex color; TODO: name
68       PetscCall(DMNetworkGetNumComponents(dmcoords, vertex, &ncomp));
69       PetscCheck(ncomp <= 1, PETSC_COMM_WORLD, PETSC_ERR_SUP, "num of components %" PetscInt_FMT " must be <= 1", ncomp);
70       color = 0.0;
71       if (ncomp == 1) {
72         PetscCall(DMNetworkGetComponent(dmcoords, vertex, 0, NULL, (void **)&color_ptr, NULL));
73         color = *color_ptr;
74       }
75       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Node,%" PetscInt_FMT ",%" PetscInt_FMT ",%lf,%lf,0,%" PetscInt_FMT ",%lf\n", (PetscInt)rank, gidx, (double)PetscRealPart(vertexCoords[0]), (double)PetscRealPart(vertexCoords[1]), gidx, (double)PetscRealPart(color)));
76     }
77 
78     // Write out each edge
79     for (i = 0; i < nedges; i++) {
80       edge = edges[i];
81       PetscCall(DMNetworkGetConnectedVertices(dmcoords, edge, &edgeVertices));
82       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, edgeVertices[0], &globalEdgeVertices[0]));
83       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, edgeVertices[1], &globalEdgeVertices[1]));
84       PetscCall(DMNetworkGetGlobalEdgeIndex(dmcoords, edge, &edge));
85 
86       // TODO: Determine edge color/name
87       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Edge,%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",0,%" PetscInt_FMT "\n", (PetscInt)rank, edge, globalEdgeVertices[0], globalEdgeVertices[1], edge));
88     }
89   }
90   // End synchronized printing
91   PetscCall(PetscViewerFlush(viewer));
92   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
93   PetscFunctionReturn(PETSC_SUCCESS);
94 }
95 
96 static PetscErrorCode DMView_Network_Matplotlib(DM dm, PetscViewer viewer)
97 {
98   PetscMPIInt rank, size;
99   MPI_Comm    comm;
100   char        filename[PETSC_MAX_PATH_LEN + 1], options[512], proccall[PETSC_MAX_PATH_LEN + 512], scriptFile[PETSC_MAX_PATH_LEN + 1], buffer[256], buffer2[256];
101   PetscViewer csvViewer;
102   FILE       *processFile = NULL;
103   PetscBool   isnull, optionShowRanks = PETSC_FALSE, optionRankIsSet = PETSC_FALSE, showNoNodes = PETSC_FALSE, showNoNumbering = PETSC_FALSE, optionShowVertices = PETSC_FALSE, optionViewPadding = PETSC_FALSE;
104   PetscDraw   draw;
105   DM_Network *network = (DM_Network *)dm->data;
106   PetscReal   drawPause, viewPadding = 1.0;
107   PetscInt    i;
108 #if defined(PETSC_HAVE_MKSTEMP)
109   PetscBool isSharedTmp;
110 #endif
111 
112   PetscFunctionBegin;
113   // Deal with the PetscDraw we are given
114   PetscCall(PetscViewerDrawGetDraw(viewer, 1, &draw));
115   PetscCall(PetscDrawIsNull(draw, &isnull));
116   PetscCall(PetscDrawSetVisible(draw, PETSC_FALSE));
117 
118   // Clear the file name buffer so all communicated bytes are well-defined
119   PetscCall(PetscMemzero(filename, sizeof(filename)));
120 
121   // Get the MPI communicator and this process' rank
122   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
123   PetscCallMPI(MPI_Comm_rank(comm, &rank));
124   PetscCallMPI(MPI_Comm_size(comm, &size));
125 
126 #if defined(PETSC_HAVE_MKSTEMP)
127   // Get if the temporary directory is shared
128   // Note: This must be done collectively on every rank, it cannot be done on a single rank
129   PetscCall(PetscSharedTmp(comm, &isSharedTmp));
130 #endif
131 
132   /* Process Options */
133   optionShowRanks = network->vieweroptions.showallranks;
134   showNoNodes     = network->vieweroptions.shownovertices;
135   showNoNumbering = network->vieweroptions.shownonumbering;
136 
137   /*
138     TODO:  if the option -dmnetwork_view_tmpdir can be moved up here that would be good as well.
139   */
140   PetscOptionsBegin(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->prefix, "MatPlotLib PetscViewer DMNetwork Options", "PetscViewer");
141   PetscCall(PetscOptionsBool("-dmnetwork_view_all_ranks", "View all ranks in the DMNetwork", NULL, optionShowRanks, &optionShowRanks, NULL));
142   PetscCall(PetscOptionsString("-dmnetwork_view_rank_range", "Set of ranks to view the DMNetwork on", NULL, buffer, buffer, sizeof(buffer), &optionRankIsSet));
143   PetscCall(PetscOptionsBool("-dmnetwork_view_no_vertices", "Do not view vertices", NULL, showNoNodes, &showNoNodes, NULL));
144   PetscCall(PetscOptionsBool("-dmnetwork_view_no_numbering", "Do not view edge and vertex numbering", NULL, showNoNumbering, &showNoNumbering, NULL));
145   PetscCall(PetscOptionsString("-dmnetwork_view_zoomin_vertices", "Focus the view on the given set of vertices", NULL, buffer2, buffer2, sizeof(buffer2), &optionShowVertices));
146   PetscCall(PetscOptionsReal("-dmnetwork_view_zoomin_vertices_padding", "Set the padding when viewing specific vertices", NULL, viewPadding, &viewPadding, &optionViewPadding));
147   PetscOptionsEnd();
148 
149   // Generate and broadcast the temporary file name from rank 0
150   if (rank == 0) {
151 #if defined(PETSC_HAVE_TMPNAM_S)
152     // Acquire a temporary file to write to and open an ASCII/CSV viewer
153     PetscCheck(tmpnam_s(filename, sizeof(filename)) == 0, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
154 #elif defined(PETSC_HAVE_MKSTEMP)
155     PetscBool isTmpOverridden;
156     size_t    numChars;
157     // Same thing, but for POSIX systems on which tmpnam is deprecated
158     // Note: Configure may detect mkstemp but it will not be defined if compiling for C99, so check additional defines to see if we can use it
159     // Mkstemp requires us to explicitly specify part of the path, but some systems may not like putting files in /tmp/ so have an option for it
160     PetscCall(PetscOptionsGetString(NULL, NULL, "-dmnetwork_view_tmpdir", filename, sizeof(filename), &isTmpOverridden));
161     // If not specified by option try using a shared tmp on the system
162     if (!isTmpOverridden) {
163       // Validate that if tmp is not overridden it is at least shared
164       PetscCheck(isSharedTmp, comm, PETSC_ERR_SUP_SYS, "Temporary file directory is not shared between ranks, try using -dmnetwork_view_tmpdir to specify a shared directory");
165       PetscCall(PetscGetTmp(PETSC_COMM_SELF, filename, sizeof(filename)));
166     }
167     // Make sure the filename ends with a '/'
168     PetscCall(PetscStrlen(filename, &numChars));
169     if (filename[numChars - 1] != '/') {
170       filename[numChars]     = '/';
171       filename[numChars + 1] = 0;
172     }
173     // Perform the actual temporary file creation
174     PetscCall(PetscStrlcat(filename, "XXXXXX", sizeof(filename)));
175     PetscCheck(mkstemp(filename) != -1, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
176 #else
177     // Same thing, but for older C versions which don't have the safe form
178     PetscCheck(tmpnam(filename) != NULL, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
179 #endif
180   }
181 
182   // Broadcast the filename to all other MPI ranks
183   PetscCallMPI(MPI_Bcast(filename, PETSC_MAX_PATH_LEN, MPI_BYTE, 0, comm));
184 
185   PetscCall(PetscViewerASCIIOpen(comm, filename, &csvViewer));
186   PetscCall(PetscViewerPushFormat(csvViewer, PETSC_VIEWER_ASCII_CSV));
187 
188   // Use the CSV viewer to write out the local network
189   PetscCall(DMView_Network_CSV(dm, csvViewer));
190 
191   // Close the viewer
192   PetscCall(PetscViewerDestroy(&csvViewer));
193 
194   // Generate options string
195   PetscCall(PetscMemzero(options, sizeof(options)));
196   // If the draw is null run as a "test execute" ie. do nothing just test that the script was called correctly
197   PetscCall(PetscStrlcat(options, isnull ? " -tx " : " ", sizeof(options)));
198   PetscCall(PetscDrawGetPause(draw, &drawPause));
199   if (drawPause > 0) {
200     char pausebuffer[64];
201     PetscCall(PetscSNPrintf(pausebuffer, sizeof(pausebuffer), "%f", (double)drawPause));
202     PetscCall(PetscStrlcat(options, " -dt ", sizeof(options)));
203     PetscCall(PetscStrlcat(options, pausebuffer, sizeof(options)));
204   }
205   if (optionShowRanks || optionRankIsSet) {
206     // Show all ranks only if the option is set in code or by the user AND not showing specific ranks AND there is more than one process
207     if (optionShowRanks && !optionRankIsSet && size != 1) PetscCall(PetscStrlcat(options, " -dar ", sizeof(options)));
208     // Do not show the global plot if the user requests it OR if one specific rank is requested
209     if (network->vieweroptions.dontshowglobal || optionRankIsSet) PetscCall(PetscStrlcat(options, " -ncp ", sizeof(options)));
210 
211     if (optionRankIsSet) {
212       // If a range of ranks to draw is specified append it
213       PetscCall(PetscStrlcat(options, " -drr ", sizeof(options)));
214       PetscCall(PetscStrlcat(options, buffer, sizeof(options)));
215     } else {
216       // Otherwise, use the options provided in code
217       if (network->vieweroptions.viewranks) {
218         const PetscInt *viewranks;
219         PetscInt        viewrankssize;
220         char            rankbuffer[64];
221         PetscCall(ISGetTotalIndices(network->vieweroptions.viewranks, &viewranks));
222         PetscCall(ISGetSize(network->vieweroptions.viewranks, &viewrankssize));
223         PetscCall(PetscStrlcat(options, " -drr ", sizeof(options)));
224         for (i = 0; i < viewrankssize; i++) {
225           PetscCall(PetscSNPrintf(rankbuffer, sizeof(rankbuffer), "%" PetscInt_FMT, viewranks[i]));
226           PetscCall(PetscStrlcat(options, rankbuffer, sizeof(options)));
227         }
228         PetscCall(ISRestoreTotalIndices(network->vieweroptions.viewranks, &viewranks));
229       } // if not provided an IS of viewing ranks, skip viewing
230     }
231   }
232   if (optionShowVertices) {
233     // Pass vertices to focus on if defined
234     PetscCall(PetscStrlcat(options, " -vsv ", sizeof(options)));
235     PetscCall(PetscStrlcat(options, buffer2, sizeof(options)));
236     optionViewPadding = PETSC_TRUE;
237     // Pass padding if set
238     if (optionViewPadding) {
239       PetscCall(PetscSNPrintf(buffer2, sizeof(buffer2), "%f", (double)viewPadding));
240       PetscCall(PetscStrlcat(options, " -vp ", sizeof(options)));
241       PetscCall(PetscStrlcat(options, buffer2, sizeof(options)));
242     }
243   }
244 
245   // Check for options for visibility...
246   if (showNoNodes) PetscCall(PetscStrlcat(options, " -nn ", sizeof(options)));
247   if (showNoNumbering) PetscCall(PetscStrlcat(options, " -nnl -nel ", sizeof(options)));
248 
249   // Get the value of $PETSC_DIR
250   PetscCall(PetscStrreplace(comm, "${PETSC_DIR}/share/petsc/bin/dmnetwork_view.py", scriptFile, sizeof(scriptFile)));
251   PetscCall(PetscFixFilename(scriptFile, scriptFile));
252   // Generate the system call for 'python3 $PETSC_DIR/share/petsc/dmnetwork_view.py <options> <file>'
253   PetscCall(PetscArrayzero(proccall, sizeof(proccall)));
254   PetscCall(PetscSNPrintf(proccall, sizeof(proccall), "%s %s %s %s", PETSC_PYTHON_EXE, scriptFile, options, filename));
255 
256 #if defined(PETSC_HAVE_POPEN)
257   // Perform the call to run the python script (Note: while this is called on all ranks POpen will only run on rank 0)
258   PetscCall(PetscPOpen(comm, NULL, proccall, "r", &processFile));
259   if (processFile != NULL) {
260     while (fgets(buffer, sizeof(buffer), processFile) != NULL) PetscCall(PetscPrintf(comm, "%s", buffer));
261   }
262   PetscCall(PetscPClose(comm, processFile));
263 #else
264   // Same thing, but using the standard library for systems that don't have POpen/PClose (only run on rank 0)
265   if (rank == 0) PetscCheck(system(proccall) == 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Failed to call viewer script");
266   // Barrier so that all ranks wait until the call completes
267   PetscCallMPI(MPI_Barrier(comm));
268 #endif
269   // Clean up the temporary file we used using rank 0
270   if (rank == 0) PetscCheck(remove(filename) == 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Failed to delete temporary file");
271   PetscFunctionReturn(PETSC_SUCCESS);
272 }
273 
274 PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
275 {
276   PetscBool         iascii, isdraw;
277   PetscViewerFormat format;
278 
279   PetscFunctionBegin;
280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
281   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
282   PetscCall(PetscViewerGetFormat(viewer, &format));
283 
284   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
285   if (isdraw) {
286     PetscCall(DMView_Network_Matplotlib(dm, viewer));
287     PetscFunctionReturn(PETSC_SUCCESS);
288   }
289 
290   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
291   if (iascii) {
292     const PetscInt *cone, *vtx, *edges;
293     PetscInt        vfrom, vto, i, j, nv, ne, nsv, p, nsubnet;
294     DM_Network     *network = (DM_Network *)dm->data;
295     PetscMPIInt     rank;
296 
297     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
298     if (format == PETSC_VIEWER_ASCII_CSV) {
299       PetscCall(DMView_Network_CSV(dm, viewer));
300       PetscFunctionReturn(PETSC_SUCCESS);
301     }
302 
303     nsubnet = network->cloneshared->Nsubnet; /* num of subnetworks */
304     if (!rank) {
305       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  NSubnets: %" PetscInt_FMT "; NEdges: %" PetscInt_FMT "; NVertices: %" PetscInt_FMT "; NSharedVertices: %" PetscInt_FMT ".\n", nsubnet, network->cloneshared->NEdges, network->cloneshared->NVertices,
306                             network->cloneshared->Nsvtx));
307     }
308 
309     PetscCall(DMNetworkGetSharedVertices(dm, &nsv, NULL));
310     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
311     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nEdges: %" PetscInt_FMT "; nVertices: %" PetscInt_FMT "; nSharedVertices: %" PetscInt_FMT "\n", rank, network->cloneshared->nEdges, network->cloneshared->nVertices, nsv));
312 
313     for (i = 0; i < nsubnet; i++) {
314       PetscCall(DMNetworkGetSubnetwork(dm, i, &nv, &ne, &vtx, &edges));
315       if (ne) {
316         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %" PetscInt_FMT ": nEdges %" PetscInt_FMT ", nVertices(include shared vertices) %" PetscInt_FMT "\n", i, ne, nv));
317         for (j = 0; j < ne; j++) {
318           p = edges[j];
319           PetscCall(DMNetworkGetConnectedVertices(dm, p, &cone));
320           PetscCall(DMNetworkGetGlobalVertexIndex(dm, cone[0], &vfrom));
321           PetscCall(DMNetworkGetGlobalVertexIndex(dm, cone[1], &vto));
322           PetscCall(DMNetworkGetGlobalEdgeIndex(dm, edges[j], &p));
323           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       edge %" PetscInt_FMT ": %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", p, vfrom, vto));
324         }
325       }
326     }
327 
328     /* Shared vertices */
329     PetscCall(DMNetworkGetSharedVertices(dm, NULL, &vtx));
330     if (nsv) {
331       PetscInt        gidx;
332       PetscBool       ghost;
333       const PetscInt *sv = NULL;
334 
335       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     SharedVertices:\n"));
336       for (i = 0; i < nsv; i++) {
337         PetscCall(DMNetworkIsGhostVertex(dm, vtx[i], &ghost));
338         if (ghost) continue;
339 
340         PetscCall(DMNetworkSharedVertexGetInfo(dm, vtx[i], &gidx, &nv, &sv));
341         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       svtx %" PetscInt_FMT ": global index %" PetscInt_FMT ", subnet[%" PetscInt_FMT "].%" PetscInt_FMT " ---->\n", i, gidx, sv[0], sv[1]));
342         for (j = 1; j < nv; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "                                           ----> subnet[%" PetscInt_FMT "].%" PetscInt_FMT "\n", sv[2 * j], sv[2 * j + 1]));
343       }
344     }
345     PetscCall(PetscViewerFlush(viewer));
346     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
347   } else PetscCheck(iascii, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMNetwork writing", ((PetscObject)viewer)->type_name);
348   PetscFunctionReturn(PETSC_SUCCESS);
349 }
350 
351 /*@
352   DMNetworkViewSetShowRanks - Sets viewing the `DMETNWORK` on each rank individually.
353 
354   Logically Collective
355 
356   Input Parameter:
357 . dm - the `DMNETWORK` object
358 
359   Output Parameter:
360 . showranks - `PETSC_TRUE` if viewing each rank's sub network individually
361 
362   Level: beginner
363 
364 .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
365 @*/
366 PetscErrorCode DMNetworkViewSetShowRanks(DM dm, PetscBool showranks)
367 {
368   DM_Network *network = (DM_Network *)dm->data;
369 
370   PetscFunctionBegin;
371   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
372   network->vieweroptions.showallranks = showranks;
373   PetscFunctionReturn(PETSC_SUCCESS);
374 }
375 
376 /*@
377   DMNetworkViewSetShowGlobal - Set viewing the global network.
378 
379   Logically Collective
380 
381   Input Parameter:
382 . dm - the `DMNETWORK` object
383 
384   Output Parameter:
385 . showglobal - `PETSC_TRUE` if viewing the global network
386 
387   Level: beginner
388 
389 .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
390 @*/
391 PetscErrorCode DMNetworkViewSetShowGlobal(DM dm, PetscBool showglobal)
392 {
393   DM_Network *network = (DM_Network *)dm->data;
394 
395   PetscFunctionBegin;
396   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
397   network->vieweroptions.dontshowglobal = (PetscBool)(!showglobal);
398   PetscFunctionReturn(PETSC_SUCCESS);
399 }
400 
401 /*@
402   DMNetworkViewSetShowVertices - Sets whether to display the vertices in viewing routines.
403 
404   Logically Collective
405 
406   Input Parameter:
407 . dm - the `DMNETWORK` object
408 
409   Output Parameter:
410 . showvertices - `PETSC_TRUE` if visualizing the vertices
411 
412   Level: beginner
413 
414 .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
415 @*/
416 PetscErrorCode DMNetworkViewSetShowVertices(DM dm, PetscBool showvertices)
417 {
418   DM_Network *network = (DM_Network *)dm->data;
419 
420   PetscFunctionBegin;
421   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
422   network->vieweroptions.shownovertices = (PetscBool)(!showvertices);
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   DMNetworkViewSetShowNumbering - Set displaying the numbering of edges and vertices in viewing routines.
428 
429   Logically Collective
430 
431   Input Parameter:
432 . dm - the `DMNETWORK` object
433 
434   Output Parameter:
435 . shownumbering - `PETSC_TRUE` if displaying the numbering of edges and vertices
436 
437   Level: beginner
438 
439 .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetViewRanks()`
440 @*/
441 PetscErrorCode DMNetworkViewSetShowNumbering(DM dm, PetscBool shownumbering)
442 {
443   DM_Network *network = (DM_Network *)dm->data;
444 
445   PetscFunctionBegin;
446   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
447   network->vieweroptions.shownonumbering = (PetscBool)(!shownumbering);
448   PetscFunctionReturn(PETSC_SUCCESS);
449 }
450 
451 /*@
452   DMNetworkViewSetViewRanks - View the `DMNETWORK` on each of the specified ranks individually.
453 
454   Collective
455 
456   Input Parameter:
457 . dm - the `DMNETWORK` object
458 
459   Output Parameter:
460 . viewranks - set of ranks to view the `DMNETWORK` on individually
461 
462   Level: beginner
463 
464   Note:
465   `DMNetwork` takes ownership of the input viewranks `IS`, it should be destroyed by the caller.
466 
467 .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`
468 @*/
469 PetscErrorCode DMNetworkViewSetViewRanks(DM dm, IS viewranks)
470 {
471   DM_Network *network = (DM_Network *)dm->data;
472 
473   PetscFunctionBegin;
474   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
475   PetscValidHeaderSpecific(viewranks, IS_CLASSID, 2);
476   PetscCheckSameComm(dm, 1, viewranks, 2);
477   PetscCall(ISDestroy(&network->vieweroptions.viewranks));
478   PetscCall(PetscObjectReference((PetscObject)viewranks));
479   network->vieweroptions.viewranks = viewranks;
480   PetscFunctionReturn(PETSC_SUCCESS);
481 }
482