xref: /petsc/src/sys/classes/viewer/impls/ascii/vcreatea.c (revision ceaaa4989964adb3f5eb130cb04b8f49c83e49c9)
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 PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelViewer(MPI_Comm comm, PetscMPIInt keyval, void *attr_val, void *extra_state)
173 {
174   PetscFunctionBegin;
175   PetscCallMPI(PetscInfo(NULL, "Removing viewer data attribute in an MPI_Comm %ld\n", (long)comm));
176   PetscFunctionReturn(MPI_SUCCESS);
177 }
178 
179 /*@C
180   PetscViewerASCIIOpen - Opens an ASCII file for writing as a `PETSCVIEWERASCII` `PetscViewer`.
181 
182   Collective
183 
184   Input Parameters:
185 + comm - the communicator
186 - name - the file name
187 
188   Output Parameter:
189 . lab - the `PetscViewer` to use with the specified file
190 
191   Level: beginner
192 
193   Notes:
194   To open a ASCII file as a viewer for reading one must use the sequence
195 .vb
196    PetscViewerCreate(comm,&lab);
197    PetscViewerSetType(lab,PETSCVIEWERASCII);
198    PetscViewerFileSetMode(lab,FILE_MODE_READ);
199    PetscViewerFileSetName(lab,name);
200 .ve
201 
202   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`.
203 
204   The MPI communicator used here must match that used by the object one is viewing. For example if the
205   Mat was created with a `PETSC_COMM_WORLD`, then the Viewer must be created with `PETSC_COMM_WORLD`
206 
207   As shown below, `PetscViewerASCIIOpen()` is useful in conjunction with
208   `MatView()` and `VecView()`
209 .vb
210      PetscViewerASCIIOpen(PETSC_COMM_WORLD,"mat.output",&viewer);
211      MatView(matrix,viewer);
212 .ve
213 
214 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIRead()`, `PETSCVIEWERASCII`
215           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
216           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`,
217 @*/
218 PetscErrorCode PetscViewerASCIIOpen(MPI_Comm comm, const char name[], PetscViewer *lab)
219 {
220   PetscViewerLink *vlink, *nv;
221   PetscBool        flg, eq;
222   size_t           len;
223 
224   PetscFunctionBegin;
225   PetscCall(PetscStrlen(name, &len));
226   if (!len) {
227     PetscCall(PetscViewerASCIIGetStdout(comm, lab));
228     PetscCall(PetscObjectReference((PetscObject)*lab));
229     PetscFunctionReturn(PETSC_SUCCESS);
230   }
231   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockOpen));
232   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
233   /*
234        It would be better to move this code to PetscFileSetName() but since it must return a preexiting communicator
235      we cannot do that, since PetscFileSetName() takes a communicator that already exists.
236 
237       Plus if the original communicator that created the file has since been close this will not detect the old
238       communictor and hence will overwrite the old data. It may be better to simply remove all this code
239   */
240   /* make sure communicator is a PETSc communicator */
241   PetscCall(PetscCommDuplicate(comm, &comm, NULL));
242   /* has file already been opened into a viewer */
243   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
244   if (flg) {
245     while (vlink) {
246       PetscCall(PetscStrcmp(name, ((PetscViewer_ASCII *)(vlink->viewer->data))->filename, &eq));
247       if (eq) {
248         PetscCall(PetscObjectReference((PetscObject)vlink->viewer));
249         *lab = vlink->viewer;
250         PetscCall(PetscCommDestroy(&comm));
251         PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
252         PetscFunctionReturn(PETSC_SUCCESS);
253       }
254       vlink = vlink->next;
255     }
256   }
257   PetscCall(PetscViewerCreate(comm, lab));
258   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
259   if (name) PetscCall(PetscViewerFileSetName(*lab, name));
260   /* save viewer into communicator if needed later */
261   PetscCall(PetscNew(&nv));
262   nv->viewer = *lab;
263   if (!flg) {
264     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
265   } else {
266     PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
267     if (vlink) {
268       while (vlink->next) vlink = vlink->next;
269       vlink->next = nv;
270     } else {
271       PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
272     }
273   }
274   PetscCall(PetscCommDestroy(&comm));
275   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
276   PetscFunctionReturn(PETSC_SUCCESS);
277 }
278 
279 /*@C
280   PetscViewerASCIIOpenWithFILE - Given an open file creates an `PETSCVIEWERASCII` viewer that prints to it.
281 
282   Collective
283 
284   Input Parameters:
285 + comm - the communicator
286 - fd   - the `FILE` pointer
287 
288   Output Parameter:
289 . lab - the `PetscViewer` to use with the specified file
290 
291   Level: beginner
292 
293   Notes:
294   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the fd will NOT be closed.
295 
296   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
297   then only the first processor in the group uses the file.  All other
298   processors send their data to the first processor to print.
299 
300   Fortran Notes:
301   Use `PetscViewerASCIIOpenWithFileUnit()`
302 
303 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIOpenWithFileUnit()`,
304           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
305           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`
306 @*/
307 PetscErrorCode PetscViewerASCIIOpenWithFILE(MPI_Comm comm, FILE *fd, PetscViewer *lab)
308 {
309   PetscFunctionBegin;
310   PetscCall(PetscViewerCreate(comm, lab));
311   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
312   PetscCall(PetscViewerASCIISetFILE(*lab, fd));
313   PetscFunctionReturn(PETSC_SUCCESS);
314 }
315 
316 /*@C
317   PetscViewerASCIISetFILE - Given an open file sets the `PETSCVIEWERASCII` viewer to use the file for output
318 
319   Not Collective
320 
321   Input Parameters:
322 + viewer - the `PetscViewer` to use with the specified file
323 - fd     - the `FILE` pointer
324 
325   Level: beginner
326 
327   Notes:
328   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the `fd` will NOT be closed.
329 
330   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
331   then only the first processor in the group uses the file.  All other
332   processors send their data to the first processor to print.
333 
334   Fortran Notes:
335   Use `PetscViewerASCIISetFileUnit()`
336 
337 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIISetFileUnit()`,
338           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
339           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIIOpenWithFILE()`, `PETSCVIEWERASCII`
340 @*/
341 PetscErrorCode PetscViewerASCIISetFILE(PetscViewer viewer, FILE *fd)
342 {
343   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
344 
345   PetscFunctionBegin;
346   vascii->fd        = fd;
347   vascii->closefile = PETSC_FALSE;
348   PetscFunctionReturn(PETSC_SUCCESS);
349 }
350