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