16dd63270SBarry Smith #include <petsc/private/ftnimpl.h> 29306f9a3SSatish Balay 39306f9a3SSatish Balay /*MC 49306f9a3SSatish Balay PetscFortranAddr - a variable type in Fortran that can hold a 59306f9a3SSatish Balay regular C pointer. 69306f9a3SSatish Balay 7811af0c4SBarry Smith Note: 8811af0c4SBarry Smith Used, for example, as the file argument in `PetscFOpen()` 99306f9a3SSatish Balay 109306f9a3SSatish Balay Level: beginner 119306f9a3SSatish Balay 12811af0c4SBarry Smith .seealso: `PetscOffset`, `PetscInt` 139306f9a3SSatish Balay M*/ 149306f9a3SSatish Balay /*MC 15811af0c4SBarry Smith PetscOffset - a variable type in Fortran used with `VecGetArray()` 16811af0c4SBarry Smith and `ISGetIndices()` 179306f9a3SSatish Balay 189306f9a3SSatish Balay Level: beginner 199306f9a3SSatish Balay 20811af0c4SBarry Smith .seealso: `PetscFortranAddr`, `PetscInt` 219306f9a3SSatish Balay M*/ 229306f9a3SSatish Balay 239306f9a3SSatish Balay /* 249306f9a3SSatish Balay This is code for translating PETSc memory addresses to integer offsets 259306f9a3SSatish Balay for Fortran. 269306f9a3SSatish Balay */ 27dfef5ea7SSatish Balay char *PETSC_NULL_CHARACTER_Fortran = NULL; 28dfef5ea7SSatish Balay void *PETSC_NULL_INTEGER_Fortran = NULL; 29dfef5ea7SSatish Balay void *PETSC_NULL_SCALAR_Fortran = NULL; 30dfef5ea7SSatish Balay void *PETSC_NULL_DOUBLE_Fortran = NULL; 31dfef5ea7SSatish Balay void *PETSC_NULL_REAL_Fortran = NULL; 32dfef5ea7SSatish Balay void *PETSC_NULL_BOOL_Fortran = NULL; 335d83a8b1SBarry Smith void *PETSC_NULL_ENUM_Fortran = NULL; 345d83a8b1SBarry Smith void *PETSC_NULL_INTEGER_ARRAY_Fortran = NULL; 355d83a8b1SBarry Smith void *PETSC_NULL_SCALAR_ARRAY_Fortran = NULL; 365d83a8b1SBarry Smith void *PETSC_NULL_REAL_ARRAY_Fortran = NULL; 37ce78bad3SBarry Smith void *PETSC_NULL_INTEGER_POINTER_Fortran = NULL; 38ce78bad3SBarry Smith void *PETSC_NULL_SCALAR_POINTER_Fortran = NULL; 39ce78bad3SBarry Smith void *PETSC_NULL_REAL_POINTER_Fortran = NULL; 405d83a8b1SBarry Smith 419306f9a3SSatish Balay EXTERN_C_BEGIN 42*5ebfa9e9SBarry Smith PetscFortranCallbackFn *PETSC_NULL_FUNCTION_Fortran = NULL; 439306f9a3SSatish Balay EXTERN_C_END 44dfef5ea7SSatish Balay void *PETSC_NULL_MPI_COMM_Fortran = NULL; 4599e0435eSBarry Smith 468ea3bf28SBarry Smith size_t PetscIntAddressToFortran(const PetscInt *base, const PetscInt *addr) 479306f9a3SSatish Balay { 489306f9a3SSatish Balay size_t tmp1 = (size_t)base, tmp2 = 0; 499306f9a3SSatish Balay size_t tmp3 = (size_t)addr; 509306f9a3SSatish Balay size_t itmp2; 519306f9a3SSatish Balay 529306f9a3SSatish Balay #if !defined(PETSC_HAVE_CRAY90_POINTER) 539306f9a3SSatish Balay if (tmp3 > tmp1) { 549306f9a3SSatish Balay tmp2 = (tmp3 - tmp1) / sizeof(PetscInt); 559306f9a3SSatish Balay itmp2 = (size_t)tmp2; 569306f9a3SSatish Balay } else { 579306f9a3SSatish Balay tmp2 = (tmp1 - tmp3) / sizeof(PetscInt); 589306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 599306f9a3SSatish Balay } 609306f9a3SSatish Balay #else 619306f9a3SSatish Balay if (tmp3 > tmp1) { 629306f9a3SSatish Balay tmp2 = (tmp3 - tmp1); 639306f9a3SSatish Balay itmp2 = (size_t)tmp2; 649306f9a3SSatish Balay } else { 659306f9a3SSatish Balay tmp2 = (tmp1 - tmp3); 669306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 679306f9a3SSatish Balay } 689306f9a3SSatish Balay #endif 699306f9a3SSatish Balay 709306f9a3SSatish Balay if (base + itmp2 != addr) { 713ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("PetscIntAddressToFortran:C and Fortran arrays are\n")); 723ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("not commonly aligned or are too far apart to be indexed \n")); 733ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("by an integer. Locations: C %zu Fortran %zu\n", tmp1, tmp3)); 7441e02c4dSJunchao Zhang PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_PLIB); 759306f9a3SSatish Balay } 769306f9a3SSatish Balay return itmp2; 779306f9a3SSatish Balay } 789306f9a3SSatish Balay 798ea3bf28SBarry Smith PetscInt *PetscIntAddressFromFortran(const PetscInt *base, size_t addr) 809306f9a3SSatish Balay { 818ea3bf28SBarry Smith return (PetscInt *)(base + addr); 829306f9a3SSatish Balay } 839306f9a3SSatish Balay 849306f9a3SSatish Balay /* 859306f9a3SSatish Balay obj - PETSc object on which request is made 869306f9a3SSatish Balay base - Fortran array address 879306f9a3SSatish Balay addr - C array address 889306f9a3SSatish Balay res - will contain offset from C to Fortran 899306f9a3SSatish Balay shift - number of bytes that prevent base and addr from being commonly aligned 909306f9a3SSatish Balay N - size of the array 919306f9a3SSatish Balay 92f91d1997SBarry Smith align indicates alignment relative to PetscScalar, 1 means aligned on PetscScalar, 2 means aligned on 2 PetscScalar etc 939306f9a3SSatish Balay */ 94f91d1997SBarry Smith PetscErrorCode PetscScalarAddressToFortran(PetscObject obj, PetscInt align, PetscScalar *base, PetscScalar *addr, PetscInt N, size_t *res) 959306f9a3SSatish Balay { 96e366c363SBarry Smith size_t tmp1 = (size_t)base, tmp2; 979306f9a3SSatish Balay size_t tmp3 = (size_t)addr; 989306f9a3SSatish Balay size_t itmp2; 999306f9a3SSatish Balay PetscInt shift; 1009306f9a3SSatish Balay 1013ba16761SJacob Faibussowitsch PetscFunctionBegin; 1029306f9a3SSatish Balay #if !defined(PETSC_HAVE_CRAY90_POINTER) 1039306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 1049306f9a3SSatish Balay tmp2 = (tmp3 - tmp1) / sizeof(PetscScalar); 1059306f9a3SSatish Balay itmp2 = (size_t)tmp2; 106f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 1079306f9a3SSatish Balay } else { 1089306f9a3SSatish Balay tmp2 = (tmp1 - tmp3) / sizeof(PetscScalar); 1099306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 110f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 1119306f9a3SSatish Balay } 1129306f9a3SSatish Balay #else 1139306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 1149306f9a3SSatish Balay tmp2 = (tmp3 - tmp1); 1159306f9a3SSatish Balay itmp2 = (size_t)tmp2; 1169306f9a3SSatish Balay } else { 1179306f9a3SSatish Balay tmp2 = (tmp1 - tmp3); 1189306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 1199306f9a3SSatish Balay } 1209306f9a3SSatish Balay shift = 0; 1219306f9a3SSatish Balay #endif 1229306f9a3SSatish Balay 1239306f9a3SSatish Balay if (shift) { 1249306f9a3SSatish Balay /* 1259306f9a3SSatish Balay Fortran and C not PetscScalar aligned,recover by copying values into 1269306f9a3SSatish Balay memory that is aligned with the Fortran 1279306f9a3SSatish Balay */ 1289306f9a3SSatish Balay PetscScalar *work; 129776b82aeSLisandro Dalcin PetscContainer container; 1309306f9a3SSatish Balay 1319566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(N + align, &work)); 132f91d1997SBarry Smith 133f91d1997SBarry Smith /* recompute shift for newly allocated space */ 134f91d1997SBarry Smith tmp3 = (size_t)work; 135f91d1997SBarry Smith if (tmp3 > tmp1) { /* C is bigger than Fortran */ 136f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 137f91d1997SBarry Smith } else { 138f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 139f91d1997SBarry Smith } 1409306f9a3SSatish Balay 1419306f9a3SSatish Balay /* shift work by that number of bytes */ 1429306f9a3SSatish Balay work = (PetscScalar *)(((char *)work) + shift); 1439566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(work, addr, N)); 1449306f9a3SSatish Balay 1459306f9a3SSatish Balay /* store in the first location in addr how much you shift it */ 1469306f9a3SSatish Balay ((PetscInt *)addr)[0] = shift; 1479306f9a3SSatish Balay 1489566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 1499566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, addr)); 1509566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose(obj, "GetArrayPtr", (PetscObject)container)); 1519306f9a3SSatish Balay 1529306f9a3SSatish Balay tmp3 = (size_t)work; 1539306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 1549306f9a3SSatish Balay tmp2 = (tmp3 - tmp1) / sizeof(PetscScalar); 1559306f9a3SSatish Balay itmp2 = (size_t)tmp2; 156f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 1579306f9a3SSatish Balay } else { 1589306f9a3SSatish Balay tmp2 = (tmp1 - tmp3) / sizeof(PetscScalar); 1599306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 160f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 1619306f9a3SSatish Balay } 1629306f9a3SSatish Balay if (shift) { 1633ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("PetscScalarAddressToFortran:C and Fortran arrays are\n")); 1643ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("not commonly aligned.\n")); 1653ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("Locations/sizeof(PetscScalar): C %g Fortran %g\n", (double)(((PetscReal)tmp3) / (PetscReal)sizeof(PetscScalar)), (double)(((PetscReal)tmp1) / (PetscReal)sizeof(PetscScalar)))); 16641e02c4dSJunchao Zhang PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_PLIB); 1679306f9a3SSatish Balay } 1689566063dSJacob Faibussowitsch PetscCall(PetscInfo(obj, "Efficiency warning, copying array in XXXGetArray() due\n\ 169b122ec5aSJacob Faibussowitsch to alignment differences between C and Fortran\n")); 1709306f9a3SSatish Balay } 1719306f9a3SSatish Balay *res = itmp2; 1723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1739306f9a3SSatish Balay } 1749306f9a3SSatish Balay 1759306f9a3SSatish Balay /* 1769306f9a3SSatish Balay obj - the PETSc object where the scalar pointer came from 1779306f9a3SSatish Balay base - the Fortran array address 1789306f9a3SSatish Balay addr - the Fortran offset from base 1799306f9a3SSatish Balay N - the amount of data 1809306f9a3SSatish Balay 1819306f9a3SSatish Balay lx - the array space that is to be passed to XXXXRestoreArray() 1829306f9a3SSatish Balay */ 1839306f9a3SSatish Balay PetscErrorCode PetscScalarAddressFromFortran(PetscObject obj, PetscScalar *base, size_t addr, PetscInt N, PetscScalar **lx) 1849306f9a3SSatish Balay { 1859306f9a3SSatish Balay PetscInt shift; 186776b82aeSLisandro Dalcin PetscContainer container; 1879306f9a3SSatish Balay PetscScalar *tlx; 1889306f9a3SSatish Balay 1893ba16761SJacob Faibussowitsch PetscFunctionBegin; 1909566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery(obj, "GetArrayPtr", (PetscObject *)&container)); 1919306f9a3SSatish Balay if (container) { 1929566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)lx)); 1939306f9a3SSatish Balay tlx = base + addr; 1949306f9a3SSatish Balay 1959306f9a3SSatish Balay shift = *(PetscInt *)*lx; 1969566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(*lx, tlx, N)); 19757508eceSPierre Jolivet tlx = (PetscScalar *)((char *)tlx - shift); 198a297a907SKarl Rupp 1999566063dSJacob Faibussowitsch PetscCall(PetscFree(tlx)); 2009566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 201dfef5ea7SSatish Balay PetscCall(PetscObjectCompose(obj, "GetArrayPtr", NULL)); 2029306f9a3SSatish Balay } else { 2039306f9a3SSatish Balay *lx = base + addr; 2049306f9a3SSatish Balay } 2053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2069306f9a3SSatish Balay } 2079306f9a3SSatish Balay 20883886165SBarry Smith #if defined(PETSC_HAVE_FORTRAN_CAPS) 209f66fdb6dSSatish Balay #define petscisinfornanscalar_ PETSCISINFORNANSCALAR 210f66fdb6dSSatish Balay #define petscisinfornanreal_ PETSCISINFORNANREAL 21183886165SBarry Smith #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 212f66fdb6dSSatish Balay #define petscisinfornanscalar_ petscisinfornanscalar 213f66fdb6dSSatish Balay #define petscisinfornanreal_ petscisinfornanreal 21483886165SBarry Smith #endif 21583886165SBarry Smith 21619caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanscalar_(PetscScalar *v) 21783886165SBarry Smith { 218ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanScalar(*v); 219f66fdb6dSSatish Balay } 220f66fdb6dSSatish Balay 22119caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanreal_(PetscReal *v) 222f66fdb6dSSatish Balay { 223ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanReal(*v); 22483886165SBarry Smith } 225