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
425ebfa9e9SBarry Smith PetscFortranCallbackFn *PETSC_NULL_FUNCTION_Fortran = NULL;
439306f9a3SSatish Balay EXTERN_C_END
44dfef5ea7SSatish Balay void *PETSC_NULL_MPI_COMM_Fortran = NULL;
4599e0435eSBarry Smith
PetscIntAddressToFortran(const PetscInt * base,const PetscInt * addr)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
PetscIntAddressFromFortran(const PetscInt * base,size_t addr)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 */
PetscScalarAddressToFortran(PetscObject obj,PetscInt align,PetscScalar * base,PetscScalar * addr,PetscInt N,size_t * res)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 */
PetscScalarAddressFromFortran(PetscObject obj,PetscScalar * base,size_t addr,PetscInt N,PetscScalar ** lx)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) {
192*2a8381b2SBarry Smith PetscCall(PetscContainerGetPointer(container, 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
petscisinfornanscalar_(PetscScalar * v)21619caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanscalar_(PetscScalar *v)
21783886165SBarry Smith {
218ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanScalar(*v);
219f66fdb6dSSatish Balay }
220f66fdb6dSSatish Balay
petscisinfornanreal_(PetscReal * v)22119caf8f3SSatish Balay PETSC_EXTERN PetscBool petscisinfornanreal_(PetscReal *v)
222f66fdb6dSSatish Balay {
223ace3abfcSBarry Smith return (PetscBool)PetscIsInfOrNanReal(*v);
22483886165SBarry Smith }
225