xref: /petsc/src/dm/impls/network/networkview.c (revision 1777c8a54be4bdf32cfa56ef79c2513d44e9bbec)
112e0ef65SDuncan Campbell #include <petscconf.h>
212e0ef65SDuncan Campbell // We need to define this ahead of any other includes to make sure mkstemp is actually defined
312e0ef65SDuncan Campbell #if defined(PETSC_HAVE_MKSTEMP)
4*1777c8a5SBarry Smith   #if !defined(_XOPEN_SOURCE)
512e0ef65SDuncan Campbell     #define _XOPEN_SOURCE 600
612e0ef65SDuncan Campbell   #endif
7*1777c8a5SBarry Smith #endif
85f25b224SDuncan Campbell #include "petsc/private/petscimpl.h"
95f25b224SDuncan Campbell #include "petscerror.h"
105f25b224SDuncan Campbell #include "petscis.h"
115f25b224SDuncan Campbell #include "petscstring.h"
125f25b224SDuncan Campbell #include "petscsys.h"
135f25b224SDuncan Campbell #include "petscsystypes.h"
14d2fd5932SHong Zhang #include <petsc/private/dmnetworkimpl.h> /*I  "petscdmnetwork.h"  I*/
1512e0ef65SDuncan Campbell #include <petscdraw.h>
16d2fd5932SHong Zhang 
17df1a93feSDuncan Campbell static PetscErrorCode DMView_Network_CSV(DM dm, PetscViewer viewer)
18df1a93feSDuncan Campbell {
19df1a93feSDuncan Campbell   DM              dmcoords;
207cd471e7SHong Zhang   PetscInt        nsubnets, i, subnet, nvertices, nedges, vertex, edge, gidx, ncomp;
21df1a93feSDuncan Campbell   PetscInt        vertexOffsets[2], globalEdgeVertices[2];
227cd471e7SHong Zhang   PetscScalar     vertexCoords[2], *color_ptr, color;
23df1a93feSDuncan Campbell   const PetscInt *vertices, *edges, *edgeVertices;
24df1a93feSDuncan Campbell   Vec             allVertexCoords;
25df1a93feSDuncan Campbell   PetscMPIInt     rank;
26df1a93feSDuncan Campbell   MPI_Comm        comm;
27df1a93feSDuncan Campbell 
28df1a93feSDuncan Campbell   PetscFunctionBegin;
297cd471e7SHong Zhang   // Get the coordinate information from dmcoords
307cd471e7SHong Zhang   PetscCheck(dm->coordinates[0].dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "CoordinateDM not created");
31df1a93feSDuncan Campbell   PetscCall(DMGetCoordinateDM(dm, &dmcoords));
327cd471e7SHong Zhang 
337cd471e7SHong Zhang   PetscCall(DMGetCoordinateDim(dmcoords, &i));
34baca6076SPierre Jolivet   PetscCheck(i == 2, PETSC_COMM_WORLD, PETSC_ERR_SUP, "dim %" PetscInt_FMT " != 2 is not supported yet", i);
357cd471e7SHong Zhang 
367cd471e7SHong Zhang   // Get the coordinate vector from dm
37df1a93feSDuncan Campbell   PetscCall(DMGetCoordinatesLocal(dm, &allVertexCoords));
387cd471e7SHong Zhang 
39df1a93feSDuncan Campbell   // Get the MPI communicator and this process' rank
407cd471e7SHong Zhang   PetscCall(PetscObjectGetComm((PetscObject)dmcoords, &comm));
41df1a93feSDuncan Campbell   PetscCallMPI(MPI_Comm_rank(comm, &rank));
427cd471e7SHong Zhang 
43df1a93feSDuncan Campbell   // Start synchronized printing
44df1a93feSDuncan Campbell   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
45df1a93feSDuncan Campbell 
46df1a93feSDuncan Campbell   // Write the header
47df1a93feSDuncan Campbell   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Type,Rank,ID,X,Y,Z,Name,Color\n"));
48df1a93feSDuncan Campbell 
49df1a93feSDuncan Campbell   // Iterate each subnetwork (Note: We need to get the global number of subnets apparently)
507cd471e7SHong Zhang   PetscCall(DMNetworkGetNumSubNetworks(dmcoords, NULL, &nsubnets));
51df1a93feSDuncan Campbell   for (subnet = 0; subnet < nsubnets; subnet++) {
52df1a93feSDuncan Campbell     // Get the subnetwork's vertices and edges
537cd471e7SHong Zhang     PetscCall(DMNetworkGetSubnetwork(dmcoords, subnet, &nvertices, &nedges, &vertices, &edges));
54df1a93feSDuncan Campbell 
55df1a93feSDuncan Campbell     // Write out each vertex
56df1a93feSDuncan Campbell     for (i = 0; i < nvertices; i++) {
57df1a93feSDuncan Campbell       vertex = vertices[i];
587cd471e7SHong Zhang 
59df1a93feSDuncan Campbell       // Get the offset into the coordinate vector for the vertex
60df1a93feSDuncan Campbell       PetscCall(DMNetworkGetLocalVecOffset(dmcoords, vertex, ALL_COMPONENTS, vertexOffsets));
61df1a93feSDuncan Campbell       vertexOffsets[1] = vertexOffsets[0] + 1;
62df1a93feSDuncan Campbell       // Remap vertex to the global value
637cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, vertex, &gidx));
64df1a93feSDuncan Campbell       // Get the vertex position from the coordinate vector
65df1a93feSDuncan Campbell       PetscCall(VecGetValues(allVertexCoords, 2, vertexOffsets, vertexCoords));
66df1a93feSDuncan Campbell 
677cd471e7SHong Zhang       // Get vertex color; TODO: name
687cd471e7SHong Zhang       PetscCall(DMNetworkGetNumComponents(dmcoords, vertex, &ncomp));
697cd471e7SHong Zhang       PetscCheck(ncomp <= 1, PETSC_COMM_WORLD, PETSC_ERR_SUP, "num of components %" PetscInt_FMT " must be <= 1", ncomp);
707cd471e7SHong Zhang       color = 0.0;
717cd471e7SHong Zhang       if (ncomp == 1) {
727cd471e7SHong Zhang         PetscCall(DMNetworkGetComponent(dmcoords, vertex, 0, NULL, (void **)&color_ptr, NULL));
737cd471e7SHong Zhang         color = *color_ptr;
747cd471e7SHong Zhang       }
757cd471e7SHong Zhang       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)));
76df1a93feSDuncan Campbell     }
77df1a93feSDuncan Campbell 
78df1a93feSDuncan Campbell     // Write out each edge
79df1a93feSDuncan Campbell     for (i = 0; i < nedges; i++) {
80df1a93feSDuncan Campbell       edge = edges[i];
817cd471e7SHong Zhang       PetscCall(DMNetworkGetConnectedVertices(dmcoords, edge, &edgeVertices));
827cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, edgeVertices[0], &globalEdgeVertices[0]));
837cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, edgeVertices[1], &globalEdgeVertices[1]));
847cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalEdgeIndex(dmcoords, edge, &edge));
85df1a93feSDuncan Campbell 
86df1a93feSDuncan Campbell       // TODO: Determine edge color/name
87df1a93feSDuncan Campbell       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Edge,%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",0,%" PetscInt_FMT "\n", (PetscInt)rank, edge, globalEdgeVertices[0], globalEdgeVertices[1], edge));
88df1a93feSDuncan Campbell     }
89df1a93feSDuncan Campbell   }
90df1a93feSDuncan Campbell   // End synchronized printing
91df1a93feSDuncan Campbell   PetscCall(PetscViewerFlush(viewer));
92df1a93feSDuncan Campbell   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
93df1a93feSDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
94df1a93feSDuncan Campbell }
95df1a93feSDuncan Campbell 
96df1a93feSDuncan Campbell static PetscErrorCode DMView_Network_Matplotlib(DM dm, PetscViewer viewer)
97df1a93feSDuncan Campbell {
98cd2bb8e3SDuncan Campbell   PetscMPIInt rank, size;
99df1a93feSDuncan Campbell   MPI_Comm    comm;
1005039956bSHong Zhang   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];
101df1a93feSDuncan Campbell   PetscViewer csvViewer;
102df1a93feSDuncan Campbell   FILE       *processFile = NULL;
1035039956bSHong Zhang   PetscBool   isnull, optionShowRanks = PETSC_FALSE, optionRankIsSet = PETSC_FALSE, showNoNodes = PETSC_FALSE, showNoNumbering = PETSC_FALSE, optionShowVertices = PETSC_FALSE, optionViewPadding = PETSC_FALSE;
104df1a93feSDuncan Campbell   PetscDraw   draw;
1055f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
1065039956bSHong Zhang   PetscReal   drawPause, viewPadding = 1.0;
1075f25b224SDuncan Campbell   PetscInt    i;
108cd2bb8e3SDuncan Campbell #if defined(PETSC_HAVE_MKSTEMP)
109cd2bb8e3SDuncan Campbell   PetscBool isSharedTmp;
110cd2bb8e3SDuncan Campbell #endif
111df1a93feSDuncan Campbell 
112df1a93feSDuncan Campbell   PetscFunctionBegin;
113df1a93feSDuncan Campbell   // Deal with the PetscDraw we are given
114df1a93feSDuncan Campbell   PetscCall(PetscViewerDrawGetDraw(viewer, 1, &draw));
115df1a93feSDuncan Campbell   PetscCall(PetscDrawIsNull(draw, &isnull));
116df1a93feSDuncan Campbell   PetscCall(PetscDrawSetVisible(draw, PETSC_FALSE));
117df1a93feSDuncan Campbell 
118df1a93feSDuncan Campbell   // Clear the file name buffer so all communicated bytes are well-defined
119df1a93feSDuncan Campbell   PetscCall(PetscMemzero(filename, sizeof(filename)));
120df1a93feSDuncan Campbell 
121df1a93feSDuncan Campbell   // Get the MPI communicator and this process' rank
122df1a93feSDuncan Campbell   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
123df1a93feSDuncan Campbell   PetscCallMPI(MPI_Comm_rank(comm, &rank));
124df1a93feSDuncan Campbell   PetscCallMPI(MPI_Comm_size(comm, &size));
125df1a93feSDuncan Campbell 
126cd2bb8e3SDuncan Campbell #if defined(PETSC_HAVE_MKSTEMP)
127cd2bb8e3SDuncan Campbell   // Get if the temporary directory is shared
128cd2bb8e3SDuncan Campbell   // Note: This must be done collectively on every rank, it cannot be done on a single rank
129cd2bb8e3SDuncan Campbell   PetscCall(PetscSharedTmp(comm, &isSharedTmp));
130cd2bb8e3SDuncan Campbell #endif
131cd2bb8e3SDuncan Campbell 
1325f25b224SDuncan Campbell   /* Process Options */
1335f25b224SDuncan Campbell   optionShowRanks = network->vieweroptions.showallranks;
1345f25b224SDuncan Campbell   showNoNodes     = network->vieweroptions.shownovertices;
1355f25b224SDuncan Campbell   showNoNumbering = network->vieweroptions.shownonumbering;
1365f25b224SDuncan Campbell 
1375f25b224SDuncan Campbell   /*
1385f25b224SDuncan Campbell     TODO:  if the option -dmnetwork_view_tmpdir can be moved up here that would be good as well.
1395f25b224SDuncan Campbell   */
1405f25b224SDuncan Campbell   PetscOptionsBegin(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->prefix, "MatPlotLib PetscViewer DMNetwork Options", "PetscViewer");
1415f25b224SDuncan Campbell   PetscCall(PetscOptionsBool("-dmnetwork_view_all_ranks", "View all ranks in the DMNetwork", NULL, optionShowRanks, &optionShowRanks, NULL));
1425f25b224SDuncan Campbell   PetscCall(PetscOptionsString("-dmnetwork_view_rank_range", "Set of ranks to view the DMNetwork on", NULL, buffer, buffer, sizeof(buffer), &optionRankIsSet));
1435f25b224SDuncan Campbell   PetscCall(PetscOptionsBool("-dmnetwork_view_no_vertices", "Do not view vertices", NULL, showNoNodes, &showNoNodes, NULL));
1445f25b224SDuncan Campbell   PetscCall(PetscOptionsBool("-dmnetwork_view_no_numbering", "Do not view edge and vertex numbering", NULL, showNoNumbering, &showNoNumbering, NULL));
1455039956bSHong Zhang   PetscCall(PetscOptionsString("-dmnetwork_view_zoomin_vertices", "Focus the view on the given set of vertices", NULL, buffer2, buffer2, sizeof(buffer2), &optionShowVertices));
1465039956bSHong Zhang   PetscCall(PetscOptionsReal("-dmnetwork_view_zoomin_vertices_padding", "Set the padding when viewing specific vertices", NULL, viewPadding, &viewPadding, &optionViewPadding));
1475f25b224SDuncan Campbell   PetscOptionsEnd();
1485f25b224SDuncan Campbell 
149df1a93feSDuncan Campbell   // Generate and broadcast the temporary file name from rank 0
150df1a93feSDuncan Campbell   if (rank == 0) {
151df1a93feSDuncan Campbell #if defined(PETSC_HAVE_TMPNAM_S)
152df1a93feSDuncan Campbell     // Acquire a temporary file to write to and open an ASCII/CSV viewer
153df1a93feSDuncan Campbell     PetscCheck(tmpnam_s(filename, sizeof(filename)) == 0, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
15412e0ef65SDuncan Campbell #elif defined(PETSC_HAVE_MKSTEMP)
155cd2bb8e3SDuncan Campbell     PetscBool isTmpOverridden;
156df1a93feSDuncan Campbell     size_t    numChars;
157df1a93feSDuncan Campbell     // Same thing, but for POSIX systems on which tmpnam is deprecated
158df1a93feSDuncan Campbell     // 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
159df1a93feSDuncan Campbell     // 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
1606e4289a0SDuncan Campbell     PetscCall(PetscOptionsGetString(NULL, NULL, "-dmnetwork_view_tmpdir", filename, sizeof(filename), &isTmpOverridden));
1616e4289a0SDuncan Campbell     // If not specified by option try using a shared tmp on the system
1626e4289a0SDuncan Campbell     if (!isTmpOverridden) {
1636e4289a0SDuncan Campbell       // Validate that if tmp is not overridden it is at least shared
164cd2bb8e3SDuncan Campbell       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");
165cd2bb8e3SDuncan Campbell       PetscCall(PetscGetTmp(PETSC_COMM_SELF, filename, sizeof(filename)));
166cd2bb8e3SDuncan Campbell     }
167df1a93feSDuncan Campbell     // Make sure the filename ends with a '/'
168df1a93feSDuncan Campbell     PetscCall(PetscStrlen(filename, &numChars));
169df1a93feSDuncan Campbell     if (filename[numChars - 1] != '/') {
170df1a93feSDuncan Campbell       filename[numChars]     = '/';
171df1a93feSDuncan Campbell       filename[numChars + 1] = 0;
172df1a93feSDuncan Campbell     }
173df1a93feSDuncan Campbell     // Perform the actual temporary file creation
174c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(filename, "XXXXXX", sizeof(filename)));
175df1a93feSDuncan Campbell     PetscCheck(mkstemp(filename) != -1, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
176df1a93feSDuncan Campbell #else
177df1a93feSDuncan Campbell     // Same thing, but for older C versions which don't have the safe form
178df1a93feSDuncan Campbell     PetscCheck(tmpnam(filename) != NULL, comm, PETSC_ERR_SYS, "Could not acquire temporary file");
179df1a93feSDuncan Campbell #endif
180df1a93feSDuncan Campbell   }
181df1a93feSDuncan Campbell 
182cd2bb8e3SDuncan Campbell   // Broadcast the filename to all other MPI ranks
183cd2bb8e3SDuncan Campbell   PetscCallMPI(MPI_Bcast(filename, PETSC_MAX_PATH_LEN, MPI_BYTE, 0, comm));
184cd2bb8e3SDuncan Campbell 
185e66d8692SHong Zhang   PetscCall(PetscViewerASCIIOpen(comm, filename, &csvViewer));
186df1a93feSDuncan Campbell   PetscCall(PetscViewerPushFormat(csvViewer, PETSC_VIEWER_ASCII_CSV));
187df1a93feSDuncan Campbell 
188df1a93feSDuncan Campbell   // Use the CSV viewer to write out the local network
189df1a93feSDuncan Campbell   PetscCall(DMView_Network_CSV(dm, csvViewer));
190df1a93feSDuncan Campbell 
191df1a93feSDuncan Campbell   // Close the viewer
192df1a93feSDuncan Campbell   PetscCall(PetscViewerDestroy(&csvViewer));
193df1a93feSDuncan Campbell 
1945f25b224SDuncan Campbell   // Generate options string
1955f25b224SDuncan Campbell   PetscCall(PetscMemzero(options, sizeof(options)));
1965f25b224SDuncan Campbell   // If the draw is null run as a "test execute" ie. do nothing just test that the script was called correctly
1975f25b224SDuncan Campbell   PetscCall(PetscStrlcat(options, isnull ? " -tx " : " ", sizeof(options)));
1985f25b224SDuncan Campbell   PetscCall(PetscDrawGetPause(draw, &drawPause));
1995f25b224SDuncan Campbell   if (drawPause > 0) {
2005f25b224SDuncan Campbell     char pausebuffer[64];
2015f25b224SDuncan Campbell     PetscCall(PetscSNPrintf(pausebuffer, sizeof(pausebuffer), "%f", (double)drawPause));
2025f25b224SDuncan Campbell     PetscCall(PetscStrlcat(options, " -dt ", sizeof(options)));
2035f25b224SDuncan Campbell     PetscCall(PetscStrlcat(options, pausebuffer, sizeof(options)));
2045f25b224SDuncan Campbell   }
2055f25b224SDuncan Campbell   if (optionShowRanks || optionRankIsSet) {
2065f25b224SDuncan Campbell     // 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
2075f25b224SDuncan Campbell     if (optionShowRanks && !optionRankIsSet && size != 1) PetscCall(PetscStrlcat(options, " -dar ", sizeof(options)));
2085f25b224SDuncan Campbell     // Do not show the global plot if the user requests it OR if one specific rank is requested
2095f25b224SDuncan Campbell     if (network->vieweroptions.dontshowglobal || optionRankIsSet) PetscCall(PetscStrlcat(options, " -ncp ", sizeof(options)));
2105f25b224SDuncan Campbell 
2115f25b224SDuncan Campbell     if (optionRankIsSet) {
2125f25b224SDuncan Campbell       // If a range of ranks to draw is specified append it
2135f25b224SDuncan Campbell       PetscCall(PetscStrlcat(options, " -drr ", sizeof(options)));
2145f25b224SDuncan Campbell       PetscCall(PetscStrlcat(options, buffer, sizeof(options)));
2155f25b224SDuncan Campbell     } else {
2165f25b224SDuncan Campbell       // Otherwise, use the options provided in code
2175f25b224SDuncan Campbell       if (network->vieweroptions.viewranks) {
2185f25b224SDuncan Campbell         const PetscInt *viewranks;
2195f25b224SDuncan Campbell         PetscInt        viewrankssize;
2205f25b224SDuncan Campbell         char            rankbuffer[64];
2215f25b224SDuncan Campbell         PetscCall(ISGetTotalIndices(network->vieweroptions.viewranks, &viewranks));
2225f25b224SDuncan Campbell         PetscCall(ISGetSize(network->vieweroptions.viewranks, &viewrankssize));
2235f25b224SDuncan Campbell         PetscCall(PetscStrlcat(options, " -drr ", sizeof(options)));
2245f25b224SDuncan Campbell         for (i = 0; i < viewrankssize; i++) {
2255f25b224SDuncan Campbell           PetscCall(PetscSNPrintf(rankbuffer, sizeof(rankbuffer), "%" PetscInt_FMT, viewranks[i]));
2265f25b224SDuncan Campbell           PetscCall(PetscStrlcat(options, rankbuffer, sizeof(options)));
2275f25b224SDuncan Campbell         }
2285f25b224SDuncan Campbell         PetscCall(ISRestoreTotalIndices(network->vieweroptions.viewranks, &viewranks));
2295f25b224SDuncan Campbell       } // if not provided an IS of viewing ranks, skip viewing
2305f25b224SDuncan Campbell     }
2315f25b224SDuncan Campbell   }
2325039956bSHong Zhang   if (optionShowVertices) {
2335039956bSHong Zhang     // Pass vertices to focus on if defined
2345039956bSHong Zhang     PetscCall(PetscStrlcat(options, " -vsv ", sizeof(options)));
2355039956bSHong Zhang     PetscCall(PetscStrlcat(options, buffer2, sizeof(options)));
2365039956bSHong Zhang     optionViewPadding = PETSC_TRUE;
2375039956bSHong Zhang     // Pass padding if set
2385039956bSHong Zhang     if (optionViewPadding) {
2395039956bSHong Zhang       PetscCall(PetscSNPrintf(buffer2, sizeof(buffer2), "%f", (double)viewPadding));
2405039956bSHong Zhang       PetscCall(PetscStrlcat(options, " -vp ", sizeof(options)));
2415039956bSHong Zhang       PetscCall(PetscStrlcat(options, buffer2, sizeof(options)));
2425039956bSHong Zhang     }
2435039956bSHong Zhang   }
2445f25b224SDuncan Campbell 
2455f25b224SDuncan Campbell   // Check for options for visibility...
2465f25b224SDuncan Campbell   if (showNoNodes) PetscCall(PetscStrlcat(options, " -nn ", sizeof(options)));
2475f25b224SDuncan Campbell   if (showNoNumbering) PetscCall(PetscStrlcat(options, " -nnl -nel ", sizeof(options)));
2485f25b224SDuncan Campbell 
249df1a93feSDuncan Campbell   // Get the value of $PETSC_DIR
250e66d8692SHong Zhang   PetscCall(PetscStrreplace(comm, "${PETSC_DIR}/share/petsc/bin/dmnetwork_view.py", scriptFile, sizeof(scriptFile)));
251df1a93feSDuncan Campbell   PetscCall(PetscFixFilename(scriptFile, scriptFile));
2525f25b224SDuncan Campbell   // Generate the system call for 'python3 $PETSC_DIR/share/petsc/dmnetwork_view.py <options> <file>'
253df1a93feSDuncan Campbell   PetscCall(PetscArrayzero(proccall, sizeof(proccall)));
2545f25b224SDuncan Campbell   PetscCall(PetscSNPrintf(proccall, sizeof(proccall), "%s %s %s %s", PETSC_PYTHON_EXE, scriptFile, options, filename));
255df1a93feSDuncan Campbell 
256df1a93feSDuncan Campbell #if defined(PETSC_HAVE_POPEN)
257df1a93feSDuncan Campbell   // Perform the call to run the python script (Note: while this is called on all ranks POpen will only run on rank 0)
258e66d8692SHong Zhang   PetscCall(PetscPOpen(comm, NULL, proccall, "r", &processFile));
259df1a93feSDuncan Campbell   if (processFile != NULL) {
2605f25b224SDuncan Campbell     while (fgets(buffer, sizeof(buffer), processFile) != NULL) PetscCall(PetscPrintf(comm, "%s", buffer));
261df1a93feSDuncan Campbell   }
262e66d8692SHong Zhang   PetscCall(PetscPClose(comm, processFile));
263df1a93feSDuncan Campbell #else
264df1a93feSDuncan Campbell   // Same thing, but using the standard library for systems that don't have POpen/PClose (only run on rank 0)
265e66d8692SHong Zhang   if (rank == 0) PetscCheck(system(proccall) == 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Failed to call viewer script");
266df1a93feSDuncan Campbell   // Barrier so that all ranks wait until the call completes
267e66d8692SHong Zhang   PetscCallMPI(MPI_Barrier(comm));
268df1a93feSDuncan Campbell #endif
269df1a93feSDuncan Campbell   // Clean up the temporary file we used using rank 0
270e66d8692SHong Zhang   if (rank == 0) PetscCheck(remove(filename) == 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Failed to delete temporary file");
271df1a93feSDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
272df1a93feSDuncan Campbell }
273df1a93feSDuncan Campbell 
274d2fd5932SHong Zhang PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
275d2fd5932SHong Zhang {
276df1a93feSDuncan Campbell   PetscBool         iascii, isdraw;
277df1a93feSDuncan Campbell   PetscViewerFormat format;
278d2fd5932SHong Zhang 
279d2fd5932SHong Zhang   PetscFunctionBegin;
280d2fd5932SHong Zhang   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
281d2fd5932SHong Zhang   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
282df1a93feSDuncan Campbell   PetscCall(PetscViewerGetFormat(viewer, &format));
283df1a93feSDuncan Campbell 
284df1a93feSDuncan Campbell   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
285df1a93feSDuncan Campbell   if (isdraw) {
286df1a93feSDuncan Campbell     PetscCall(DMView_Network_Matplotlib(dm, viewer));
287df1a93feSDuncan Campbell     PetscFunctionReturn(PETSC_SUCCESS);
288df1a93feSDuncan Campbell   }
289df1a93feSDuncan Campbell 
290d2fd5932SHong Zhang   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
291d2fd5932SHong Zhang   if (iascii) {
292d2fd5932SHong Zhang     const PetscInt *cone, *vtx, *edges;
293d2fd5932SHong Zhang     PetscInt        vfrom, vto, i, j, nv, ne, nsv, p, nsubnet;
294d2fd5932SHong Zhang     DM_Network     *network = (DM_Network *)dm->data;
295df1a93feSDuncan Campbell     PetscMPIInt     rank;
296df1a93feSDuncan Campbell 
297df1a93feSDuncan Campbell     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
298df1a93feSDuncan Campbell     if (format == PETSC_VIEWER_ASCII_CSV) {
299df1a93feSDuncan Campbell       PetscCall(DMView_Network_CSV(dm, viewer));
300df1a93feSDuncan Campbell       PetscFunctionReturn(PETSC_SUCCESS);
301df1a93feSDuncan Campbell     }
302d2fd5932SHong Zhang 
303d2fd5932SHong Zhang     nsubnet = network->cloneshared->Nsubnet; /* num of subnetworks */
304df1a93feSDuncan Campbell     if (!rank) {
305d2fd5932SHong Zhang       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,
306d2fd5932SHong Zhang                             network->cloneshared->Nsvtx));
307d2fd5932SHong Zhang     }
308d2fd5932SHong Zhang 
309d2fd5932SHong Zhang     PetscCall(DMNetworkGetSharedVertices(dm, &nsv, NULL));
310d2fd5932SHong Zhang     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
311d2fd5932SHong Zhang     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nEdges: %" PetscInt_FMT "; nVertices: %" PetscInt_FMT "; nSharedVertices: %" PetscInt_FMT "\n", rank, network->cloneshared->nEdges, network->cloneshared->nVertices, nsv));
312d2fd5932SHong Zhang 
313d2fd5932SHong Zhang     for (i = 0; i < nsubnet; i++) {
314d2fd5932SHong Zhang       PetscCall(DMNetworkGetSubnetwork(dm, i, &nv, &ne, &vtx, &edges));
315d2fd5932SHong Zhang       if (ne) {
316d2fd5932SHong Zhang         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %" PetscInt_FMT ": nEdges %" PetscInt_FMT ", nVertices(include shared vertices) %" PetscInt_FMT "\n", i, ne, nv));
317d2fd5932SHong Zhang         for (j = 0; j < ne; j++) {
318d2fd5932SHong Zhang           p = edges[j];
319d2fd5932SHong Zhang           PetscCall(DMNetworkGetConnectedVertices(dm, p, &cone));
320d2fd5932SHong Zhang           PetscCall(DMNetworkGetGlobalVertexIndex(dm, cone[0], &vfrom));
321d2fd5932SHong Zhang           PetscCall(DMNetworkGetGlobalVertexIndex(dm, cone[1], &vto));
322d2fd5932SHong Zhang           PetscCall(DMNetworkGetGlobalEdgeIndex(dm, edges[j], &p));
323d2fd5932SHong Zhang           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       edge %" PetscInt_FMT ": %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", p, vfrom, vto));
324d2fd5932SHong Zhang         }
325d2fd5932SHong Zhang       }
326d2fd5932SHong Zhang     }
327d2fd5932SHong Zhang 
328d2fd5932SHong Zhang     /* Shared vertices */
329d2fd5932SHong Zhang     PetscCall(DMNetworkGetSharedVertices(dm, NULL, &vtx));
330d2fd5932SHong Zhang     if (nsv) {
331d2fd5932SHong Zhang       PetscInt        gidx;
332d2fd5932SHong Zhang       PetscBool       ghost;
333d2fd5932SHong Zhang       const PetscInt *sv = NULL;
334d2fd5932SHong Zhang 
335d2fd5932SHong Zhang       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     SharedVertices:\n"));
336d2fd5932SHong Zhang       for (i = 0; i < nsv; i++) {
337d2fd5932SHong Zhang         PetscCall(DMNetworkIsGhostVertex(dm, vtx[i], &ghost));
338d2fd5932SHong Zhang         if (ghost) continue;
339d2fd5932SHong Zhang 
340d2fd5932SHong Zhang         PetscCall(DMNetworkSharedVertexGetInfo(dm, vtx[i], &gidx, &nv, &sv));
341d2fd5932SHong Zhang         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       svtx %" PetscInt_FMT ": global index %" PetscInt_FMT ", subnet[%" PetscInt_FMT "].%" PetscInt_FMT " ---->\n", i, gidx, sv[0], sv[1]));
342d2fd5932SHong Zhang         for (j = 1; j < nv; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "                                           ----> subnet[%" PetscInt_FMT "].%" PetscInt_FMT "\n", sv[2 * j], sv[2 * j + 1]));
343d2fd5932SHong Zhang       }
344d2fd5932SHong Zhang     }
345d2fd5932SHong Zhang     PetscCall(PetscViewerFlush(viewer));
346d2fd5932SHong Zhang     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
347d2fd5932SHong Zhang   } else PetscCheck(iascii, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMNetwork writing", ((PetscObject)viewer)->type_name);
348d2fd5932SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
349d2fd5932SHong Zhang }
3505f25b224SDuncan Campbell 
3515f25b224SDuncan Campbell /*@
3525f25b224SDuncan Campbell   DMNetworkViewSetShowRanks - Sets viewing the `DMETNWORK` on each rank individually.
3535f25b224SDuncan Campbell 
3545f25b224SDuncan Campbell   Logically Collective
3555f25b224SDuncan Campbell 
3565f25b224SDuncan Campbell   Input Parameter:
3575f25b224SDuncan Campbell . dm - the `DMNETWORK` object
3585f25b224SDuncan Campbell 
3595f25b224SDuncan Campbell   Output Parameter:
3605f25b224SDuncan Campbell . showranks - `PETSC_TRUE` if viewing each rank's sub network individually
3615f25b224SDuncan Campbell 
3625f25b224SDuncan Campbell   Level: beginner
3635f25b224SDuncan Campbell 
3645f25b224SDuncan Campbell .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
3655f25b224SDuncan Campbell @*/
3665f25b224SDuncan Campbell PetscErrorCode DMNetworkViewSetShowRanks(DM dm, PetscBool showranks)
3675f25b224SDuncan Campbell {
3685f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
3695f25b224SDuncan Campbell 
3705f25b224SDuncan Campbell   PetscFunctionBegin;
3715f25b224SDuncan Campbell   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
3725f25b224SDuncan Campbell   network->vieweroptions.showallranks = showranks;
3735f25b224SDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
3745f25b224SDuncan Campbell }
3755f25b224SDuncan Campbell 
3765f25b224SDuncan Campbell /*@
3775f25b224SDuncan Campbell   DMNetworkViewSetShowGlobal - Set viewing the global network.
3785f25b224SDuncan Campbell 
3795f25b224SDuncan Campbell   Logically Collective
3805f25b224SDuncan Campbell 
3815f25b224SDuncan Campbell   Input Parameter:
3825f25b224SDuncan Campbell . dm - the `DMNETWORK` object
3835f25b224SDuncan Campbell 
3845f25b224SDuncan Campbell   Output Parameter:
3855f25b224SDuncan Campbell . showglobal - `PETSC_TRUE` if viewing the global network
3865f25b224SDuncan Campbell 
3875f25b224SDuncan Campbell   Level: beginner
3885f25b224SDuncan Campbell 
3895f25b224SDuncan Campbell .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
3905f25b224SDuncan Campbell @*/
3915f25b224SDuncan Campbell PetscErrorCode DMNetworkViewSetShowGlobal(DM dm, PetscBool showglobal)
3925f25b224SDuncan Campbell {
3935f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
3945f25b224SDuncan Campbell 
3955f25b224SDuncan Campbell   PetscFunctionBegin;
3965f25b224SDuncan Campbell   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
3975f25b224SDuncan Campbell   network->vieweroptions.dontshowglobal = (PetscBool)(!showglobal);
3985f25b224SDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
3995f25b224SDuncan Campbell }
4005f25b224SDuncan Campbell 
4015f25b224SDuncan Campbell /*@
4025f25b224SDuncan Campbell   DMNetworkViewSetShowVertices - Sets whether to display the vertices in viewing routines.
4035f25b224SDuncan Campbell 
4045f25b224SDuncan Campbell   Logically Collective
4055f25b224SDuncan Campbell 
4065f25b224SDuncan Campbell   Input Parameter:
4075f25b224SDuncan Campbell . dm - the `DMNETWORK` object
4085f25b224SDuncan Campbell 
4095f25b224SDuncan Campbell   Output Parameter:
4105f25b224SDuncan Campbell . showvertices - `PETSC_TRUE` if visualizing the vertices
4115f25b224SDuncan Campbell 
4125f25b224SDuncan Campbell   Level: beginner
4135f25b224SDuncan Campbell 
4145f25b224SDuncan Campbell .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowNumbering()`, `DMNetworkViewSetViewRanks()`
4155f25b224SDuncan Campbell @*/
4165f25b224SDuncan Campbell PetscErrorCode DMNetworkViewSetShowVertices(DM dm, PetscBool showvertices)
4175f25b224SDuncan Campbell {
4185f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
4195f25b224SDuncan Campbell 
4205f25b224SDuncan Campbell   PetscFunctionBegin;
4215f25b224SDuncan Campbell   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
4225f25b224SDuncan Campbell   network->vieweroptions.shownovertices = (PetscBool)(!showvertices);
4235f25b224SDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
4245f25b224SDuncan Campbell }
4255f25b224SDuncan Campbell 
4265f25b224SDuncan Campbell /*@
4275f25b224SDuncan Campbell   DMNetworkViewSetShowNumbering - Set displaying the numbering of edges and vertices in viewing routines.
4285f25b224SDuncan Campbell 
4295f25b224SDuncan Campbell   Logically Collective
4305f25b224SDuncan Campbell 
4315f25b224SDuncan Campbell   Input Parameter:
4325f25b224SDuncan Campbell . dm - the `DMNETWORK` object
4335f25b224SDuncan Campbell 
4345f25b224SDuncan Campbell   Output Parameter:
4355f25b224SDuncan Campbell . shownumbering - `PETSC_TRUE` if displaying the numbering of edges and vertices
4365f25b224SDuncan Campbell 
4375f25b224SDuncan Campbell   Level: beginner
4385f25b224SDuncan Campbell 
4395f25b224SDuncan Campbell .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetViewRanks()`
4405f25b224SDuncan Campbell @*/
4415f25b224SDuncan Campbell PetscErrorCode DMNetworkViewSetShowNumbering(DM dm, PetscBool shownumbering)
4425f25b224SDuncan Campbell {
4435f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
4445f25b224SDuncan Campbell 
4455f25b224SDuncan Campbell   PetscFunctionBegin;
4465f25b224SDuncan Campbell   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
4475f25b224SDuncan Campbell   network->vieweroptions.shownonumbering = (PetscBool)(!shownumbering);
4485f25b224SDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
4495f25b224SDuncan Campbell }
4505f25b224SDuncan Campbell 
4515f25b224SDuncan Campbell /*@
4525f25b224SDuncan Campbell   DMNetworkViewSetViewRanks - View the `DMNETWORK` on each of the specified ranks individually.
4535f25b224SDuncan Campbell 
4545f25b224SDuncan Campbell   Collective
4555f25b224SDuncan Campbell 
4565f25b224SDuncan Campbell   Input Parameter:
4575f25b224SDuncan Campbell . dm - the `DMNETWORK` object
4585f25b224SDuncan Campbell 
4595f25b224SDuncan Campbell   Output Parameter:
4605f25b224SDuncan Campbell . viewranks - set of ranks to view the `DMNETWORK` on individually
4615f25b224SDuncan Campbell 
4625f25b224SDuncan Campbell   Level: beginner
4635f25b224SDuncan Campbell 
4645f25b224SDuncan Campbell   Note:
4655f25b224SDuncan Campbell   `DMNetwork` takes ownership of the input viewranks `IS`, it should be destroyed by the caller.
4665f25b224SDuncan Campbell 
4675f25b224SDuncan Campbell .seealso: `DM`, `DMNETWORK`, `DMNetworkViewSetShowRanks()`, `DMNetworkViewSetShowGlobal()`, `DMNetworkViewSetShowVertices()`, `DMNetworkViewSetShowNumbering()`
4685f25b224SDuncan Campbell @*/
4695f25b224SDuncan Campbell PetscErrorCode DMNetworkViewSetViewRanks(DM dm, IS viewranks)
4705f25b224SDuncan Campbell {
4715f25b224SDuncan Campbell   DM_Network *network = (DM_Network *)dm->data;
4725f25b224SDuncan Campbell 
4735f25b224SDuncan Campbell   PetscFunctionBegin;
4745f25b224SDuncan Campbell   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMNETWORK);
4755f25b224SDuncan Campbell   PetscValidHeaderSpecific(viewranks, IS_CLASSID, 2);
4765f25b224SDuncan Campbell   PetscCheckSameComm(dm, 1, viewranks, 2);
4775f25b224SDuncan Campbell   PetscCall(ISDestroy(&network->vieweroptions.viewranks));
4785f25b224SDuncan Campbell   PetscCall(PetscObjectReference((PetscObject)viewranks));
4795f25b224SDuncan Campbell   network->vieweroptions.viewranks = viewranks;
4805f25b224SDuncan Campbell   PetscFunctionReturn(PETSC_SUCCESS);
4815f25b224SDuncan Campbell }
482