xref: /petsc/src/sys/classes/viewer/impls/ascii/vcreatea.c (revision 3df6fe7bb68c28049dcc48161db5df4684fa05c1)
1 
2 #include <../src/sys/classes/viewer/impls/ascii/asciiimpl.h> /*I     "petscviewer.h"   I*/
3 
4 /*
5     The variable Petsc_Viewer_Stdout_keyval is used to indicate an MPI attribute that
6   is attached to a communicator, in this case the attribute is a PetscViewer.
7 */
8 PetscMPIInt Petsc_Viewer_Stdout_keyval = MPI_KEYVAL_INVALID;
9 
10 /*@
11   PetscViewerASCIIGetStdout - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all processors
12   in a communicator. Error returning version of `PETSC_VIEWER_STDOUT_()`
13 
14   Collective
15 
16   Input Parameter:
17 . comm - the MPI communicator to share the `PetscViewer`
18 
19   Output Parameter:
20 . viewer - the viewer
21 
22   Level: beginner
23 
24   Note:
25   This should be used in all PETSc source code instead of `PETSC_VIEWER_STDOUT_()` since it allows error checking
26 
27 .seealso: [](sec_viewers), `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDOUT_WORLD`,
28           `PETSC_VIEWER_STDOUT_SELF`
29 @*/
30 PetscErrorCode PetscViewerASCIIGetStdout(MPI_Comm comm, PetscViewer *viewer)
31 {
32   PetscBool flg;
33   MPI_Comm  ncomm;
34 
35   PetscFunctionBegin;
36   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockStdout));
37   PetscCall(PetscCommDuplicate(comm, &ncomm, NULL));
38   if (Petsc_Viewer_Stdout_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Stdout_keyval, NULL));
39   PetscCallMPI(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void **)viewer, (PetscMPIInt *)&flg));
40   if (!flg) { /* PetscViewer not yet created */
41     PetscCall(PetscViewerASCIIOpen(ncomm, "stdout", viewer));
42     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
43     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void *)*viewer));
44   }
45   PetscCall(PetscCommDestroy(&ncomm));
46   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStdout));
47   PetscFunctionReturn(PETSC_SUCCESS);
48 }
49 
50 /*@C
51    PETSC_VIEWER_STDOUT_ - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all MPI processes
52                     in a communicator.
53 
54    Collective
55 
56    Input Parameter:
57 .  comm - the MPI communicator to share the `PetscViewer`
58 
59    Level: beginner
60 
61    Note:
62    Unlike almost all other PETSc routines, this does not return
63    an error code. Usually used in the form
64 $      XXXView(XXX object, PETSC_VIEWER_STDOUT_(comm));
65 
66 .seealso: [](sec_viewers), `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDOUT_WORLD`,
67           `PETSC_VIEWER_STDOUT_SELF`
68 @*/
69 PetscViewer PETSC_VIEWER_STDOUT_(MPI_Comm comm)
70 {
71   PetscErrorCode ierr;
72   PetscViewer    viewer;
73 
74   PetscFunctionBegin;
75   ierr = PetscViewerASCIIGetStdout(comm, &viewer);
76   if (ierr) {
77     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_STDOUT_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
78     PetscFunctionReturn(NULL);
79   }
80   PetscFunctionReturn(viewer);
81 }
82 
83 /*
84     The variable Petsc_Viewer_Stderr_keyval is used to indicate an MPI attribute that
85   is attached to a communicator, in this case the attribute is a PetscViewer.
86 */
87 PetscMPIInt Petsc_Viewer_Stderr_keyval = MPI_KEYVAL_INVALID;
88 
89 /*@
90   PetscViewerASCIIGetStderr - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all MPI processes
91   in a communicator. Error returning version of `PETSC_VIEWER_STDERR_()`
92 
93   Collective
94 
95   Input Parameter:
96 . comm - the MPI communicator to share the `PetscViewer`
97 
98   Output Parameter:
99 . viewer - the viewer
100 
101   Level: beginner
102 
103   Note:
104   This should be used in all PETSc source code instead of `PETSC_VIEWER_STDERR_()` since it allows error checking
105 
106 .seealso: [](sec_viewers), `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDERR_WORLD`,
107           `PETSC_VIEWER_STDERR_SELF`
108 @*/
109 PetscErrorCode PetscViewerASCIIGetStderr(MPI_Comm comm, PetscViewer *viewer)
110 {
111   PetscBool flg;
112   MPI_Comm  ncomm;
113 
114   PetscFunctionBegin;
115   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockStderr));
116   PetscCall(PetscCommDuplicate(comm, &ncomm, NULL));
117   if (Petsc_Viewer_Stderr_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Stderr_keyval, NULL));
118   PetscCallMPI(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Stderr_keyval, (void **)viewer, (PetscMPIInt *)&flg));
119   if (!flg) { /* PetscViewer not yet created */
120     PetscCall(PetscViewerASCIIOpen(ncomm, "stderr", viewer));
121     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
122     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stderr_keyval, (void *)*viewer));
123   }
124   PetscCall(PetscCommDestroy(&ncomm));
125   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStderr));
126   PetscFunctionReturn(PETSC_SUCCESS);
127 }
128 
129 /*@C
130    PETSC_VIEWER_STDERR_ - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all MPI processes
131                     in a communicator.
132 
133    Collective
134 
135    Input Parameter:
136 .  comm - the MPI communicator to share the `PetscViewer`
137 
138    Level: beginner
139 
140    Notes:
141    Unlike almost all other PETSc routines, this does not return
142    an error code. Usually used in the form
143 $      XXXView(XXX object, PETSC_VIEWER_STDERR_(comm));
144 
145    `PetscViewerASCIIGetStderr()` is preferred  since it allows error checking
146 
147 .seealso: [](sec_viewers), `PETSC_VIEWER_DRAW_`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDOUT_WORLD`,
148           `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDERR_WORLD`, `PETSC_VIEWER_STDERR_SELF`
149 @*/
150 PetscViewer PETSC_VIEWER_STDERR_(MPI_Comm comm)
151 {
152   PetscErrorCode ierr;
153   PetscViewer    viewer;
154 
155   PetscFunctionBegin;
156   ierr = PetscViewerASCIIGetStderr(comm, &viewer);
157   if (ierr) {
158     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_STDERR_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
159     PetscFunctionReturn(NULL);
160   }
161   PetscFunctionReturn(viewer);
162 }
163 
164 PetscMPIInt Petsc_Viewer_keyval = MPI_KEYVAL_INVALID;
165 /*
166    Called with MPI_Comm_free() is called on a communicator that has a viewer as an attribute. The viewer is not actually destroyed
167    because that is managed by PetscObjectDestroyRegisterAll(). PetscViewerASCIIGetStdout() registers the viewer with PetscObjectDestroyRegister() to be destroyed when PetscFinalize() is called.
168 
169   This is called by MPI, not by users.
170 
171 */
172 PetscMPIInt MPIAPI Petsc_DelViewer(MPI_Comm comm, PetscMPIInt keyval, void *attr_val, void *extra_state)
173 {
174   PetscFunctionBegin;
175   (void)keyval;
176   (void)attr_val;
177   (void)extra_state;
178   PetscCallMPI(PetscInfo(NULL, "Removing viewer data attribute in an MPI_Comm %" PETSC_INTPTR_T_FMT "\n", (PETSC_INTPTR_T)comm));
179   PetscFunctionReturn(MPI_SUCCESS);
180 }
181 
182 /*@C
183   PetscViewerASCIIOpen - Opens an ASCII file for writing as a `PETSCVIEWERASCII` `PetscViewer`.
184 
185   Collective
186 
187   Input Parameters:
188 + comm - the communicator
189 - name - the file name
190 
191   Output Parameter:
192 . lab - the `PetscViewer` to use with the specified file
193 
194   Level: beginner
195 
196   Notes:
197   To open a ASCII file as a viewer for reading one must use the sequence
198 .vb
199    PetscViewerCreate(comm,&lab);
200    PetscViewerSetType(lab,PETSCVIEWERASCII);
201    PetscViewerFileSetMode(lab,FILE_MODE_READ);
202    PetscViewerFileSetName(lab,name);
203 .ve
204 
205   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`.
206 
207   The MPI communicator used here must match that used by the object one is viewing. For example if the
208   Mat was created with a `PETSC_COMM_WORLD`, then the Viewer must be created with `PETSC_COMM_WORLD`
209 
210   As shown below, `PetscViewerASCIIOpen()` is useful in conjunction with
211   `MatView()` and `VecView()`
212 .vb
213      PetscViewerASCIIOpen(PETSC_COMM_WORLD,"mat.output",&viewer);
214      MatView(matrix,viewer);
215 .ve
216 
217 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIRead()`, `PETSCVIEWERASCII`
218           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
219           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`,
220 @*/
221 PetscErrorCode PetscViewerASCIIOpen(MPI_Comm comm, const char name[], PetscViewer *lab)
222 {
223   PetscViewerLink *vlink, *nv;
224   PetscBool        flg, eq;
225   size_t           len;
226 
227   PetscFunctionBegin;
228   PetscCall(PetscStrlen(name, &len));
229   if (!len) {
230     PetscCall(PetscViewerASCIIGetStdout(comm, lab));
231     PetscCall(PetscObjectReference((PetscObject)*lab));
232     PetscFunctionReturn(PETSC_SUCCESS);
233   }
234   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockOpen));
235   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
236   /*
237        It would be better to move this code to PetscFileSetName() but since it must return a preexiting communicator
238      we cannot do that, since PetscFileSetName() takes a communicator that already exists.
239 
240       Plus if the original communicator that created the file has since been close this will not detect the old
241       communictor and hence will overwrite the old data. It may be better to simply remove all this code
242   */
243   /* make sure communicator is a PETSc communicator */
244   PetscCall(PetscCommDuplicate(comm, &comm, NULL));
245   /* has file already been opened into a viewer */
246   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
247   if (flg) {
248     while (vlink) {
249       PetscCall(PetscStrcmp(name, ((PetscViewer_ASCII *)(vlink->viewer->data))->filename, &eq));
250       if (eq) {
251         PetscCall(PetscObjectReference((PetscObject)vlink->viewer));
252         *lab = vlink->viewer;
253         PetscCall(PetscCommDestroy(&comm));
254         PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
255         PetscFunctionReturn(PETSC_SUCCESS);
256       }
257       vlink = vlink->next;
258     }
259   }
260   PetscCall(PetscViewerCreate(comm, lab));
261   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
262   if (name) PetscCall(PetscViewerFileSetName(*lab, name));
263   /* save viewer into communicator if needed later */
264   PetscCall(PetscNew(&nv));
265   nv->viewer = *lab;
266   if (!flg) {
267     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
268   } else {
269     PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
270     if (vlink) {
271       while (vlink->next) vlink = vlink->next;
272       vlink->next = nv;
273     } else {
274       PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
275     }
276   }
277   PetscCall(PetscCommDestroy(&comm));
278   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
279   PetscFunctionReturn(PETSC_SUCCESS);
280 }
281 
282 /*@C
283   PetscViewerASCIIOpenWithFILE - Given an open file creates an `PETSCVIEWERASCII` viewer that prints to it.
284 
285   Collective
286 
287   Input Parameters:
288 + comm - the communicator
289 - fd   - the `FILE` pointer
290 
291   Output Parameter:
292 . lab - the `PetscViewer` to use with the specified file
293 
294   Level: beginner
295 
296   Notes:
297   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the fd will NOT be closed.
298 
299   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
300   then only the first processor in the group uses the file.  All other
301   processors send their data to the first processor to print.
302 
303   Fortran Notes:
304   Use `PetscViewerASCIIOpenWithFileUnit()`
305 
306 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIOpenWithFileUnit()`,
307           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
308           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`
309 @*/
310 PetscErrorCode PetscViewerASCIIOpenWithFILE(MPI_Comm comm, FILE *fd, PetscViewer *lab)
311 {
312   PetscFunctionBegin;
313   PetscCall(PetscViewerCreate(comm, lab));
314   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
315   PetscCall(PetscViewerASCIISetFILE(*lab, fd));
316   PetscFunctionReturn(PETSC_SUCCESS);
317 }
318 
319 /*@C
320   PetscViewerASCIISetFILE - Given an open file sets the `PETSCVIEWERASCII` viewer to use the file for output
321 
322   Not Collective
323 
324   Input Parameters:
325 + viewer - the `PetscViewer` to use with the specified file
326 - fd     - the `FILE` pointer
327 
328   Level: beginner
329 
330   Notes:
331   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the `fd` will NOT be closed.
332 
333   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
334   then only the first processor in the group uses the file.  All other
335   processors send their data to the first processor to print.
336 
337   Fortran Notes:
338   Use `PetscViewerASCIISetFileUnit()`
339 
340 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIISetFileUnit()`,
341           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
342           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIIOpenWithFILE()`, `PETSCVIEWERASCII`
343 @*/
344 PetscErrorCode PetscViewerASCIISetFILE(PetscViewer viewer, FILE *fd)
345 {
346   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
347 
348   PetscFunctionBegin;
349   vascii->fd        = fd;
350   vascii->closefile = PETSC_FALSE;
351   PetscFunctionReturn(PETSC_SUCCESS);
352 }
353