xref: /petsc/src/sys/classes/viewer/impls/ascii/vcreatea.c (revision df4cd43f92eaa320656440c40edb1046daee8f75)
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 ASCII `PetscViewer` shared by all processors
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 processors
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 processors
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 `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 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`,
295           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
296           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`
297 @*/
298 PetscErrorCode PetscViewerASCIIOpenWithFILE(MPI_Comm comm, FILE *fd, PetscViewer *lab)
299 {
300   PetscFunctionBegin;
301   PetscCall(PetscViewerCreate(comm, lab));
302   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
303   PetscCall(PetscViewerASCIISetFILE(*lab, fd));
304   PetscFunctionReturn(PETSC_SUCCESS);
305 }
306 
307 /*@C
308    PetscViewerASCIISetFILE - Given an open file sets the `PETSCVIEWERASCII` viewer to use the file for output
309 
310    Not collective
311 
312    Input Parameters:
313 +  viewer - the `PetscViewer` to use with the specified file
314 -  fd - the FILE pointer
315 
316    Level: beginner
317 
318    Notes:
319    This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the fd will NOT be closed.
320 
321    If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
322    then only the first processor in the group uses the file.  All other
323    processors send their data to the first processor to print.
324 
325 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`,
326           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
327           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIIOpenWithFILE()`, `PETSCVIEWERASCII`
328 @*/
329 PetscErrorCode PetscViewerASCIISetFILE(PetscViewer viewer, FILE *fd)
330 {
331   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
332 
333   PetscFunctionBegin;
334   vascii->fd        = fd;
335   vascii->closefile = PETSC_FALSE;
336   PetscFunctionReturn(PETSC_SUCCESS);
337 }
338