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