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