xref: /petsc/src/sys/objects/ftn-custom/zstart.c (revision dce8aeba1c9b69b19f651c53d8a6b674bd7e9cbd)
1 /*
2   This file contains Fortran stubs for PetscInitialize and Finalize.
3 */
4 
5 /*
6     This is to prevent the Cray T3D version of MPI (University of Edinburgh)
7   from stupidly redefining MPI_INIT(). They put this in to detect errors
8   in C code,but here I do want to be calling the Fortran version from a
9   C subroutine.
10 */
11 #define T3DMPI_FORTRAN
12 #define T3EMPI_FORTRAN
13 
14 #include <petsc/private/fortranimpl.h>
15 
16 #if defined(PETSC_HAVE_FORTRAN_CAPS)
17 #define petscinitializef_             PETSCINITIALIZEF
18 #define petscfinalize_                PETSCFINALIZE
19 #define petscend_                     PETSCEND
20 #define iargc_                        IARGC
21 #define getarg_                       GETARG
22 #define mpi_init_                     MPI_INIT
23 #define petscgetcomm_                 PETSCGETCOMM
24 #define petsccommandargumentcount_    PETSCCOMMANDARGUMENTCOUNT
25 #define petscgetcommandargument_      PETSCGETCOMMANDARGUMENT
26 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
27 #define petscinitializef_             petscinitializef
28 #define petscfinalize_                petscfinalize
29 #define petscend_                     petscend
30 #define mpi_init_                     mpi_init
31 #define iargc_                        iargc
32 #define getarg_                       getarg
33 #define petscgetcomm_                 petscgetcomm
34 #define petsccommandargumentcount_    petsccommandargumentcount
35 #define petscgetcommandargument_      petscgetcommandargument
36 #endif
37 
38 #if defined(PETSC_HAVE_NAGF90)
39 #undef iargc_
40 #undef getarg_
41 #define iargc_  f90_unix_MP_iargc
42 #define getarg_ f90_unix_MP_getarg
43 #endif
44 #if defined(PETSC_USE_NARGS) /* Digital Fortran */
45 #undef iargc_
46 #undef getarg_
47 #define iargc_  NARGS
48 #define getarg_ GETARG
49 #elif defined(PETSC_HAVE_PXFGETARG_NEW)  /* cray x1 */
50 #undef iargc_
51 #undef getarg_
52 #define iargc_  ipxfargc_
53 #define getarg_ pxfgetarg_
54 #endif
55 
56 #if defined(PETSC_HAVE_FORTRAN_GET_COMMAND_ARGUMENT) /* Fortran 2003 */
57 #undef iargc_
58 #undef getarg_
59 #define iargc_ petsccommandargumentcount_
60 #define getarg_ petscgetcommandargument_
61 #elif defined(PETSC_HAVE_BGL_IARGC) /* bgl g77 has different external & internal name mangling */
62 #undef iargc_
63 #undef getarg_
64 #define iargc  iargc_
65 #define getarg getarg_
66 #endif
67 
68 /*
69     The extra _ is because the f2c compiler puts an
70   extra _ at the end if the original routine name
71   contained any _.
72 */
73 #if defined(PETSC_HAVE_FORTRAN_UNDERSCORE_UNDERSCORE)
74 #define mpi_init_             mpi_init__
75 #endif
76 
77 #if defined(PETSC_HAVE_MPIUNI)
78 #if defined(mpi_init_)
79 #undef mpi_init_
80 #if defined(PETSC_HAVE_FORTRAN_CAPS)
81 #define mpi_init_             PETSC_MPI_INIT
82 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
83 #define mpi_init_             petsc_mpi_init
84 #elif defined(PETSC_HAVE_FORTRAN_UNDERSCORE_UNDERSCORE)
85 #define mpi_init_             petsc_mpi_init__
86 #endif
87 #else    /* mpi_init_ */
88 #define mpi_init_             petsc_mpi_init_
89 #endif   /* mpi_init_ */
90 #endif   /* PETSC_HAVE_MPIUNI */
91 
92 PETSC_EXTERN void mpi_init_(int*);
93 PETSC_EXTERN void petscgetcomm_(PetscMPIInt*);
94 
95 /*
96      Different Fortran compilers handle command lines in different ways
97 */
98 #if defined(PETSC_HAVE_FORTRAN_GET_COMMAND_ARGUMENT) /* Fortran 2003  - same as 'else' case */
99 PETSC_EXTERN int iargc_(void);
100 PETSC_EXTERN void getarg_(int*,char*,int);
101 #elif defined(PETSC_USE_NARGS)
102 PETSC_EXTERN short __stdcall NARGS(void);
103 PETSC_EXTERN void __stdcall GETARG(short*,char*,int,short *);
104 
105 #elif defined(PETSC_HAVE_PXFGETARG_NEW)
106 PETSC_EXTERN int iargc_(void);
107 PETSC_EXTERN void getarg_(int*,char*,int*,int*,int);
108 
109 #else
110 PETSC_EXTERN int iargc_(void);
111 PETSC_EXTERN void getarg_(int*,char*,int);
112 /*
113       The Cray T3D/T3E use the PXFGETARG() function
114 */
115 #if defined(PETSC_HAVE_PXFGETARG)
116 PETSC_EXTERN void PXFGETARG(int*,_fcd,int*,int*);
117 #endif
118 #endif
119 
120 PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t,PetscBool,int,const char[],const char[],void**);
121 PETSC_EXTERN PetscErrorCode PetscFreeAlign(void*,int,const char[],const char[]);
122 PETSC_INTERN int  PetscGlobalArgc;
123 PETSC_INTERN char **PetscGlobalArgs;
124 
125 /*
126     Reads in Fortran command line arguments and sends them to
127   all processors.
128 */
129 
130 PetscErrorCode PETScParseFortranArgs_Private(int *argc,char ***argv)
131 {
132 #if defined(PETSC_USE_NARGS)
133   short          i,flg;
134 #else
135   int            i;
136 #endif
137   int            warg = 256;
138   PetscMPIInt    rank;
139   char           *p;
140 
141   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
142   if (rank == 0) {
143 #if defined(PETSC_HAVE_IARG_COUNT_PROGNAME)
144     *argc = iargc_();
145 #else
146     /* most compilers do not count the program name for argv[0] */
147     *argc = 1 + iargc_();
148 #endif
149   }
150   PetscCallMPI(MPI_Bcast(argc,1,MPI_INT,0,PETSC_COMM_WORLD));
151 
152   /* PetscTrMalloc() not yet set, so don't use PetscMalloc() */
153   PetscCall(PetscMallocAlign((*argc+1)*(warg*sizeof(char)+sizeof(char*)),PETSC_FALSE,0,0,0,(void**)argv));
154   (*argv)[0] = (char*)(*argv + *argc + 1);
155 
156   if (rank == 0) {
157     PetscCall(PetscMemzero((*argv)[0],(*argc)*warg*sizeof(char)));
158     for (i=0; i<*argc; i++) {
159       (*argv)[i+1] = (*argv)[i] + warg;
160 #if defined (PETSC_HAVE_FORTRAN_GET_COMMAND_ARGUMENT) /* same as 'else' case */
161       getarg_(&i,(*argv)[i],warg);
162 #elif defined(PETSC_HAVE_PXFGETARG_NEW)
163       {char *tmp = (*argv)[i];
164       int ilen;
165       PetscCallFortranVoidFunction(getarg_(&i,tmp,&ilen,&ierr,warg));
166       tmp[ilen] = 0;}
167 #elif defined(PETSC_USE_NARGS)
168       GETARG(&i,(*argv)[i],warg,&flg);
169 #else
170       /*
171       Because the stupid #defines above define all kinds of things to getarg_ we cannot do this test
172       #elif defined(PETSC_HAVE_GETARG)
173       getarg_(&i,(*argv)[i],warg);
174       #else
175          SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get Fortran command line arguments");
176       */
177       getarg_(&i,(*argv)[i],warg);
178 #endif
179       /* zero out garbage at end of each argument */
180       p = (*argv)[i] + warg-1;
181       while (p > (*argv)[i]) {
182         if (*p == ' ') *p = 0;
183         p--;
184       }
185     }
186   }
187   PetscCallMPI(MPI_Bcast((*argv)[0],*argc*warg,MPI_CHAR,0,PETSC_COMM_WORLD));
188   if (rank) {
189     for (i=0; i<*argc; i++) (*argv)[i+1] = (*argv)[i] + warg;
190   }
191   return 0;
192 }
193 
194 /* -----------------------------------------------------------------------------------------------*/
195 
196 PETSC_INTERN PetscErrorCode PetscPreMPIInit_Private(void);
197 
198 PETSC_INTERN PetscErrorCode PetscInitFortran_Private(PetscBool readarguments,const char *filename,PetscInt len)
199 {
200   char           *tmp = NULL;
201 
202   PetscFunctionBegin;
203   PetscCall(PetscInitializeFortran());
204   if (readarguments) {
205     PetscCall(PETScParseFortranArgs_Private(&PetscGlobalArgc,&PetscGlobalArgs));
206     if (filename != PETSC_NULL_CHARACTER_Fortran) {  /* FIXCHAR */
207       while ((len > 0) && (filename[len-1] == ' ')) len--;
208       PetscCall(PetscMalloc1(len+1,&tmp));
209       PetscCall(PetscStrncpy(tmp,filename,len+1));
210     }
211     PetscCall(PetscOptionsInsert(NULL,&PetscGlobalArgc,&PetscGlobalArgs,tmp));
212     PetscCall(PetscFree(tmp)); /* FREECHAR */
213   }
214   PetscFunctionReturn(0);
215 }
216 
217 /*
218     petscinitialize - Version called from Fortran.
219 
220     Note:
221       Since this is called from Fortran it does not return error codes
222 
223 */
224 PETSC_EXTERN void petscinitializef_(char* filename,char* help,PetscBool *readarguments,PetscErrorCode *ierr,PETSC_FORTRAN_CHARLEN_T len,PETSC_FORTRAN_CHARLEN_T helplen)
225 {
226   int            j,i;
227 #if defined (PETSC_USE_NARGS)
228   short          flg;
229 #endif
230   int            flag;
231   char           name[256] = {0};
232   PetscMPIInt    f_petsc_comm_world;
233 
234   if (PetscInitializeCalled) {*ierr = 0; return;}
235   i = 0;
236 #if defined (PETSC_HAVE_FORTRAN_GET_COMMAND_ARGUMENT) /* same as 'else' case */
237   getarg_(&i,name,sizeof(name));
238 #elif defined (PETSC_HAVE_PXFGETARG_NEW)
239   { int ilen,sierr;
240     getarg_(&i,name,&ilen,&sierr,256);
241     if (sierr) PetscStrncpy(name,"Unknown Name",256);
242     else name[ilen] = 0;
243   }
244 #elif defined(PETSC_USE_NARGS)
245   GETARG(&i,name,256,&flg);
246 #else
247   getarg_(&i,name,256);
248 #endif
249   /* Eliminate spaces at the end of the string */
250   for (j=sizeof(name)-2; j>=0; j--) {
251     if (name[j] != ' ') {
252       name[j+1] = 0;
253       break;
254     }
255   }
256   if (j<0) PetscStrncpy(name,"Unknown Name",256);
257 
258   /* check if PETSC_COMM_WORLD is initialized by the user in fortran */
259   petscgetcomm_(&f_petsc_comm_world);
260   MPI_Initialized(&flag);
261   if (!flag) {
262     PetscMPIInt mierr;
263 
264     if (f_petsc_comm_world) {(*PetscErrorPrintf)("You cannot set PETSC_COMM_WORLD if you have not initialized MPI first\n");return;}
265 
266     *ierr = PetscPreMPIInit_Private(); if (*ierr) return;
267     mpi_init_(&mierr);
268     if (mierr) {
269       *ierr = mierr;
270       (*PetscErrorPrintf)("PetscInitialize: Calling Fortran MPI_Init()\n");
271       return;
272     }
273     PetscBeganMPI = PETSC_TRUE;
274   }
275   if (f_petsc_comm_world) PETSC_COMM_WORLD = MPI_Comm_f2c(*(MPI_Fint*)&f_petsc_comm_world); /* User called MPI_INITIALIZE() and changed PETSC_COMM_WORLD */
276   else PETSC_COMM_WORLD = MPI_COMM_WORLD;
277 
278   *ierr = PetscInitialize_Common(name,filename,help,PETSC_TRUE,*readarguments,(PetscInt)len);
279   if (*ierr) {(*PetscErrorPrintf)("PetscInitialize:PetscInitialize_Common\n");return;}
280 }
281 
282 PETSC_EXTERN void petscfinalize_(PetscErrorCode *ierr)
283 {
284   /* was malloced with PetscMallocAlign() so free the same way */
285   *ierr = PetscFreeAlign(PetscGlobalArgs,0,0,0);if (*ierr) {(*PetscErrorPrintf)("PetscFinalize:Freeing args\n");return;}
286 
287   *ierr = PetscFinalize();
288 }
289 
290 PETSC_EXTERN void petscend_(PetscErrorCode *ierr)
291 {
292   *ierr = PetscEnd();
293 }
294