1af0996ceSBarry Smith #include <petsc/private/fortranimpl.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 */ 27*dfef5ea7SSatish Balay char *PETSC_NULL_CHARACTER_Fortran = NULL; 28*dfef5ea7SSatish Balay void *PETSC_NULL_INTEGER_Fortran = NULL; 29*dfef5ea7SSatish Balay void *PETSC_NULL_SCALAR_Fortran = NULL; 30*dfef5ea7SSatish Balay void *PETSC_NULL_DOUBLE_Fortran = NULL; 31*dfef5ea7SSatish Balay void *PETSC_NULL_REAL_Fortran = NULL; 32*dfef5ea7SSatish Balay void *PETSC_NULL_BOOL_Fortran = NULL; 339306f9a3SSatish Balay EXTERN_C_BEGIN 34*dfef5ea7SSatish Balay void (*PETSC_NULL_FUNCTION_Fortran)(void) = NULL; 359306f9a3SSatish Balay EXTERN_C_END 36*dfef5ea7SSatish Balay void *PETSC_NULL_MPI_COMM_Fortran = NULL; 3799e0435eSBarry Smith 388ea3bf28SBarry Smith size_t PetscIntAddressToFortran(const PetscInt *base, const 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) { 633ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("PetscIntAddressToFortran:C and Fortran arrays are\n")); 643ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("not commonly aligned or are too far apart to be indexed \n")); 653ba16761SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, (*PetscErrorPrintf)("by an integer. Locations: C %zu Fortran %zu\n", tmp1, tmp3)); 6641e02c4dSJunchao Zhang PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_PLIB); 679306f9a3SSatish Balay } 689306f9a3SSatish Balay return itmp2; 699306f9a3SSatish Balay } 709306f9a3SSatish Balay 718ea3bf28SBarry Smith PetscInt *PetscIntAddressFromFortran(const PetscInt *base, size_t addr) 729306f9a3SSatish Balay { 738ea3bf28SBarry Smith return (PetscInt *)(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 84f91d1997SBarry Smith align indicates alignment relative to PetscScalar, 1 means aligned on PetscScalar, 2 means aligned on 2 PetscScalar etc 859306f9a3SSatish Balay */ 86f91d1997SBarry Smith PetscErrorCode PetscScalarAddressToFortran(PetscObject obj, PetscInt align, PetscScalar *base, PetscScalar *addr, PetscInt N, size_t *res) 879306f9a3SSatish Balay { 88e366c363SBarry Smith size_t tmp1 = (size_t)base, tmp2; 899306f9a3SSatish Balay size_t tmp3 = (size_t)addr; 909306f9a3SSatish Balay size_t itmp2; 919306f9a3SSatish Balay PetscInt shift; 929306f9a3SSatish Balay 933ba16761SJacob Faibussowitsch PetscFunctionBegin; 949306f9a3SSatish Balay #if !defined(PETSC_HAVE_CRAY90_POINTER) 959306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 969306f9a3SSatish Balay tmp2 = (tmp3 - tmp1) / sizeof(PetscScalar); 979306f9a3SSatish Balay itmp2 = (size_t)tmp2; 98f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 999306f9a3SSatish Balay } else { 1009306f9a3SSatish Balay tmp2 = (tmp1 - tmp3) / sizeof(PetscScalar); 1019306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 102f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 1039306f9a3SSatish Balay } 1049306f9a3SSatish Balay #else 1059306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 1069306f9a3SSatish Balay tmp2 = (tmp3 - tmp1); 1079306f9a3SSatish Balay itmp2 = (size_t)tmp2; 1089306f9a3SSatish Balay } else { 1099306f9a3SSatish Balay tmp2 = (tmp1 - tmp3); 1109306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 1119306f9a3SSatish Balay } 1129306f9a3SSatish Balay shift = 0; 1139306f9a3SSatish Balay #endif 1149306f9a3SSatish Balay 1159306f9a3SSatish Balay if (shift) { 1169306f9a3SSatish Balay /* 1179306f9a3SSatish Balay Fortran and C not PetscScalar aligned,recover by copying values into 1189306f9a3SSatish Balay memory that is aligned with the Fortran 1199306f9a3SSatish Balay */ 1209306f9a3SSatish Balay PetscScalar *work; 121776b82aeSLisandro Dalcin PetscContainer container; 1229306f9a3SSatish Balay 1239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(N + align, &work)); 124f91d1997SBarry Smith 125f91d1997SBarry Smith /* recompute shift for newly allocated space */ 126f91d1997SBarry Smith tmp3 = (size_t)work; 127f91d1997SBarry Smith if (tmp3 > tmp1) { /* C is bigger than Fortran */ 128f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 129f91d1997SBarry Smith } else { 130f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 131f91d1997SBarry Smith } 1329306f9a3SSatish Balay 1339306f9a3SSatish Balay /* shift work by that number of bytes */ 1349306f9a3SSatish Balay work = (PetscScalar *)(((char *)work) + shift); 1359566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(work, addr, N)); 1369306f9a3SSatish Balay 1379306f9a3SSatish Balay /* store in the first location in addr how much you shift it */ 1389306f9a3SSatish Balay ((PetscInt *)addr)[0] = shift; 1399306f9a3SSatish Balay 1409566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 1419566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, addr)); 1429566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose(obj, "GetArrayPtr", (PetscObject)container)); 1439306f9a3SSatish Balay 1449306f9a3SSatish Balay tmp3 = (size_t)work; 1459306f9a3SSatish Balay if (tmp3 > tmp1) { /* C is bigger than Fortran */ 1469306f9a3SSatish Balay tmp2 = (tmp3 - tmp1) / sizeof(PetscScalar); 1479306f9a3SSatish Balay itmp2 = (size_t)tmp2; 148f91d1997SBarry Smith shift = (align * sizeof(PetscScalar) - (PetscInt)((tmp3 - tmp1) % (align * sizeof(PetscScalar)))) % (align * sizeof(PetscScalar)); 1499306f9a3SSatish Balay } else { 1509306f9a3SSatish Balay tmp2 = (tmp1 - tmp3) / sizeof(PetscScalar); 1519306f9a3SSatish Balay itmp2 = -((size_t)tmp2); 152f91d1997SBarry Smith shift = (PetscInt)((tmp1 - tmp3) % (align * sizeof(PetscScalar))); 1539306f9a3SSatish Balay } 1549306f9a3SSatish Balay if (shift) { 1553ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("PetscScalarAddressToFortran:C and Fortran arrays are\n")); 1563ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("not commonly aligned.\n")); 1573ba16761SJacob Faibussowitsch PetscCall((*PetscErrorPrintf)("Locations/sizeof(PetscScalar): C %g Fortran %g\n", (double)(((PetscReal)tmp3) / (PetscReal)sizeof(PetscScalar)), (double)(((PetscReal)tmp1) / (PetscReal)sizeof(PetscScalar)))); 15841e02c4dSJunchao Zhang PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_PLIB); 1599306f9a3SSatish Balay } 1609566063dSJacob Faibussowitsch PetscCall(PetscInfo(obj, "Efficiency warning, copying array in XXXGetArray() due\n\ 161b122ec5aSJacob Faibussowitsch to alignment differences between C and Fortran\n")); 1629306f9a3SSatish Balay } 1639306f9a3SSatish Balay *res = itmp2; 1643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1659306f9a3SSatish Balay } 1669306f9a3SSatish Balay 1679306f9a3SSatish Balay /* 1689306f9a3SSatish Balay obj - the PETSc object where the scalar pointer came from 1699306f9a3SSatish Balay base - the Fortran array address 1709306f9a3SSatish Balay addr - the Fortran offset from base 1719306f9a3SSatish Balay N - the amount of data 1729306f9a3SSatish Balay 1739306f9a3SSatish Balay lx - the array space that is to be passed to XXXXRestoreArray() 1749306f9a3SSatish Balay */ 1759306f9a3SSatish Balay PetscErrorCode PetscScalarAddressFromFortran(PetscObject obj, PetscScalar *base, size_t addr, PetscInt N, PetscScalar **lx) 1769306f9a3SSatish Balay { 1779306f9a3SSatish Balay PetscInt shift; 178776b82aeSLisandro Dalcin PetscContainer container; 1799306f9a3SSatish Balay PetscScalar *tlx; 1809306f9a3SSatish Balay 1813ba16761SJacob Faibussowitsch PetscFunctionBegin; 1829566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery(obj, "GetArrayPtr", (PetscObject *)&container)); 1839306f9a3SSatish Balay if (container) { 1849566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)lx)); 1859306f9a3SSatish Balay tlx = base + addr; 1869306f9a3SSatish Balay 1879306f9a3SSatish Balay shift = *(PetscInt *)*lx; 1889566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(*lx, tlx, N)); 1899306f9a3SSatish Balay tlx = (PetscScalar *)(((char *)tlx) - shift); 190a297a907SKarl Rupp 1919566063dSJacob Faibussowitsch PetscCall(PetscFree(tlx)); 1929566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 193*dfef5ea7SSatish Balay PetscCall(PetscObjectCompose(obj, "GetArrayPtr", NULL)); 1949306f9a3SSatish Balay } else { 1959306f9a3SSatish Balay *lx = base + addr; 1969306f9a3SSatish Balay } 1973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1989306f9a3SSatish Balay } 1999306f9a3SSatish Balay 20083886165SBarry Smith #if defined(PETSC_HAVE_FORTRAN_CAPS) 201f66fdb6dSSatish Balay #define petscisinfornanscalar_ PETSCISINFORNANSCALAR 202f66fdb6dSSatish Balay #define petscisinfornanreal_ PETSCISINFORNANREAL 20383886165SBarry Smith #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 204f66fdb6dSSatish Balay #define petscisinfornanscalar_ petscisinfornanscalar 205f66fdb6dSSatish Balay #define petscisinfornanreal_ petscisinfornanreal 20683886165SBarry Smith #endif 20783886165SBarry Smith 20819caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanscalar_(PetscScalar *v) 20983886165SBarry Smith { 210ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanScalar(*v); 211f66fdb6dSSatish Balay } 212f66fdb6dSSatish Balay 21319caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanreal_(PetscReal *v) 214f66fdb6dSSatish Balay { 215ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanReal(*v); 21683886165SBarry Smith } 217