Несоответствие интерфейсов - функции высшего порядка

Я пытаюсь «воспроизвести» функции высшего порядка в fortran.

module rk4

contains



 pure function f(t,x) result (fx)
    real, dimension(1), intent(in) :: x
    real, intent(in) :: t
    real, dimension(1) ::  fx

    fx = x
  end function f

  function step(x,f,dt) result(xn)
    real, intent(in) :: dt
    real, intent(in),  dimension(:) :: x
    real, dimension(:), allocatable :: k1,k2,k3,k4,xn
    real, external :: f
    integer :: N

    N = size(x)

    allocate(k1(N))
    allocate(k2(N))
    allocate(k3(N))
    allocate(k4(N))

    k1 = f(t,x)
    k2 = f(t+0.5*dt,x+0.5*k1*dt)
    k3 = f(t+0.5*dt,x+0.5*k2*dt)
    k4 = f(t+dt,x+dt*k3)


    allocate(xn(N))
    xn = x + (dt/6.)*(k1 + 2*k2 + 2*k3 + k4)


    deallocate(k1)
    deallocate(k2)
    deallocate(k3)
    deallocate(k4)

  end function step

end module rk4

Когда модуль вызывается следующим образом

 real, dimension(1) :: x0 = 2

 x0 = step(x0,f,0.01)

Я получаю следующую ошибку

$gfortran -c test_rk4.f95 
test_rk4.f95:7.15:

  x0 = step(x0,f,0.01)
               1
Error: Interface mismatch in dummy procedure 'f' at (1): Type/rank mismatch in function result

Что могло быть причиной этого?


person tgoossens    schedule 22.03.2014    source источник


Ответы (1)


В сообщении об ошибке содержится жалоба на несовместимость функции f с фиктивным аргументом f.

Вы объявляете это как

   real, external :: f

это означает, что он должен возвращать скаляр, тогда как на самом деле функция f возвращает массив.

Одни и те же имена здесь не очень помогают пониманию. Я изменил имя фиктивного аргумента в следующем коде на g.

Самый простой способ решить эту проблему -

 pure function f(t,x) result (fx)
    real, dimension(1), intent(in) :: x
    real, intent(in) :: t
    real, dimension(1) ::  fx

    fx = x
  end function f

  function step(x,g,dt) result(xn)
    real, intent(in) :: dt
    real, intent(in),  dimension(:) :: x
    real, dimension(:), allocatable :: xn
    procedure(f) :: g

    !here call g, not f!!!

Оператор процедуры взят из Фортрана 2003 и заставляет процедуру фиктивного аргумента g иметь тот же интерфейс, что и процедура f.

В противном случае вы можете использовать блок интерфейса:

  function step(x,g,dt) result(xn)
    real, intent(in) :: dt
    real, intent(in),  dimension(:) :: x
    real, dimension(:), allocatable :: xn

    interface
      pure function g(t,x) result (fx)
        real, dimension(1), intent(in) :: x
        real, intent(in) :: t
        real, dimension(1) ::  fx
      end function g
    end interface

Внешний оператор следует использовать в современном коде только в некоторых исключительных случаях.

person Vladimir F    schedule 22.03.2014
comment
Спасибо. Но как можно расширить ваш код на более общий случай? x может быть вектором длины 2 (и, следовательно, f также должен возвращать вектор длины 2) - person tgoossens; 22.03.2014
comment
Я понял. Спасибо, я опубликую свое решение позже - person tgoossens; 22.03.2014
comment
Вы выбрали явную длину. Обычно предполагаемые массивы форм лучше. Тогда просто используйте fx(size(x)). Но это не так уж сильно связано с исходной ошибкой. - person Vladimir F; 22.03.2014