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