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