#include #include #include #include #if defined(PETSC_HAVE_FORTRAN_CAPS) #define matdestroymatrices_ MATDESTROYMATRICES #define matdestroysubmatrices_ MATDESTROYSUBMATRICES #define matgetrowij_ MATGETROWIJ #define matrestorerowij_ MATRESTOREROWIJ #define matgetrow_ MATGETROW #define matrestorerow_ MATRESTOREROW #define matseqaijgetarray_ MATSEQAIJGETARRAY #define matseqaijrestorearray_ MATSEQAIJRESTOREARRAY #define matdensegetarray_ MATDENSEGETARRAY #define matdensegetarrayread_ MATDENSEGETARRAYREAD #define matdenserestorearray_ MATDENSERESTOREARRAY #define matdenserestorearrayread_ MATDENSERESTOREARRAYREAD #define matcreatesubmatrices_ MATCREATESUBMATRICES #define matcreatesubmatricesmpi_ MATCREATESUBMATRICESMPI #define matnullspacesetfunction_ MATNULLSPACESETFUNCTION #define matfindnonzerorows_ MATFINDNONZEROROWS #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) #define matdestroymatrices_ matdestroymatrices #define matdestroysubmatrices_ matdestroysubmatrices #define matgetrowij_ matgetrowij #define matrestorerowij_ matrestorerowij #define matgetrow_ matgetrow #define matrestorerow_ matrestorerow #define matseqaijgetarray_ matseqaijgetarray #define matseqaijrestorearray_ matseqaijrestorearray #define matdensegetarray_ matdensegetarray #define matdensegetarrayread_ matdensegetarrayread #define matdenserestorearray_ matdenserestorearray #define matdenserestorearrayread_ matdenserestorearrayread #define matcreatesubmatrices_ matcreatesubmatrices #define matcreatesubmatricesmpi_ matcreatesubmatricesmpi #define matnullspacesetfunction_ matnullspacesetfunction #define matfindnonzerorows_ matfindnonzerorows #endif static PetscErrorCode ournullfunction(MatNullSpace sp, Vec x, void *ctx) { PetscCallFortranVoidFunction((*(void (*)(MatNullSpace *, Vec *, void *, PetscErrorCode *))(((PetscObject)sp)->fortran_func_pointers[0]))(&sp, &x, ctx, &ierr)); return PETSC_SUCCESS; } PETSC_EXTERN void matnullspacesetfunction_(MatNullSpace *sp, PetscErrorCode (*rem)(MatNullSpace, Vec, void *), void *ctx, PetscErrorCode *ierr) { PetscObjectAllocateFortranPointers(*sp, 1); ((PetscObject)*sp)->fortran_func_pointers[0] = (PetscVoidFn *)rem; *ierr = MatNullSpaceSetFunction(*sp, ournullfunction, ctx); } PETSC_EXTERN void matgetrowij_(Mat *B, PetscInt *shift, PetscBool *sym, PetscBool *blockcompressed, PetscInt *n, PetscInt *ia, size_t *iia, PetscInt *ja, size_t *jja, PetscBool *done, PetscErrorCode *ierr) { const PetscInt *IA, *JA; *ierr = MatGetRowIJ(*B, *shift, *sym, *blockcompressed, n, &IA, &JA, done); if (*ierr) return; *iia = PetscIntAddressToFortran(ia, (PetscInt *)IA); *jja = PetscIntAddressToFortran(ja, (PetscInt *)JA); } PETSC_EXTERN void matrestorerowij_(Mat *B, PetscInt *shift, PetscBool *sym, PetscBool *blockcompressed, PetscInt *n, PetscInt *ia, size_t *iia, PetscInt *ja, size_t *jja, PetscBool *done, PetscErrorCode *ierr) { const PetscInt *IA = PetscIntAddressFromFortran(ia, *iia), *JA = PetscIntAddressFromFortran(ja, *jja); *ierr = MatRestoreRowIJ(*B, *shift, *sym, *blockcompressed, n, &IA, &JA, done); } /* This is a poor way of storing the column and value pointers generated by MatGetRow() to be returned with MatRestoreRow() but there is not natural,good place else to store them. Hence Fortran programmers can only have one outstanding MatGetRows() at a time. */ static int matgetrowactive = 0; static const PetscInt *my_ocols = NULL; static const PetscScalar *my_ovals = NULL; PETSC_EXTERN void matgetrow_(Mat *mat, PetscInt *row, PetscInt *ncols, PetscInt *cols, PetscScalar *vals, PetscErrorCode *ierr) { const PetscInt **oocols = &my_ocols; const PetscScalar **oovals = &my_ovals; if (matgetrowactive) { *ierr = PetscError(PETSC_COMM_SELF, __LINE__, "MatGetRow_Fortran", __FILE__, PETSC_ERR_ARG_WRONGSTATE, PETSC_ERROR_INITIAL, "Cannot have two MatGetRow() active simultaneously\n\ call MatRestoreRow() before calling MatGetRow() a second time"); *ierr = PETSC_ERR_ARG_WRONGSTATE; return; } CHKFORTRANNULLINTEGER(cols); if (!cols) oocols = NULL; CHKFORTRANNULLSCALAR(vals); if (!vals) oovals = NULL; *ierr = MatGetRow(*mat, *row, ncols, oocols, oovals); if (*ierr) return; if (oocols) { *ierr = PetscArraycpy(cols, my_ocols, *ncols); if (*ierr) return; } if (oovals) { *ierr = PetscArraycpy(vals, my_ovals, *ncols); if (*ierr) return; } matgetrowactive = 1; } PETSC_EXTERN void matrestorerow_(Mat *mat, PetscInt *row, PetscInt *ncols, PetscInt *cols, PetscScalar *vals, PetscErrorCode *ierr) { const PetscInt **oocols = &my_ocols; const PetscScalar **oovals = &my_ovals; if (!matgetrowactive) { *ierr = PetscError(PETSC_COMM_SELF, __LINE__, "MatRestoreRow_Fortran", __FILE__, PETSC_ERR_ARG_WRONGSTATE, PETSC_ERROR_INITIAL, "Must call MatGetRow() first"); *ierr = PETSC_ERR_ARG_WRONGSTATE; return; } CHKFORTRANNULLINTEGER(cols); if (!cols) oocols = NULL; CHKFORTRANNULLSCALAR(vals); if (!vals) oovals = NULL; *ierr = MatRestoreRow(*mat, *row, ncols, oocols, oovals); matgetrowactive = 0; } PETSC_EXTERN void matseqaijgetarray_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { PetscScalar *mm; PetscInt m, n; *ierr = MatSeqAIJGetArray(*mat, &mm); if (*ierr) return; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressToFortran((PetscObject)*mat, 1, fa, mm, m * n, ia); if (*ierr) return; } PETSC_EXTERN void matseqaijrestorearray_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { PetscScalar *lx; PetscInt m, n; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressFromFortran((PetscObject)*mat, fa, *ia, m * n, &lx); if (*ierr) return; *ierr = MatSeqAIJRestoreArray(*mat, &lx); if (*ierr) return; } PETSC_EXTERN void matdensegetarray_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { PetscScalar *mm; PetscInt m, n; *ierr = MatDenseGetArray(*mat, &mm); if (*ierr) return; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressToFortran((PetscObject)*mat, 1, fa, mm, m * n, ia); if (*ierr) return; } PETSC_EXTERN void matdenserestorearray_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { PetscScalar *lx; PetscInt m, n; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressFromFortran((PetscObject)*mat, fa, *ia, m * n, &lx); if (*ierr) return; *ierr = MatDenseRestoreArray(*mat, &lx); if (*ierr) return; } PETSC_EXTERN void matdensegetarrayread_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { const PetscScalar *mm; PetscInt m, n; *ierr = MatDenseGetArrayRead(*mat, &mm); if (*ierr) return; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressToFortran((PetscObject)*mat, 1, fa, (PetscScalar *)mm, m * n, ia); if (*ierr) return; } PETSC_EXTERN void matdenserestorearrayread_(Mat *mat, PetscScalar *fa, size_t *ia, PetscErrorCode *ierr) { const PetscScalar *lx; PetscInt m, n; *ierr = MatGetSize(*mat, &m, &n); if (*ierr) return; *ierr = PetscScalarAddressFromFortran((PetscObject)*mat, fa, *ia, m * n, (PetscScalar **)&lx); if (*ierr) return; *ierr = MatDenseRestoreArrayRead(*mat, &lx); if (*ierr) return; } /* MatCreateSubmatrices() is slightly different from C since the Fortran provides the array to hold the submatrix objects,while in C that array is allocated by the MatCreateSubmatrices() */ PETSC_EXTERN void matcreatesubmatrices_(Mat *mat, PetscInt *n, IS *isrow, IS *iscol, MatReuse *scall, Mat *smat, PetscErrorCode *ierr) { Mat *lsmat; PetscInt i; if (*scall == MAT_INITIAL_MATRIX) { *ierr = MatCreateSubMatrices(*mat, *n, isrow, iscol, *scall, &lsmat); for (i = 0; i <= *n; i++) { /* lsmat[*n] might be a dummy matrix for saving data structure */ smat[i] = lsmat[i]; } *ierr = PetscFree(lsmat); } else { *ierr = MatCreateSubMatrices(*mat, *n, isrow, iscol, *scall, &smat); } } /* MatCreateSubmatrices() is slightly different from C since the Fortran provides the array to hold the submatrix objects,while in C that array is allocated by the MatCreateSubmatrices() */ PETSC_EXTERN void matcreatesubmatricesmpi_(Mat *mat, PetscInt *n, IS *isrow, IS *iscol, MatReuse *scall, Mat *smat, PetscErrorCode *ierr) { Mat *lsmat; PetscInt i; if (*scall == MAT_INITIAL_MATRIX) { *ierr = MatCreateSubMatricesMPI(*mat, *n, isrow, iscol, *scall, &lsmat); for (i = 0; i <= *n; i++) { /* lsmat[*n] might be a dummy matrix for saving data structure */ smat[i] = lsmat[i]; } *ierr = PetscFree(lsmat); } else { *ierr = MatCreateSubMatricesMPI(*mat, *n, isrow, iscol, *scall, &smat); } } /* MatDestroyMatrices() is slightly different from C since the Fortran does not free the array of matrix objects, while in C that the array is freed */ PETSC_EXTERN void matdestroymatrices_(PetscInt *n, Mat *smat, PetscErrorCode *ierr) { PetscInt i; for (i = 0; i < *n; i++) { PETSC_FORTRAN_OBJECT_F_DESTROYED_TO_C_NULL(&smat[i]); *ierr = MatDestroy(&smat[i]); if (*ierr) return; PETSC_FORTRAN_OBJECT_C_NULL_TO_F_DESTROYED(&smat[i]); } } /* MatDestroySubMatrices() is slightly different from C since the Fortran provides the array to hold the submatrix objects, while in C that array is allocated by the MatCreateSubmatrices() An extra matrix may be stored at the end of the array, hence the check see MatDestroySubMatrices_Dummy() */ PETSC_EXTERN void matdestroysubmatrices_(PetscInt *n, Mat *smat, PetscErrorCode *ierr) { Mat *lsmat; PetscInt i; if (*n == 0) return; *ierr = PetscMalloc1(*n + 1, &lsmat); if (*ierr) return; for (i = 0; i <= *n; i++) { lsmat[i] = smat[i]; } *ierr = MatDestroySubMatrices(*n, &lsmat); if (*ierr) return; for (i = 0; i <= *n; i++) { PETSC_FORTRAN_OBJECT_C_NULL_TO_F_DESTROYED(&smat[i]); } }