Могу ли я вернуть «дескриптор функции» из функции в Фортране? - PullRequest
1 голос
/ 13 октября 2019

Я портирую некоторый код MATLAB на Фортран и мне нужно повторить функциональность scatteredInterpolant . scatteredInterpolant берет набор точек выборки и возвращает, по сути, дескриптор функции, который может взять новую точку и вернуть интерполированное значение.

Я мог бы сделать это, возвращая производный тип с помощью функции «интерполировать» или чего-то ещепохоже, но я бы хотел, чтобы Фортран был как можно ближе к оригинальной MATLAB. Есть ли способ сгенерировать функцию во время выполнения и вернуть какой-либо способ доступа к функции из другой функции?

Ответы [ 2 ]

2 голосов
/ 14 октября 2019

Скорее всего, вы можете достичь желаемого поведения объектно-ориентированным способом,

module Interpolation_mod

    use iso_fortran_env, only: RK => real64
    implicit none

    type :: Interpolation_type
        real(RK)              :: linearInterpSlope, linearInterpIntercept
        real(RK), allocatable :: X(:), Value(:)
    contains
        procedure, pass :: functionHandle
    end type Interpolation_type

    interface Interpolation_type
        module procedure :: scatteredInterpolant
    end interface Interpolation_type

contains

    ! creates an Interpolation object and sets up all the essentials of calling functionHandle
    function scatteredInterpolant(X,Value) result(InterpolationObject)
        implicit none
        real(RK), intent(in)        :: X(2), Value(2)
        type(Interpolation_type)    :: InterpolationObject
        InterpolationObject%X = X
        InterpolationObject%Value = Value
        InterpolationObject%linearInterpSlope = ( Value(2) - Value(1) ) / (X(2) - X(1))
        InterpolationObject%linearInterpIntercept = Value(1) - InterpolationObject%linearInterpSlope * X(1)
    end function scatteredInterpolant

    ! equivalent of MATLAB functionHandle
    function functionHandle(InterpolationObject,x) result(functionValue)
        implicit none
        class(Interpolation_type), intent(in)   :: InterpolationObject
        real(RK), intent(in)                    :: x
        real(RK)                                :: functionValue
        if ( x < InterpolationObject%X(1) .or. x > InterpolationObject%X(2) ) then
            write(*,"(A)") "This is interpolation, not extrapolation."
            error stop
        else
            functionValue = InterpolationObject%linearInterpSlope * x + InterpolationObject%linearInterpIntercept
        end if
    end function functionHandle

end module Interpolation_mod

program test_Interpolation
use Interpolation_mod, only: RK, Interpolation_type
implicit none
type(Interpolation_type) :: Interpolation
Interpolation = Interpolation_type( X = [0._RK,1._RK], Value = [0._RK,1._RK] )
write(*,"(*(g0,:,' '))") "Interpolation(", 0.5, ") =", Interpolation%functionHandle(0.5_RK)
end program test_Interpolation
C:\> ifort main.f90 -o main.exe

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.4.245 Build 20190417
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.22.27905.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:main.exe
-subsystem:console
main.obj

C:\> main.exe
Interpolation( .5000000 ) = .5000000000000000
0 голосов
/ 13 октября 2019

То, что вы хотели бы, на самом деле замыкание определенного рода. Это невозможно в Фортране. Кроме того, синтаксис Fortran не позволяет напрямую вызывать производный тип. Вам понадобится один из косвенных подходов, которые вы предлагаете. Вы также можете использовать модуль, но он допускает только один экземпляр такого замыкания / функции.

Fortran позволяет возвращать указатель на функцию, но этого недостаточно для того, что вы описываете. См. Также связанные методы в минимизации Фортрана функции с дополнительными аргументами и в функциях, связанных там под Связанным. Вероятно, он не будет делать именно то, что вам нужно, но это связано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...