xref: /petsc/src/sys/ftn-custom/zutils.c (revision ae15b995b5732fffd2de5a75cf61ef7190c6fef1)
19306f9a3SSatish Balay #include "zpetsc.h"
29306f9a3SSatish Balay 
355fcb7f5SSatish Balay void *PETSCNULLPOINTERADDRESS = PETSC_NULL;
455fcb7f5SSatish Balay 
59306f9a3SSatish Balay /*MC
69306f9a3SSatish Balay    PetscFortranAddr - a variable type in Fortran that can hold a
79306f9a3SSatish Balay      regular C pointer.
89306f9a3SSatish Balay 
99306f9a3SSatish Balay    Notes: Used, for example, as the file argument in PetscFOpen()
109306f9a3SSatish Balay 
119306f9a3SSatish Balay    Level: beginner
129306f9a3SSatish Balay 
139306f9a3SSatish Balay .seealso:  PetscOffset, PetscInt
149306f9a3SSatish Balay M*/
159306f9a3SSatish Balay /*MC
169306f9a3SSatish Balay    PetscOffset - a variable type in Fortran used with VecGetArray()
179306f9a3SSatish Balay      and ISGetIndices()
189306f9a3SSatish Balay 
199306f9a3SSatish Balay    Level: beginner
209306f9a3SSatish Balay 
219306f9a3SSatish Balay .seealso:  PetscFortranAddr, PetscInt
229306f9a3SSatish Balay M*/
239306f9a3SSatish Balay 
249306f9a3SSatish Balay /*
259306f9a3SSatish Balay     This is code for translating PETSc memory addresses to integer offsets
269306f9a3SSatish Balay     for Fortran.
279306f9a3SSatish Balay */
289306f9a3SSatish Balay char   *PETSC_NULL_CHARACTER_Fortran = 0;
299306f9a3SSatish Balay void   *PETSC_NULL_INTEGER_Fortran   = 0;
309306f9a3SSatish Balay void   *PETSC_NULL_OBJECT_Fortran    = 0;
319306f9a3SSatish Balay void   *PETSC_NULL_Fortran           = 0;
329306f9a3SSatish Balay void   *PETSC_NULL_SCALAR_Fortran    = 0;
339306f9a3SSatish Balay void   *PETSC_NULL_DOUBLE_Fortran    = 0;
349306f9a3SSatish Balay void   *PETSC_NULL_REAL_Fortran      = 0;
359306f9a3SSatish Balay EXTERN_C_BEGIN
369306f9a3SSatish Balay void   (*PETSC_NULL_FUNCTION_Fortran)(void) = 0;
379306f9a3SSatish Balay EXTERN_C_END
389306f9a3SSatish Balay size_t PetscIntAddressToFortran(PetscInt *base,PetscInt *addr)
399306f9a3SSatish Balay {
409306f9a3SSatish Balay   size_t tmp1 = (size_t) base,tmp2 = 0;
419306f9a3SSatish Balay   size_t tmp3 = (size_t) addr;
429306f9a3SSatish Balay   size_t itmp2;
439306f9a3SSatish Balay 
449306f9a3SSatish Balay #if !defined(PETSC_HAVE_CRAY90_POINTER)
459306f9a3SSatish Balay   if (tmp3 > tmp1) {
469306f9a3SSatish Balay     tmp2  = (tmp3 - tmp1)/sizeof(PetscInt);
479306f9a3SSatish Balay     itmp2 = (size_t) tmp2;
489306f9a3SSatish Balay   } else {
499306f9a3SSatish Balay     tmp2  = (tmp1 - tmp3)/sizeof(PetscInt);
509306f9a3SSatish Balay     itmp2 = -((size_t) tmp2);
519306f9a3SSatish Balay   }
529306f9a3SSatish Balay #else
539306f9a3SSatish Balay   if (tmp3 > tmp1) {
549306f9a3SSatish Balay     tmp2  = (tmp3 - tmp1);
559306f9a3SSatish Balay     itmp2 = (size_t) tmp2;
569306f9a3SSatish Balay   } else {
579306f9a3SSatish Balay     tmp2  = (tmp1 - tmp3);
589306f9a3SSatish Balay     itmp2 = -((size_t) tmp2);
599306f9a3SSatish Balay   }
609306f9a3SSatish Balay #endif
619306f9a3SSatish Balay 
629306f9a3SSatish Balay   if (base + itmp2 != addr) {
639306f9a3SSatish Balay     (*PetscErrorPrintf)("PetscIntAddressToFortran:C and Fortran arrays are\n");
649306f9a3SSatish Balay     (*PetscErrorPrintf)("not commonly aligned or are too far apart to be indexed \n");
659306f9a3SSatish Balay     (*PetscErrorPrintf)("by an integer. Locations: C %uld Fortran %uld\n",tmp1,tmp3);
669306f9a3SSatish Balay     MPI_Abort(PETSC_COMM_WORLD,1);
679306f9a3SSatish Balay   }
689306f9a3SSatish Balay   return itmp2;
699306f9a3SSatish Balay }
709306f9a3SSatish Balay 
719306f9a3SSatish Balay PetscInt *PetscIntAddressFromFortran(PetscInt *base,size_t addr)
729306f9a3SSatish Balay {
739306f9a3SSatish Balay   return base + addr;
749306f9a3SSatish Balay }
759306f9a3SSatish Balay 
769306f9a3SSatish Balay /*
779306f9a3SSatish Balay        obj - PETSc object on which request is made
789306f9a3SSatish Balay        base - Fortran array address
799306f9a3SSatish Balay        addr - C array address
809306f9a3SSatish Balay        res  - will contain offset from C to Fortran
819306f9a3SSatish Balay        shift - number of bytes that prevent base and addr from being commonly aligned
829306f9a3SSatish Balay        N - size of the array
839306f9a3SSatish Balay 
849306f9a3SSatish Balay */
859306f9a3SSatish Balay PetscErrorCode PetscScalarAddressToFortran(PetscObject obj,PetscScalar *base,PetscScalar *addr,PetscInt N,size_t *res)
869306f9a3SSatish Balay {
879306f9a3SSatish Balay   size_t   tmp1 = (size_t) base,tmp2 = tmp1/sizeof(PetscScalar);
889306f9a3SSatish Balay   size_t   tmp3 = (size_t) addr;
899306f9a3SSatish Balay   size_t   itmp2;
909306f9a3SSatish Balay   PetscInt shift;
919306f9a3SSatish Balay 
929306f9a3SSatish Balay #if !defined(PETSC_HAVE_CRAY90_POINTER)
939306f9a3SSatish Balay   if (tmp3 > tmp1) {  /* C is bigger than Fortran */
949306f9a3SSatish Balay     tmp2  = (tmp3 - tmp1)/sizeof(PetscScalar);
959306f9a3SSatish Balay     itmp2 = (size_t) tmp2;
969306f9a3SSatish Balay     shift = (sizeof(PetscScalar) - (int)((tmp3 - tmp1) % sizeof(PetscScalar))) % sizeof(PetscScalar);
979306f9a3SSatish Balay   } else {
989306f9a3SSatish Balay     tmp2  = (tmp1 - tmp3)/sizeof(PetscScalar);
999306f9a3SSatish Balay     itmp2 = -((size_t) tmp2);
1009306f9a3SSatish Balay     shift = (int)((tmp1 - tmp3) % sizeof(PetscScalar));
1019306f9a3SSatish Balay   }
1029306f9a3SSatish Balay #else
1039306f9a3SSatish Balay   if (tmp3 > tmp1) {  /* C is bigger than Fortran */
1049306f9a3SSatish Balay     tmp2  = (tmp3 - tmp1);
1059306f9a3SSatish Balay     itmp2 = (size_t) tmp2;
1069306f9a3SSatish Balay   } else {
1079306f9a3SSatish Balay     tmp2  = (tmp1 - tmp3);
1089306f9a3SSatish Balay     itmp2 = -((size_t) tmp2);
1099306f9a3SSatish Balay   }
1109306f9a3SSatish Balay   shift = 0;
1119306f9a3SSatish Balay #endif
1129306f9a3SSatish Balay 
1139306f9a3SSatish Balay   if (shift) {
1149306f9a3SSatish Balay     /*
1159306f9a3SSatish Balay         Fortran and C not PetscScalar aligned,recover by copying values into
1169306f9a3SSatish Balay         memory that is aligned with the Fortran
1179306f9a3SSatish Balay     */
1189306f9a3SSatish Balay     PetscErrorCode       ierr;
1199306f9a3SSatish Balay     PetscScalar          *work;
1209306f9a3SSatish Balay     PetscObjectContainer container;
1219306f9a3SSatish Balay 
1229306f9a3SSatish Balay     ierr = PetscMalloc((N+1)*sizeof(PetscScalar),&work);CHKERRQ(ierr);
1239306f9a3SSatish Balay 
1249306f9a3SSatish Balay     /* shift work by that number of bytes */
1259306f9a3SSatish Balay     work = (PetscScalar*)(((char*)work) + shift);
1269306f9a3SSatish Balay     ierr = PetscMemcpy(work,addr,N*sizeof(PetscScalar));CHKERRQ(ierr);
1279306f9a3SSatish Balay 
1289306f9a3SSatish Balay     /* store in the first location in addr how much you shift it */
1299306f9a3SSatish Balay     ((PetscInt*)addr)[0] = shift;
1309306f9a3SSatish Balay 
1319306f9a3SSatish Balay     ierr = PetscObjectContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr);
1329306f9a3SSatish Balay     ierr = PetscObjectContainerSetPointer(container,addr);CHKERRQ(ierr);
1339306f9a3SSatish Balay     ierr = PetscObjectCompose(obj,"GetArrayPtr",(PetscObject)container);CHKERRQ(ierr);
1349306f9a3SSatish Balay 
1359306f9a3SSatish Balay     tmp3 = (size_t) work;
1369306f9a3SSatish Balay     if (tmp3 > tmp1) {  /* C is bigger than Fortran */
1379306f9a3SSatish Balay       tmp2  = (tmp3 - tmp1)/sizeof(PetscScalar);
1389306f9a3SSatish Balay       itmp2 = (size_t) tmp2;
1399306f9a3SSatish Balay       shift = (sizeof(PetscScalar) - (int)((tmp3 - tmp1) % sizeof(PetscScalar))) % sizeof(PetscScalar);
1409306f9a3SSatish Balay     } else {
1419306f9a3SSatish Balay       tmp2  = (tmp1 - tmp3)/sizeof(PetscScalar);
1429306f9a3SSatish Balay       itmp2 = -((size_t) tmp2);
1439306f9a3SSatish Balay       shift = (int)((tmp1 - tmp3) % sizeof(PetscScalar));
1449306f9a3SSatish Balay     }
1459306f9a3SSatish Balay     if (shift) {
1469306f9a3SSatish Balay       (*PetscErrorPrintf)("PetscScalarAddressToFortran:C and Fortran arrays are\n");
1479306f9a3SSatish Balay       (*PetscErrorPrintf)("not commonly aligned.\n");
1489306f9a3SSatish Balay       /* double/int doesn't work with ADIC */
1499306f9a3SSatish Balay       (*PetscErrorPrintf)("Locations/sizeof(PetscScalar): C %f Fortran %f\n",
1509306f9a3SSatish Balay                          ((PetscReal)tmp3)/(PetscReal)sizeof(PetscScalar),((PetscReal)tmp1)/(PetscReal)sizeof(PetscScalar));
1519306f9a3SSatish Balay       MPI_Abort(PETSC_COMM_WORLD,1);
1529306f9a3SSatish Balay     }
153*ae15b995SBarry Smith     ierr = PetscInfo((void*)obj,"Efficiency warning, copying array in XXXGetArray() due\n\
154*ae15b995SBarry Smith     to alignment differences between C and Fortran\n");CHKERRQ(ierr);
1559306f9a3SSatish Balay   }
1569306f9a3SSatish Balay   *res = itmp2;
1579306f9a3SSatish Balay   return 0;
1589306f9a3SSatish Balay }
1599306f9a3SSatish Balay 
1609306f9a3SSatish Balay /*
1619306f9a3SSatish Balay     obj - the PETSc object where the scalar pointer came from
1629306f9a3SSatish Balay     base - the Fortran array address
1639306f9a3SSatish Balay     addr - the Fortran offset from base
1649306f9a3SSatish Balay     N    - the amount of data
1659306f9a3SSatish Balay 
1669306f9a3SSatish Balay     lx   - the array space that is to be passed to XXXXRestoreArray()
1679306f9a3SSatish Balay */
1689306f9a3SSatish Balay PetscErrorCode PetscScalarAddressFromFortran(PetscObject obj,PetscScalar *base,size_t addr,PetscInt N,PetscScalar **lx)
1699306f9a3SSatish Balay {
1709306f9a3SSatish Balay   PetscErrorCode       ierr;
1719306f9a3SSatish Balay   PetscInt             shift;
1729306f9a3SSatish Balay   PetscObjectContainer container;
1739306f9a3SSatish Balay   PetscScalar          *tlx;
1749306f9a3SSatish Balay 
1759306f9a3SSatish Balay   ierr = PetscObjectQuery(obj,"GetArrayPtr",(PetscObject *)&container);CHKERRQ(ierr);
1769306f9a3SSatish Balay   if (container) {
1779306f9a3SSatish Balay     ierr  = PetscObjectContainerGetPointer(container,(void**)lx);CHKERRQ(ierr);
1789306f9a3SSatish Balay     tlx   = base + addr;
1799306f9a3SSatish Balay 
1809306f9a3SSatish Balay     shift = *(PetscInt*)*lx;
1819306f9a3SSatish Balay     ierr  = PetscMemcpy(*lx,tlx,N*sizeof(PetscScalar));CHKERRQ(ierr);
1829306f9a3SSatish Balay     tlx   = (PetscScalar*)(((char *)tlx) - shift);
1839306f9a3SSatish Balay     ierr = PetscFree(tlx);CHKERRQ(ierr);
1849306f9a3SSatish Balay     ierr = PetscObjectContainerDestroy(container);CHKERRQ(ierr);
1859306f9a3SSatish Balay     ierr = PetscObjectCompose(obj,"GetArrayPtr",0);CHKERRQ(ierr);
1869306f9a3SSatish Balay   } else {
1879306f9a3SSatish Balay     *lx = base + addr;
1889306f9a3SSatish Balay   }
1899306f9a3SSatish Balay   return 0;
1909306f9a3SSatish Balay }
1919306f9a3SSatish Balay 
1929306f9a3SSatish Balay #undef __FUNCT__
1939306f9a3SSatish Balay #define __FUNCT__ "MPICCommToFortranComm"
1949306f9a3SSatish Balay /*@C
1959306f9a3SSatish Balay     MPICCommToFortranComm - Converts a MPI_Comm represented
1969306f9a3SSatish Balay     in C to one appropriate to pass to a Fortran routine.
1979306f9a3SSatish Balay 
1989306f9a3SSatish Balay     Not collective
1999306f9a3SSatish Balay 
2009306f9a3SSatish Balay     Input Parameter:
2019306f9a3SSatish Balay .   cobj - the C MPI_Comm
2029306f9a3SSatish Balay 
2039306f9a3SSatish Balay     Output Parameter:
2049306f9a3SSatish Balay .   fobj - the Fortran MPI_Comm
2059306f9a3SSatish Balay 
2069306f9a3SSatish Balay     Level: advanced
2079306f9a3SSatish Balay 
2089306f9a3SSatish Balay     Notes:
2099306f9a3SSatish Balay     MPICCommToFortranComm() must be called in a C/C++ routine.
2109306f9a3SSatish Balay     MPI 1 does not provide a standard for mapping between
2119306f9a3SSatish Balay     Fortran and C MPI communicators; this routine handles the
2129306f9a3SSatish Balay     mapping correctly on all machines.
2139306f9a3SSatish Balay 
2149306f9a3SSatish Balay .keywords: Fortran, C, MPI_Comm, convert, interlanguage
2159306f9a3SSatish Balay 
2169306f9a3SSatish Balay .seealso: MPIFortranCommToCComm()
2179306f9a3SSatish Balay @*/
2189306f9a3SSatish Balay PetscErrorCode MPICCommToFortranComm(MPI_Comm comm,int *fcomm)
2199306f9a3SSatish Balay {
2209306f9a3SSatish Balay   PetscErrorCode ierr;
2219306f9a3SSatish Balay   PetscMPIInt    size;
2229306f9a3SSatish Balay 
2239306f9a3SSatish Balay   PetscFunctionBegin;
2249306f9a3SSatish Balay   /* call to MPI_Comm_size() is for error checking on comm */
2259306f9a3SSatish Balay   ierr = MPI_Comm_size(comm,&size);
2269306f9a3SSatish Balay   if (ierr) SETERRQ(PETSC_ERR_ARG_CORRUPT ,"Invalid MPI communicator");
2279306f9a3SSatish Balay 
2289306f9a3SSatish Balay   *fcomm = PetscFromPointerComm(comm);
2299306f9a3SSatish Balay   PetscFunctionReturn(0);
2309306f9a3SSatish Balay }
2319306f9a3SSatish Balay 
2329306f9a3SSatish Balay #undef __FUNCT__
2339306f9a3SSatish Balay #define __FUNCT__ "MPIFortranCommToCComm"
2349306f9a3SSatish Balay /*@C
2359306f9a3SSatish Balay     MPIFortranCommToCComm - Converts a MPI_Comm represented
2369306f9a3SSatish Balay     int Fortran (as an integer) to a MPI_Comm in C.
2379306f9a3SSatish Balay 
2389306f9a3SSatish Balay     Not collective
2399306f9a3SSatish Balay 
2409306f9a3SSatish Balay     Input Parameter:
2419306f9a3SSatish Balay .   fcomm - the Fortran MPI_Comm (an integer)
2429306f9a3SSatish Balay 
2439306f9a3SSatish Balay     Output Parameter:
2449306f9a3SSatish Balay .   comm - the C MPI_Comm
2459306f9a3SSatish Balay 
2469306f9a3SSatish Balay     Level: advanced
2479306f9a3SSatish Balay 
2489306f9a3SSatish Balay     Notes:
2499306f9a3SSatish Balay     MPIFortranCommToCComm() must be called in a C/C++ routine.
2509306f9a3SSatish Balay     MPI 1 does not provide a standard for mapping between
2519306f9a3SSatish Balay     Fortran and C MPI communicators; this routine handles the
2529306f9a3SSatish Balay     mapping correctly on all machines.
2539306f9a3SSatish Balay 
2549306f9a3SSatish Balay .keywords: Fortran, C, MPI_Comm, convert, interlanguage
2559306f9a3SSatish Balay 
2569306f9a3SSatish Balay .seealso: MPICCommToFortranComm()
2579306f9a3SSatish Balay @*/
2589306f9a3SSatish Balay PetscErrorCode MPIFortranCommToCComm(int fcomm,MPI_Comm *comm)
2599306f9a3SSatish Balay {
2609306f9a3SSatish Balay   PetscErrorCode ierr;
2619306f9a3SSatish Balay   PetscMPIInt    size;
2629306f9a3SSatish Balay 
2639306f9a3SSatish Balay   PetscFunctionBegin;
2649306f9a3SSatish Balay   *comm = (MPI_Comm)PetscToPointerComm(fcomm);
2659306f9a3SSatish Balay   /* call to MPI_Comm_size() is for error checking on comm */
2669306f9a3SSatish Balay   ierr = MPI_Comm_size(*comm,&size);
2679306f9a3SSatish Balay   if (ierr) SETERRQ(PETSC_ERR_ARG_CORRUPT,"Invalid MPI communicator");
2689306f9a3SSatish Balay   PetscFunctionReturn(0);
2699306f9a3SSatish Balay }
2709306f9a3SSatish Balay 
2719306f9a3SSatish Balay 
2729306f9a3SSatish Balay 
273