xref: /petsc/src/sys/classes/viewer/impls/ascii/vcreatea.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795) !
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 ASCII 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    Notes:
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 @*/
30 PetscErrorCode PetscViewerASCIIGetStdout(MPI_Comm comm, PetscViewer *viewer) {
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    Notes:
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 @*/
69 PetscViewer PETSC_VIEWER_STDOUT_(MPI_Comm comm) {
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 ASCII 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    Notes:
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 @*/
108 PetscErrorCode PetscViewerASCIIGetStderr(MPI_Comm comm, PetscViewer *viewer) {
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 ASCII 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   PetscErrorCode ierr;
148   PetscViewer    viewer;
149 
150   PetscFunctionBegin;
151   ierr = PetscViewerASCIIGetStderr(comm, &viewer);
152   if (ierr) {
153     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_STDERR_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
154     PetscFunctionReturn(NULL);
155   }
156   PetscFunctionReturn(viewer);
157 }
158 
159 PetscMPIInt                     Petsc_Viewer_keyval = MPI_KEYVAL_INVALID;
160 /*
161    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
162    PetscObjectDestroyRegisterAll(). PetscViewerASCIIGetStdout() registers the viewer with PetscObjectDestroyRegister() to be destroyed when PetscFinalize() is called.
163 
164   This is called by MPI, not by users.
165 
166 */
167 PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelViewer(MPI_Comm comm, PetscMPIInt keyval, void *attr_val, void *extra_state) {
168   PetscFunctionBegin;
169   PetscCallMPI(PetscInfo(NULL, "Removing viewer data attribute in an MPI_Comm %ld\n", (long)comm));
170   PetscFunctionReturn(MPI_SUCCESS);
171 }
172 
173 /*@C
174    PetscViewerASCIIOpen - Opens an ASCII file for writing as a PetscViewer.
175 
176    Collective
177 
178    Input Parameters:
179 +  comm - the communicator
180 -  name - the file name
181 
182    Output Parameter:
183 .  lab - the PetscViewer to use with the specified file
184 
185    Level: beginner
186 
187    Notes:
188    To open a ASCII file as a viewer for reading one must use the sequence
189 $     PetscViewerCreate(comm,&lab);
190 $     PetscViewerSetType(lab,PETSCVIEWERASCII);
191 $     PetscViewerFileSetMode(lab,FILE_MODE_READ);
192 $     PetscViewerFileSetName(lab,name);
193 
194    This PetscViewer can be destroyed with PetscViewerDestroy().
195 
196    The MPI communicator used here must match that used by the object one is viewing. For example if the
197    Mat was created with a PETSC_COMM_WORLD, then the Viewer must be created with PETSC_COMM_WORLD
198 
199    As shown below, PetscViewerASCIIOpen() is useful in conjunction with
200    MatView() and VecView()
201 .vb
202      PetscViewerASCIIOpen(PETSC_COMM_WORLD,"mat.output",&viewer);
203      MatView(matrix,viewer);
204 .ve
205 
206 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`, `PetscViewerASCIIRead()`
207           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
208           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`,
209 @*/
210 PetscErrorCode PetscViewerASCIIOpen(MPI_Comm comm, const char name[], PetscViewer *lab) {
211   PetscViewerLink *vlink, *nv;
212   PetscBool        flg, eq;
213   size_t           len;
214 
215   PetscFunctionBegin;
216   PetscCall(PetscStrlen(name, &len));
217   if (!len) {
218     PetscCall(PetscViewerASCIIGetStdout(comm, lab));
219     PetscCall(PetscObjectReference((PetscObject)*lab));
220     PetscFunctionReturn(0);
221   }
222   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockOpen));
223   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
224   /*
225        It would be better to move this code to PetscFileSetName() but since it must return a preexiting communicator
226      we cannot do that, since PetscFileSetName() takes a communicator that already exists.
227 
228       Plus if the original communicator that created the file has since been close this will not detect the old
229       communictor and hence will overwrite the old data. It may be better to simply remove all this code
230   */
231   /* make sure communicator is a PETSc communicator */
232   PetscCall(PetscCommDuplicate(comm, &comm, NULL));
233   /* has file already been opened into a viewer */
234   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
235   if (flg) {
236     while (vlink) {
237       PetscCall(PetscStrcmp(name, ((PetscViewer_ASCII *)(vlink->viewer->data))->filename, &eq));
238       if (eq) {
239         PetscCall(PetscObjectReference((PetscObject)vlink->viewer));
240         *lab = vlink->viewer;
241         PetscCall(PetscCommDestroy(&comm));
242         PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
243         PetscFunctionReturn(0);
244       }
245       vlink = vlink->next;
246     }
247   }
248   PetscCall(PetscViewerCreate(comm, lab));
249   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
250   if (name) PetscCall(PetscViewerFileSetName(*lab, name));
251   /* save viewer into communicator if needed later */
252   PetscCall(PetscNew(&nv));
253   nv->viewer = *lab;
254   if (!flg) {
255     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
256   } else {
257     PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
258     if (vlink) {
259       while (vlink->next) vlink = vlink->next;
260       vlink->next = nv;
261     } else {
262       PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Viewer_keyval, nv));
263     }
264   }
265   PetscCall(PetscCommDestroy(&comm));
266   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockOpen));
267   PetscFunctionReturn(0);
268 }
269 
270 /*@C
271    PetscViewerASCIIOpenWithFILE - Given an open file creates an ASCII viewer that prints to it.
272 
273    Collective
274 
275    Input Parameters:
276 +  comm - the communicator
277 -  fd - the FILE pointer
278 
279    Output Parameter:
280 .  lab - the PetscViewer to use with the specified file
281 
282    Level: beginner
283 
284    Notes:
285    This PetscViewer can be destroyed with PetscViewerDestroy(), but the fd will NOT be closed.
286 
287    If a multiprocessor communicator is used (such as PETSC_COMM_WORLD),
288    then only the first processor in the group uses the file.  All other
289    processors send their data to the first processor to print.
290 
291 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerBinaryOpen()`,
292           `PetscViewerASCIIGetPointer()`, `PetscViewerPushFormat()`, `PETSC_VIEWER_STDOUT_`, `PETSC_VIEWER_STDERR_`,
293           `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF`, `PetscViewerASCIIOpen()`
294 @*/
295 PetscErrorCode PetscViewerASCIIOpenWithFILE(MPI_Comm comm, FILE *fd, PetscViewer *lab) {
296   PetscFunctionBegin;
297   PetscCall(PetscViewerCreate(comm, lab));
298   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERASCII));
299   PetscCall(PetscViewerASCIISetFILE(*lab, fd));
300   PetscFunctionReturn(0);
301 }
302 
303 PetscErrorCode PetscViewerASCIISetFILE(PetscViewer viewer, FILE *fd) {
304   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
305 
306   PetscFunctionBegin;
307   vascii->fd        = fd;
308   vascii->closefile = PETSC_FALSE;
309   PetscFunctionReturn(0);
310 }
311