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