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