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