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