xref: /petsc/src/sys/ftn-custom/zutils.c (revision dfef5ea798a36ccc664ca1bbe435d183ec21e5c1)
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