xref: /petsc/src/sys/classes/viewer/impls/vu/petscvu.c (revision 0619917b5a674bb687c64e7daba2ab22be99af31)
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 static 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 static 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   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
129   PetscFunctionReturn(PETSC_SUCCESS);
130 }
131 
132 /*MC
133    PETSCVIEWERVU - A viewer that prints to a VU file
134 
135   Level: beginner
136 
137 .seealso: [](sec_viewers), `PetscViewerVUFlushDeferred()`, `PetscViewerVUGetPointer()`, `PetscViewerVUSetVecSeen()`, `PetscViewerVUGetVecSeen()`,
138           `PetscViewerVUPrintDeferred()`, `PetscViewerVUFlushDeferred()`
139 M*/
140 PETSC_EXTERN PetscErrorCode PetscViewerCreate_VU(PetscViewer viewer)
141 {
142   PetscViewer_VU *vu;
143 
144   PetscFunctionBegin;
145   PetscCall(PetscNew(&vu));
146   viewer->data = (void *)vu;
147 
148   viewer->ops->destroy          = PetscViewerDestroy_VU;
149   viewer->ops->flush            = PetscViewerFlush_VU;
150   viewer->ops->getsubviewer     = NULL;
151   viewer->ops->restoresubviewer = NULL;
152 
153   vu->fd          = NULL;
154   vu->mode        = FILE_MODE_WRITE;
155   vu->filename    = NULL;
156   vu->vecSeen     = PETSC_FALSE;
157   vu->queue       = NULL;
158   vu->queueBase   = NULL;
159   vu->queueLength = 0;
160 
161   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_VU));
162   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_VU));
163   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_VU));
164   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_VU));
165   PetscFunctionReturn(PETSC_SUCCESS);
166 }
167 
168 /*@C
169   PetscViewerVUGetPointer - Extracts the file pointer from a `PETSCVIEWERVU` `PetscViewer`.
170 
171   Not Collective
172 
173   Input Parameter:
174 . viewer - The `PetscViewer`
175 
176   Output Parameter:
177 . fd - The file pointer
178 
179   Level: intermediate
180 
181 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerASCIIGetPointer()`
182 @*/
183 PetscErrorCode PetscViewerVUGetPointer(PetscViewer viewer, FILE **fd)
184 {
185   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
186 
187   PetscFunctionBegin;
188   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
189   PetscAssertPointer(fd, 2);
190   *fd = vu->fd;
191   PetscFunctionReturn(PETSC_SUCCESS);
192 }
193 
194 /*@C
195   PetscViewerVUSetVecSeen - Sets the flag which indicates whether we have viewed
196   a vector. This is usually called internally rather than by a user.
197 
198   Not Collective
199 
200   Input Parameters:
201 + viewer  - The `PETSCVIEWERVU` `PetscViewer`
202 - vecSeen - The flag which indicates whether we have viewed a vector
203 
204   Level: developer
205 
206 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUGetVecSeen()`
207 @*/
208 PetscErrorCode PetscViewerVUSetVecSeen(PetscViewer viewer, PetscBool vecSeen)
209 {
210   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
211 
212   PetscFunctionBegin;
213   vu->vecSeen = vecSeen;
214   PetscFunctionReturn(PETSC_SUCCESS);
215 }
216 
217 /*@C
218   PetscViewerVUGetVecSeen - Gets the flag which indicates whether we have viewed
219   a vector. This is usually called internally rather than by a user.
220 
221   Not Collective
222 
223   Input Parameter:
224 . viewer - The `PETSCVIEWERVU` `PetscViewer`
225 
226   Output Parameter:
227 . vecSeen - The flag which indicates whether we have viewed a vector
228 
229   Level: advanced
230 
231 .seealso: [](sec_viewers), `PETSCVIEWERVU`
232 @*/
233 PetscErrorCode PetscViewerVUGetVecSeen(PetscViewer viewer, PetscBool *vecSeen)
234 {
235   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
236 
237   PetscFunctionBegin;
238   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
239   PetscAssertPointer(vecSeen, 2);
240   *vecSeen = vu->vecSeen;
241   PetscFunctionReturn(PETSC_SUCCESS);
242 }
243 
244 /*@C
245   PetscViewerVUPrintDeferred - Prints to the deferred write cache instead of the file.
246 
247   Not Collective
248 
249   Input Parameters:
250 + viewer - The `PETSCVIEWERVU` `PetscViewer`
251 - format - The format string
252 
253   Level: intermediate
254 
255 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUFlushDeferred()`
256 @*/
257 PetscErrorCode PetscViewerVUPrintDeferred(PetscViewer viewer, const char format[], ...)
258 {
259   PetscViewer_VU *vu = (PetscViewer_VU *)viewer->data;
260   va_list         Argp;
261   size_t          fullLength;
262   PrintfQueue     next;
263 
264   PetscFunctionBegin;
265   PetscCall(PetscNew(&next));
266   if (vu->queue) {
267     vu->queue->next = next;
268     vu->queue       = next;
269     vu->queue->next = NULL;
270   } else {
271     vu->queueBase = vu->queue = next;
272   }
273   vu->queueLength++;
274 
275   va_start(Argp, format);
276   PetscCall(PetscArrayzero(next->string, QUEUESTRINGSIZE));
277   PetscCall(PetscVSNPrintf(next->string, QUEUESTRINGSIZE, format, &fullLength, Argp));
278   va_end(Argp);
279   PetscFunctionReturn(PETSC_SUCCESS);
280 }
281 
282 /*@C
283   PetscViewerVUFlushDeferred - Flushes the deferred write cache to the file.
284 
285   Not Collective
286 
287   Input Parameter:
288 . viewer - The `PETSCVIEWERVU` `PetscViewer`
289 
290   Level: intermediate
291 
292 .seealso: [](sec_viewers), `PETSCVIEWERVU`, `PetscViewerVUPrintDeferred()`
293 @*/
294 PetscErrorCode PetscViewerVUFlushDeferred(PetscViewer viewer)
295 {
296   PetscViewer_VU *vu   = (PetscViewer_VU *)viewer->data;
297   PrintfQueue     next = vu->queueBase;
298   PrintfQueue     previous;
299   int             i;
300 
301   PetscFunctionBegin;
302   for (i = 0; i < vu->queueLength; i++) {
303     PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)viewer), vu->fd, "%s", next->string));
304     previous = next;
305     next     = next->next;
306     PetscCall(PetscFree(previous));
307   }
308   vu->queue       = NULL;
309   vu->queueLength = 0;
310   PetscFunctionReturn(PETSC_SUCCESS);
311 }
312