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