xref: /petsc/src/sys/classes/viewer/impls/ascii/vcreatea.c (revision 4cc2b5b5fe4ffd09e5956b56d7cdc4f43e324103)
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 /*@
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 . viewer - 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,&viewer);
167    PetscViewerSetType(viewer,PETSCVIEWERASCII);
168    PetscViewerFileSetMode(viewer,FILE_MODE_READ);
169    PetscViewerFileSetName(viewer,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 *viewer)
189 {
190   PetscViewerLink *vlink, *nv;
191   PetscBool        flg, eq;
192   size_t           len;
193 
194   PetscFunctionBegin;
195   PetscAssertPointer(viewer, 3);
196   PetscCall(PetscStrlen(name, &len));
197   if (!len) {
198     PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
199     PetscCall(PetscObjectReference((PetscObject)*viewer));
200     PetscFunctionReturn(PETSC_SUCCESS);
201   }
202   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockOpen));
203   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
204   /*
205        It would be better to move this code to PetscFileSetName() but since it must return a preexiting communicator
206      we cannot do that, since PetscFileSetName() takes a communicator that already exists.
207 
208       Plus if the original communicator that created the file has since been close this will not detect the old
209       communictor and hence will overwrite the old data. It may be better to simply remove all this code
210   */
211   /* make sure communicator is a PETSc communicator */
212   PetscCall(PetscCommDuplicate(comm, &comm, NULL));
213   /* has file already been opened into a viewer */
214   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
215   if (flg) {
216     while (vlink) {
217       PetscCall(PetscStrcmp(name, ((PetscViewer_ASCII *)vlink->viewer->data)->filename, &eq));
218       if (eq) {
219         PetscCall(PetscObjectReference((PetscObject)vlink->viewer));
220         *viewer = vlink->viewer;
221         PetscCall(PetscCommDestroy(&comm));
222         PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
223         PetscFunctionReturn(PETSC_SUCCESS);
224       }
225       vlink = vlink->next;
226     }
227   }
228   PetscCall(PetscViewerCreate(comm, viewer));
229   PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERASCII));
230   if (name) PetscCall(PetscViewerFileSetName(*viewer, name));
231   /* save viewer into communicator if needed later */
232   PetscCall(PetscNew(&nv));
233   nv->viewer = *viewer;
234   if (!flg) {
235     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
236   } else {
237     PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
238     if (vlink) {
239       while (vlink->next) vlink = vlink->next;
240       vlink->next = nv;
241     } else {
242       PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
243     }
244   }
245   PetscCall(PetscCommDestroy(&comm));
246   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
247   PetscFunctionReturn(PETSC_SUCCESS);
248 }
249 
250 /*@C
251   PetscViewerASCIIOpenWithFILE - Given an open file creates an `PETSCVIEWERASCII` viewer that prints to it.
252 
253   Collective
254 
255   Input Parameters:
256 + comm - the communicator
257 - fd   - the `FILE` pointer
258 
259   Output Parameter:
260 . viewer - the `PetscViewer` to use with the specified file
261 
262   Level: beginner
263 
264   Notes:
265   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the fd will NOT be closed.
266 
267   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
268   then only the first processor in the group uses the file.  All other
269   processors send their data to the first processor to print.
270 
271   Fortran Notes:
272   Use `PetscViewerASCIIOpenWithFileUnit()`
273 
274 .seealso: [](sec_viewers), `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIOpenWithFileUnit()`,
275           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
276           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`
277 @*/
278 PetscErrorCode PetscViewerASCIIOpenWithFILE(MPI_Comm comm, FILE *fd, PetscViewer *viewer)
279 {
280   PetscFunctionBegin;
281   PetscCall(PetscViewerCreate(comm, viewer));
282   PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERASCII));
283   PetscCall(PetscViewerASCIISetFILE(*viewer, fd));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@C
288   PetscViewerASCIISetFILE - Given an open file sets the `PETSCVIEWERASCII` viewer to use the file for output
289 
290   Not Collective
291 
292   Input Parameters:
293 + viewer - the `PetscViewer` to use with the specified file
294 - fd     - the `FILE` pointer
295 
296   Level: beginner
297 
298   Notes:
299   This `PetscViewer` can be destroyed with `PetscViewerDestroy()`, but the `fd` will NOT be closed.
300 
301   If a multiprocessor communicator is used (such as `PETSC_COMM_WORLD`),
302   then only the first processor in the group uses the file.  All other
303   processors send their data to the first processor to print.
304 
305   Fortran Notes:
306   Use `PetscViewerASCIISetFileUnit()`
307 
308 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIISetFileUnit()`,
309           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
310           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`, `PetscViewerASCIIOpenWithFILE()`, `PETSCVIEWERASCII`
311 @*/
312 PetscErrorCode PetscViewerASCIISetFILE(PetscViewer viewer, FILE *fd)
313 {
314   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
315 
316   PetscFunctionBegin;
317   vascii->fd        = fd;
318   vascii->closefile = PETSC_FALSE;
319   PetscFunctionReturn(PETSC_SUCCESS);
320 }
321