xref: /petsc/src/sys/classes/viewer/impls/vu/petscvu.c (revision 856bee69f0e0908e75ff837867b1777dfb1ced96)
1 
2 #include <petsc/private/viewerimpl.h> /*I     "petscsys.h"   I*/
3 
4 #define QUEUESTRINGSIZE 1024
5 
6 typedef struct _PrintfQueue *PrintfQueue;
7 struct _PrintfQueue {
8   char        string[QUEUESTRINGSIZE];
9   PrintfQueue next;
10 };
11 
12 typedef struct {
13   FILE         *fd;
14   PetscFileMode mode; /* The mode in which to open the file */
15   char         *filename;
16   PetscBool     vecSeen; /* The flag indicating whether any vector has been viewed so far */
17   PrintfQueue   queue, queueBase;
18   int           queueLength;
19 } PetscViewer_VU;
20 
21 static PetscErrorCode PetscViewerFileClose_VU(PetscViewer viewer)
22 {
23   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
24 
25   PetscFunctionBegin;
26   if (vu->vecSeen) PetscCall(PetscViewerVUPrintDeferred(viewer, "};\n\n"));
27   PetscCall(PetscViewerVUFlushDeferred(viewer));
28   PetscCall(PetscFClose(PetscObjectComm((PetscObject)viewer), vu->fd));
29   vu->fd = NULL;
30   PetscCall(PetscFree(vu->filename));
31   PetscFunctionReturn(PETSC_SUCCESS);
32 }
33 
34 PetscErrorCode PetscViewerDestroy_VU(PetscViewer viewer)
35 {
36   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
37 
38   PetscFunctionBegin;
39   PetscCall(PetscViewerFileClose_VU(viewer));
40   PetscCall(PetscFree(vu));
41   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
42   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
43   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
44   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
45   PetscFunctionReturn(PETSC_SUCCESS);
46 }
47 
48 PetscErrorCode PetscViewerFlush_VU(PetscViewer viewer)
49 {
50   PetscMPIInt rank;
51 
52   PetscFunctionBegin;
53   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
54   if (rank == 0) PetscCall(PetscFFlush(((PetscViewer_VU *)viewer->data)->fd));
55   PetscFunctionReturn(PETSC_SUCCESS);
56 }
57 
58 static PetscErrorCode PetscViewerFileSetMode_VU(PetscViewer viewer, PetscFileMode mode)
59 {
60   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
61 
62   PetscFunctionBegin;
63   vu->mode = mode;
64   PetscFunctionReturn(PETSC_SUCCESS);
65 }
66 
67 static PetscErrorCode PetscViewerFileGetMode_VU(PetscViewer viewer, PetscFileMode *type)
68 {
69   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
70 
71   PetscFunctionBegin;
72   *type = vu->mode;
73   PetscFunctionReturn(PETSC_SUCCESS);
74 }
75 
76 static PetscErrorCode PetscViewerFileGetName_VU(PetscViewer viewer, const char **name)
77 {
78   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
79 
80   PetscFunctionBegin;
81   *name = vu->filename;
82   PetscFunctionReturn(PETSC_SUCCESS);
83 }
84 
85 static PetscErrorCode PetscViewerFileSetName_VU(PetscViewer viewer, const char name[])
86 {
87   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
88   char            fname[PETSC_MAX_PATH_LEN];
89   int             rank;
90 
91   PetscFunctionBegin;
92   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
93   PetscCall(PetscViewerFileClose_VU(viewer));
94   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
95   if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS);
96   PetscCall(PetscStrallocpy(name, &vu->filename));
97   PetscCall(PetscFixFilename(name, fname));
98   switch (vu->mode) {
99   case FILE_MODE_READ:
100     vu->fd = fopen(fname, "r");
101     break;
102   case FILE_MODE_WRITE:
103     vu->fd = fopen(fname, "w");
104     break;
105   case FILE_MODE_APPEND:
106     vu->fd = fopen(fname, "a");
107     break;
108   case FILE_MODE_UPDATE:
109     vu->fd = fopen(fname, "r+");
110     if (!vu->fd) vu->fd = fopen(fname, "w+");
111     break;
112   case FILE_MODE_APPEND_UPDATE:
113     /* I really want a file which is opened at the end for updating,
114        not a+, which opens at the beginning, but makes writes at the end.
115     */
116     vu->fd = fopen(fname, "r+");
117     if (!vu->fd) vu->fd = fopen(fname, "w+");
118     else {
119       int ret = fseek(vu->fd, 0, SEEK_END);
120       PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
121     }
122     break;
123   default:
124     SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vu->mode]);
125   }
126 
127   PetscCheck(vu->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s", fname);
128 #if defined(PETSC_USE_LOG)
129   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
130 #endif
131   PetscFunctionReturn(PETSC_SUCCESS);
132 }
133 
134 /*MC
135    PETSCVIEWERVU - A viewer that prints to a VU file
136 
137   Level: beginner
138 
139 .seealso: [](sec_viewers), `PetscViewerVUFlushDeferred()`, `PetscViewerVUGetPointer()`, `PetscViewerVUSetVecSeen()`, `PetscViewerVUGetVecSeen()`,
140           `PetscViewerVUPrintDeferred()`, `PetscViewerVUFlushDeferred()`
141 M*/
142 PETSC_EXTERN PetscErrorCode PetscViewerCreate_VU(PetscViewer viewer)
143 {
144   PetscViewer_VU *vu;
145 
146   PetscFunctionBegin;
147   PetscCall(PetscNew(&vu));
148   viewer->data = (void *)vu;
149 
150   viewer->ops->destroy          = PetscViewerDestroy_VU;
151   viewer->ops->flush            = PetscViewerFlush_VU;
152   viewer->ops->getsubviewer     = NULL;
153   viewer->ops->restoresubviewer = NULL;
154 
155   vu->fd          = NULL;
156   vu->mode        = FILE_MODE_WRITE;
157   vu->filename    = NULL;
158   vu->vecSeen     = PETSC_FALSE;
159   vu->queue       = NULL;
160   vu->queueBase   = NULL;
161   vu->queueLength = 0;
162 
163   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_VU));
164   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_VU));
165   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_VU));
166   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_VU));
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
170 /*@C
171   PetscViewerVUGetPointer - Extracts the file pointer from a `PETSCVIEWERVU` `PetscViewer`.
172 
173   Not Collective
174 
175   Input Parameter:
176 . viewer - The `PetscViewer`
177 
178   Output Parameter:
179 . fd - The file pointer
180 
181   Level: intermediate
182 
183 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerASCIIGetPointer()`
184 @*/
185 PetscErrorCode PetscViewerVUGetPointer(PetscViewer viewer, FILE **fd)
186 {
187   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
188 
189   PetscFunctionBegin;
190   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
191   PetscAssertPointer(fd, 2);
192   *fd = vu->fd;
193   PetscFunctionReturn(PETSC_SUCCESS);
194 }
195 
196 /*@C
197   PetscViewerVUSetVecSeen - Sets the flag which indicates whether we have viewed
198   a vector. This is usually called internally rather than by a user.
199 
200   Not Collective
201 
202   Input Parameters:
203 + viewer  - The `PETSCVIEWERVU` `PetscViewer`
204 - vecSeen - The flag which indicates whether we have viewed a vector
205 
206   Level: developer
207 
208 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUGetVecSeen()`
209 @*/
210 PetscErrorCode PetscViewerVUSetVecSeen(PetscViewer viewer, PetscBool vecSeen)
211 {
212   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
213 
214   PetscFunctionBegin;
215   vu->vecSeen = vecSeen;
216   PetscFunctionReturn(PETSC_SUCCESS);
217 }
218 
219 /*@C
220   PetscViewerVUGetVecSeen - Gets the flag which indicates whether we have viewed
221   a vector. This is usually called internally rather than by a user.
222 
223   Not Collective
224 
225   Input Parameter:
226 . viewer - The `PETSCVIEWERVU` `PetscViewer`
227 
228   Output Parameter:
229 . vecSeen - The flag which indicates whether we have viewed a vector
230 
231   Level: advanced
232 
233 .seealso: [](sec_viewers), `PETSCVIEWERVU`
234 @*/
235 PetscErrorCode PetscViewerVUGetVecSeen(PetscViewer viewer, PetscBool *vecSeen)
236 {
237   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
238 
239   PetscFunctionBegin;
240   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
241   PetscAssertPointer(vecSeen, 2);
242   *vecSeen = vu->vecSeen;
243   PetscFunctionReturn(PETSC_SUCCESS);
244 }
245 
246 /*@C
247   PetscViewerVUPrintDeferred - Prints to the deferred write cache instead of the file.
248 
249   Not Collective
250 
251   Input Parameters:
252 + viewer - The `PETSCVIEWERVU` `PetscViewer`
253 - format - The format string
254 
255   Level: intermediate
256 
257 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUFlushDeferred()`
258 @*/
259 PetscErrorCode PetscViewerVUPrintDeferred(PetscViewer viewer, const char format[], ...)
260 {
261   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
262   va_list         Argp;
263   size_t          fullLength;
264   PrintfQueue     next;
265 
266   PetscFunctionBegin;
267   PetscCall(PetscNew(&next));
268   if (vu->queue) {
269     vu->queue->next = next;
270     vu->queue       = next;
271     vu->queue->next = NULL;
272   } else {
273     vu->queueBase = vu->queue = next;
274   }
275   vu->queueLength++;
276 
277   va_start(Argp, format);
278   PetscCall(PetscArrayzero(next->string, QUEUESTRINGSIZE));
279   PetscCall(PetscVSNPrintf(next->string, QUEUESTRINGSIZE, format, &fullLength, Argp));
280   va_end(Argp);
281   PetscFunctionReturn(PETSC_SUCCESS);
282 }
283 
284 /*@C
285   PetscViewerVUFlushDeferred - Flushes the deferred write cache to the file.
286 
287   Not Collective
288 
289   Input Parameter:
290 . viewer - The `PETSCVIEWERVU` `PetscViewer`
291 
292   Level: intermediate
293 
294 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUPrintDeferred()`
295 @*/
296 PetscErrorCode PetscViewerVUFlushDeferred(PetscViewer viewer)
297 {
298   PetscViewer_VU *vu   = (PetscViewer_VU *)viewer->data;
299   PrintfQueue     next = vu->queueBase;
300   PrintfQueue     previous;
301   int             i;
302 
303   PetscFunctionBegin;
304   for (i = 0; i < vu->queueLength; i++) {
305     PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)viewer), vu->fd, "%s", next->string));
306     previous = next;
307     next     = next->next;
308     PetscCall(PetscFree(previous));
309   }
310   vu->queue       = NULL;
311   vu->queueLength = 0;
312   PetscFunctionReturn(PETSC_SUCCESS);
313 }
314