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 = PetscLogInfo(((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