xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 8886ffe3e22d8c354eeb44a60666f206b8239e38)
1 
2 #include <petscsys.h>
3 
4 #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
5 /* Some systems have inconsistent include files that use but do not
6    ensure that the following definitions are made */
7 typedef unsigned char   u_char;
8 typedef unsigned short  u_short;
9 typedef unsigned short  ushort;
10 typedef unsigned int    u_int;
11 typedef unsigned long   u_long;
12 #endif
13 
14 #include <errno.h>
15 #include <ctype.h>
16 #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
17 #include <machine/endian.h>
18 #endif
19 #if defined(PETSC_HAVE_UNISTD_H)
20 #include <unistd.h>
21 #endif
22 #if defined(PETSC_HAVE_SYS_SOCKET_H)
23 #include <sys/socket.h>
24 #endif
25 #if defined(PETSC_HAVE_SYS_WAIT_H)
26 #include <sys/wait.h>
27 #endif
28 #if defined(PETSC_HAVE_NETINET_IN_H)
29 #include <netinet/in.h>
30 #endif
31 #if defined(PETSC_HAVE_NETDB_H)
32 #include <netdb.h>
33 #endif
34 #if defined(PETSC_HAVE_FCNTL_H)
35 #include <fcntl.h>
36 #endif
37 #if defined(PETSC_HAVE_IO_H)
38 #include <io.h>
39 #endif
40 #if defined(PETSC_HAVE_WINSOCK2_H)
41 #include <Winsock2.h>
42 #endif
43 #include <sys/stat.h>
44 #include <../src/sys/classes/viewer/impls/socket/socket.h>
45 
46 #if defined(PETSC_NEED_CLOSE_PROTO)
47 PETSC_EXTERN int close(int);
48 #endif
49 #if defined(PETSC_NEED_SOCKET_PROTO)
50 PETSC_EXTERN int socket(int,int,int);
51 #endif
52 #if defined(PETSC_NEED_SLEEP_PROTO)
53 PETSC_EXTERN int sleep(unsigned);
54 #endif
55 #if defined(PETSC_NEED_CONNECT_PROTO)
56 PETSC_EXTERN int connect(int,struct sockaddr*,int);
57 #endif
58 
59 /*--------------------------------------------------------------*/
60 #undef __FUNCT__
61 #define __FUNCT__ "PetscViewerDestroy_Socket"
62 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
63 {
64   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
65   PetscErrorCode     ierr;
66 
67   PetscFunctionBegin;
68   if (vmatlab->port) {
69 #if defined(PETSC_HAVE_CLOSESOCKET)
70     ierr = closesocket(vmatlab->port);
71 #else
72     ierr = close(vmatlab->port);
73 #endif
74     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
75   }
76   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
77   PetscFunctionReturn(0);
78 }
79 
80 /*--------------------------------------------------------------*/
81 #undef __FUNCT__
82 #define __FUNCT__ "PetscOpenSocket"
83 /*
84     PetscSocketOpen - handles connected to an open port where someone is waiting.
85 
86 .seealso:   PetscSocketListen(), PetscSocketEstablish()
87 */
88 PetscErrorCode  PetscOpenSocket(const char hostname[],int portnum,int *t)
89 {
90   struct sockaddr_in sa;
91   struct hostent     *hp;
92   int                s = 0;
93   PetscErrorCode     ierr;
94   PetscBool          flg = PETSC_TRUE;
95   static int         refcnt = 0;
96 
97   PetscFunctionBegin;
98   if (!(hp=gethostbyname(hostname))) {
99     perror("SEND: error gethostbyname: ");
100     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
101   }
102   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
103   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
104 
105   sa.sin_family = hp->h_addrtype;
106   sa.sin_port   = htons((u_short) portnum);
107   while (flg) {
108     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
109       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
110     }
111     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
112 #if defined(PETSC_HAVE_WSAGETLASTERROR)
113       ierr = WSAGetLastError();
114       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
115       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
116       else if (ierr == WSAEISCONN) {
117         (*PetscErrorPrintf)("SEND: socket already connected\n");
118         Sleep((unsigned) 1);
119       } else if (ierr == WSAECONNREFUSED) {
120         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
121         Sleep((unsigned) 1);
122       } else {
123         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
124       }
125 #else
126       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
127       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
128       else if (errno == EISCONN) {
129         (*PetscErrorPrintf)("SEND: socket already connected\n");
130         sleep((unsigned) 1);
131       } else if (errno == ECONNREFUSED) {
132         refcnt++;
133         if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum);
134         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again\n");CHKERRQ(ierr);
135         sleep((unsigned) 1);
136       } else {
137         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
138       }
139 #endif
140       flg = PETSC_TRUE;
141 #if defined(PETSC_HAVE_CLOSESOCKET)
142       closesocket(s);
143 #else
144       close(s);
145 #endif
146     } else flg = PETSC_FALSE;
147   }
148   *t = s;
149   PetscFunctionReturn(0);
150 }
151 
152 #define MAXHOSTNAME 100
153 #undef __FUNCT__
154 #define __FUNCT__ "PetscSocketEstablish"
155 /*
156    PetscSocketEstablish - starts a listener on a socket
157 
158 .seealso:   PetscSocketListen()
159 */
160 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
161 {
162   char               myname[MAXHOSTNAME+1];
163   int                s;
164   PetscErrorCode     ierr;
165   struct sockaddr_in sa;
166   struct hostent     *hp;
167 
168   PetscFunctionBegin;
169   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
170 
171   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
172 
173   hp = gethostbyname(myname);
174   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
175 
176   sa.sin_family = hp->h_addrtype;
177   sa.sin_port   = htons((u_short)portnum);
178 
179   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
180 #if defined(PETSC_HAVE_SO_REUSEADDR)
181   {
182     int optval = 1; /* Turn on the option */
183     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
184   }
185 #endif
186 
187   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
188 #if defined(PETSC_HAVE_WSAGETLASTERROR)
189     ierr = WSAGetLastError();
190     if (ierr != WSAEADDRINUSE) {
191 #else
192     if (errno != EADDRINUSE) {
193 #endif
194       close(s);
195       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
196     }
197   }
198   listen(s,0);
199   *ss = s;
200   return(0);
201 }
202 
203 #undef __FUNCT__
204 #define __FUNCT__ "PetscSocketListen"
205 /*
206    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()
207 
208 .seealso:   PetscSocketEstablish()
209 */
210 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
211 {
212   struct sockaddr_in isa;
213 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
214   size_t             i;
215 #else
216   int                i;
217 #endif
218 
219   PetscFunctionBegin;
220   /* wait for someone to try to connect */
221   i = sizeof(struct sockaddr_in);
222   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
223   PetscFunctionReturn(0);
224 }
225 
226 #undef __FUNCT__
227 #define __FUNCT__ "PetscViewerSocketOpen"
228 /*@C
229    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
230 
231    Collective on MPI_Comm
232 
233    Input Parameters:
234 +  comm - the MPI communicator
235 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
236              a connection from elsewhere
237 -  port - the port to connect to, use PETSC_DEFAULT for the default
238 
239    Output Parameter:
240 .  lab - a context to use when communicating with the server
241 
242    Level: intermediate
243 
244    Notes:
245    Most users should employ the following commands to access the
246    MATLAB PetscViewers
247 $
248 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
249 $    MatView(Mat matrix,PetscViewer viewer)
250 $
251 $                or
252 $
253 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
254 $    VecView(Vec vector,PetscViewer viewer)
255 
256    Options Database Keys:
257    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
258    PETSC_VIEWER_SOCKET_() or if
259     NULL is passed for machine or PETSC_DEFAULT is passed for port
260 $    -viewer_socket_machine <machine>
261 $    -viewer_socket_port <port>
262 
263    Environmental variables:
264 +   PETSC_VIEWER_SOCKET_PORT portnumber
265 -   PETSC_VIEWER_SOCKET_MACHINE machine name
266 
267      Currently the only socket client available is MATLAB. See
268      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
269 
270    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
271           use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().
272 
273      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
274      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
275      for communicating with a MATLAB Engine
276 
277    Concepts: MATLAB^sending data
278    Concepts: sockets^sending data
279 
280 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
281           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
282           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
283           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
284 @*/
285 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
286 {
287   PetscErrorCode ierr;
288 
289   PetscFunctionBegin;
290   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
291   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
292   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
293   PetscFunctionReturn(0);
294 }
295 
296 #undef __FUNCT__
297 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
298 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
299 {
300   PetscErrorCode ierr;
301   PetscInt       def = -1;
302   char           sdef[256];
303   PetscBool      tflg;
304 
305   PetscFunctionBegin;
306   /*
307        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
308     are listed here for the GUI to display
309   */
310   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
311   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
312   if (tflg) {
313     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
314   } else def = PETSCSOCKETDEFAULTPORT;
315   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
316 
317   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
318   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
319   if (!tflg) {
320     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
321   }
322   ierr = PetscOptionsTail();CHKERRQ(ierr);
323   PetscFunctionReturn(0);
324 }
325 
326 #undef __FUNCT__
327 #define __FUNCT__ "PetscViewerCreate_Socket"
328 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
329 {
330   PetscViewer_Socket *vmatlab;
331   PetscErrorCode     ierr;
332 
333   PetscFunctionBegin;
334   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
335   vmatlab->port          = 0;
336   v->data                = (void*)vmatlab;
337   v->ops->destroy        = PetscViewerDestroy_Socket;
338   v->ops->flush          = 0;
339   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
340 
341   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
342   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "PetscViewerSocketSetConnection"
348 /*@C
349       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
350              viewer is to use
351 
352   Logically Collective on PetscViewer
353 
354   Input Parameters:
355 +   v - viewer to connect
356 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
357              a connection from elsewhere
358 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
359 
360     Level: advanced
361 
362 .seealso: PetscViewerSocketOpen()
363 @*/
364 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
365 {
366   PetscErrorCode     ierr;
367   PetscMPIInt        rank;
368   char               mach[256];
369   PetscBool          tflg;
370   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
371 
372   PetscFunctionBegin;
373   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
374   if (port <= 0) {
375     char portn[16];
376     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
377     if (tflg) {
378       PetscInt pport;
379       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
380       port = (int)pport;
381     } else port = PETSCSOCKETDEFAULTPORT;
382   }
383   if (!machine) {
384     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
385     if (!tflg) {
386       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
387     }
388   } else {
389     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
390   }
391 
392   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
393   if (!rank) {
394     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
395     if (tflg) {
396       int listenport;
397       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
398       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
399       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
400       close(listenport);
401     } else {
402       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
403       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
404     }
405   }
406   PetscFunctionReturn(0);
407 }
408 
409 /* ---------------------------------------------------------------------*/
410 /*
411     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
412   is attached to a communicator, in this case the attribute is a PetscViewer.
413 */
414 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
415 
416 
417 #undef __FUNCT__
418 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
419 /*@C
420      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
421 
422      Collective on MPI_Comm
423 
424      Input Parameter:
425 .    comm - the MPI communicator to share the socket PetscViewer
426 
427      Level: intermediate
428 
429    Options Database Keys:
430    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
431     NULL is passed for machine or PETSC_DEFAULT is passed for port
432 $    -viewer_socket_machine <machine>
433 $    -viewer_socket_port <port>
434 
435    Environmental variables:
436 +   PETSC_VIEWER_SOCKET_PORT portnumber
437 -   PETSC_VIEWER_SOCKET_MACHINE machine name
438 
439      Notes:
440      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
441      an error code.  The socket PetscViewer is usually used in the form
442 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
443 
444      Currently the only socket client available is MATLAB. See
445      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
446 
447      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
448 
449      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
450      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
451      for communicating with a MATLAB Engine
452 
453 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
454           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
455           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
456 @*/
457 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
458 {
459   PetscErrorCode ierr;
460   PetscBool      flg;
461   PetscViewer    viewer;
462   MPI_Comm       ncomm;
463 
464   PetscFunctionBegin;
465   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
466   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
467     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
468     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
469   }
470   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
471   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
472   if (!flg) { /* PetscViewer not yet created */
473     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
474     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
475     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
476     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
477     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
478     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
479   }
480   ierr = PetscCommDestroy(&ncomm);
481   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
482   PetscFunctionReturn(viewer);
483 }
484 
485