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