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