xref: /petsc/src/sys/ftn-custom/zutils.c (revision 09f3b4e5628a00a1eaf17d80982cfbcc515cc9c1)
1 #include "zpetsc.h"
2 
3 void *PETSCNULLPOINTERADDRESS = PETSC_NULL;
4 
5 /*MC
6    PetscFortranAddr - a variable type in Fortran that can hold a
7      regular C pointer.
8 
9    Notes: Used, for example, as the file argument in PetscFOpen()
10 
11    Level: beginner
12 
13 .seealso:  PetscOffset, PetscInt
14 M*/
15 /*MC
16    PetscOffset - a variable type in Fortran used with VecGetArray()
17      and ISGetIndices()
18 
19    Level: beginner
20 
21 .seealso:  PetscFortranAddr, PetscInt
22 M*/
23 
24 /*
25     This is code for translating PETSc memory addresses to integer offsets
26     for Fortran.
27 */
28 char   *PETSC_NULL_CHARACTER_Fortran = 0;
29 void   *PETSC_NULL_INTEGER_Fortran   = 0;
30 void   *PETSC_NULL_OBJECT_Fortran    = 0;
31 void   *PETSC_NULL_Fortran           = 0;
32 void   *PETSC_NULL_SCALAR_Fortran    = 0;
33 void   *PETSC_NULL_DOUBLE_Fortran    = 0;
34 void   *PETSC_NULL_REAL_Fortran      = 0;
35 EXTERN_C_BEGIN
36 void   (*PETSC_NULL_FUNCTION_Fortran)(void) = 0;
37 EXTERN_C_END
38 size_t PetscIntAddressToFortran(PetscInt *base,PetscInt *addr)
39 {
40   size_t tmp1 = (size_t) base,tmp2 = 0;
41   size_t tmp3 = (size_t) addr;
42   size_t itmp2;
43 
44 #if !defined(PETSC_HAVE_CRAY90_POINTER)
45   if (tmp3 > tmp1) {
46     tmp2  = (tmp3 - tmp1)/sizeof(PetscInt);
47     itmp2 = (size_t) tmp2;
48   } else {
49     tmp2  = (tmp1 - tmp3)/sizeof(PetscInt);
50     itmp2 = -((size_t) tmp2);
51   }
52 #else
53   if (tmp3 > tmp1) {
54     tmp2  = (tmp3 - tmp1);
55     itmp2 = (size_t) tmp2;
56   } else {
57     tmp2  = (tmp1 - tmp3);
58     itmp2 = -((size_t) tmp2);
59   }
60 #endif
61 
62   if (base + itmp2 != addr) {
63     (*PetscErrorPrintf)("PetscIntAddressToFortran:C and Fortran arrays are\n");
64     (*PetscErrorPrintf)("not commonly aligned or are too far apart to be indexed \n");
65     (*PetscErrorPrintf)("by an integer. Locations: C %uld Fortran %uld\n",tmp1,tmp3);
66     MPI_Abort(PETSC_COMM_WORLD,1);
67   }
68   return itmp2;
69 }
70 
71 PetscInt *PetscIntAddressFromFortran(PetscInt *base,size_t addr)
72 {
73   return base + addr;
74 }
75 
76 /*
77        obj - PETSc object on which request is made
78        base - Fortran array address
79        addr - C array address
80        res  - will contain offset from C to Fortran
81        shift - number of bytes that prevent base and addr from being commonly aligned
82        N - size of the array
83 
84 */
85 PetscErrorCode PetscScalarAddressToFortran(PetscObject obj,PetscScalar *base,PetscScalar *addr,PetscInt N,size_t *res)
86 {
87   size_t   tmp1 = (size_t) base,tmp2 = tmp1/sizeof(PetscScalar);
88   size_t   tmp3 = (size_t) addr;
89   size_t   itmp2;
90   PetscInt shift;
91 
92 #if !defined(PETSC_HAVE_CRAY90_POINTER)
93   if (tmp3 > tmp1) {  /* C is bigger than Fortran */
94     tmp2  = (tmp3 - tmp1)/sizeof(PetscScalar);
95     itmp2 = (size_t) tmp2;
96     shift = (sizeof(PetscScalar) - (int)((tmp3 - tmp1) % sizeof(PetscScalar))) % sizeof(PetscScalar);
97   } else {
98     tmp2  = (tmp1 - tmp3)/sizeof(PetscScalar);
99     itmp2 = -((size_t) tmp2);
100     shift = (int)((tmp1 - tmp3) % sizeof(PetscScalar));
101   }
102 #else
103   if (tmp3 > tmp1) {  /* C is bigger than Fortran */
104     tmp2  = (tmp3 - tmp1);
105     itmp2 = (size_t) tmp2;
106   } else {
107     tmp2  = (tmp1 - tmp3);
108     itmp2 = -((size_t) tmp2);
109   }
110   shift = 0;
111 #endif
112 
113   if (shift) {
114     /*
115         Fortran and C not PetscScalar aligned,recover by copying values into
116         memory that is aligned with the Fortran
117     */
118     PetscErrorCode       ierr;
119     PetscScalar          *work;
120     PetscObjectContainer container;
121 
122     ierr = PetscMalloc((N+1)*sizeof(PetscScalar),&work);CHKERRQ(ierr);
123 
124     /* shift work by that number of bytes */
125     work = (PetscScalar*)(((char*)work) + shift);
126     ierr = PetscMemcpy(work,addr,N*sizeof(PetscScalar));CHKERRQ(ierr);
127 
128     /* store in the first location in addr how much you shift it */
129     ((PetscInt*)addr)[0] = shift;
130 
131     ierr = PetscObjectContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr);
132     ierr = PetscObjectContainerSetPointer(container,addr);CHKERRQ(ierr);
133     ierr = PetscObjectCompose(obj,"GetArrayPtr",(PetscObject)container);CHKERRQ(ierr);
134 
135     tmp3 = (size_t) work;
136     if (tmp3 > tmp1) {  /* C is bigger than Fortran */
137       tmp2  = (tmp3 - tmp1)/sizeof(PetscScalar);
138       itmp2 = (size_t) tmp2;
139       shift = (sizeof(PetscScalar) - (int)((tmp3 - tmp1) % sizeof(PetscScalar))) % sizeof(PetscScalar);
140     } else {
141       tmp2  = (tmp1 - tmp3)/sizeof(PetscScalar);
142       itmp2 = -((size_t) tmp2);
143       shift = (int)((tmp1 - tmp3) % sizeof(PetscScalar));
144     }
145     if (shift) {
146       (*PetscErrorPrintf)("PetscScalarAddressToFortran:C and Fortran arrays are\n");
147       (*PetscErrorPrintf)("not commonly aligned.\n");
148       /* double/int doesn't work with ADIC */
149       (*PetscErrorPrintf)("Locations/sizeof(PetscScalar): C %f Fortran %f\n",
150                          ((PetscReal)tmp3)/(PetscReal)sizeof(PetscScalar),((PetscReal)tmp1)/(PetscReal)sizeof(PetscScalar));
151       MPI_Abort(PETSC_COMM_WORLD,1);
152     }
153     ierr = PetscVerboseInfo(((void*)obj,"PetscScalarAddressToFortran:Efficiency warning, copying array in XXXGetArray() due\n\
154     to alignment differences between C and Fortran\n"));CHKERRQ(ierr);
155   }
156   *res = itmp2;
157   return 0;
158 }
159 
160 /*
161     obj - the PETSc object where the scalar pointer came from
162     base - the Fortran array address
163     addr - the Fortran offset from base
164     N    - the amount of data
165 
166     lx   - the array space that is to be passed to XXXXRestoreArray()
167 */
168 PetscErrorCode PetscScalarAddressFromFortran(PetscObject obj,PetscScalar *base,size_t addr,PetscInt N,PetscScalar **lx)
169 {
170   PetscErrorCode       ierr;
171   PetscInt             shift;
172   PetscObjectContainer container;
173   PetscScalar          *tlx;
174 
175   ierr = PetscObjectQuery(obj,"GetArrayPtr",(PetscObject *)&container);CHKERRQ(ierr);
176   if (container) {
177     ierr  = PetscObjectContainerGetPointer(container,(void**)lx);CHKERRQ(ierr);
178     tlx   = base + addr;
179 
180     shift = *(PetscInt*)*lx;
181     ierr  = PetscMemcpy(*lx,tlx,N*sizeof(PetscScalar));CHKERRQ(ierr);
182     tlx   = (PetscScalar*)(((char *)tlx) - shift);
183     ierr = PetscFree(tlx);CHKERRQ(ierr);
184     ierr = PetscObjectContainerDestroy(container);CHKERRQ(ierr);
185     ierr = PetscObjectCompose(obj,"GetArrayPtr",0);CHKERRQ(ierr);
186   } else {
187     *lx = base + addr;
188   }
189   return 0;
190 }
191 
192 #undef __FUNCT__
193 #define __FUNCT__ "MPICCommToFortranComm"
194 /*@C
195     MPICCommToFortranComm - Converts a MPI_Comm represented
196     in C to one appropriate to pass to a Fortran routine.
197 
198     Not collective
199 
200     Input Parameter:
201 .   cobj - the C MPI_Comm
202 
203     Output Parameter:
204 .   fobj - the Fortran MPI_Comm
205 
206     Level: advanced
207 
208     Notes:
209     MPICCommToFortranComm() must be called in a C/C++ routine.
210     MPI 1 does not provide a standard for mapping between
211     Fortran and C MPI communicators; this routine handles the
212     mapping correctly on all machines.
213 
214 .keywords: Fortran, C, MPI_Comm, convert, interlanguage
215 
216 .seealso: MPIFortranCommToCComm()
217 @*/
218 PetscErrorCode MPICCommToFortranComm(MPI_Comm comm,int *fcomm)
219 {
220   PetscErrorCode ierr;
221   PetscMPIInt    size;
222 
223   PetscFunctionBegin;
224   /* call to MPI_Comm_size() is for error checking on comm */
225   ierr = MPI_Comm_size(comm,&size);
226   if (ierr) SETERRQ(PETSC_ERR_ARG_CORRUPT ,"Invalid MPI communicator");
227 
228   *fcomm = PetscFromPointerComm(comm);
229   PetscFunctionReturn(0);
230 }
231 
232 #undef __FUNCT__
233 #define __FUNCT__ "MPIFortranCommToCComm"
234 /*@C
235     MPIFortranCommToCComm - Converts a MPI_Comm represented
236     int Fortran (as an integer) to a MPI_Comm in C.
237 
238     Not collective
239 
240     Input Parameter:
241 .   fcomm - the Fortran MPI_Comm (an integer)
242 
243     Output Parameter:
244 .   comm - the C MPI_Comm
245 
246     Level: advanced
247 
248     Notes:
249     MPIFortranCommToCComm() must be called in a C/C++ routine.
250     MPI 1 does not provide a standard for mapping between
251     Fortran and C MPI communicators; this routine handles the
252     mapping correctly on all machines.
253 
254 .keywords: Fortran, C, MPI_Comm, convert, interlanguage
255 
256 .seealso: MPICCommToFortranComm()
257 @*/
258 PetscErrorCode MPIFortranCommToCComm(int fcomm,MPI_Comm *comm)
259 {
260   PetscErrorCode ierr;
261   PetscMPIInt    size;
262 
263   PetscFunctionBegin;
264   *comm = (MPI_Comm)PetscToPointerComm(fcomm);
265   /* call to MPI_Comm_size() is for error checking on comm */
266   ierr = MPI_Comm_size(*comm,&size);
267   if (ierr) SETERRQ(PETSC_ERR_ARG_CORRUPT,"Invalid MPI communicator");
268   PetscFunctionReturn(0);
269 }
270 
271 
272 
273