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