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