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