Передача дополнительных аргументов в метод Ньютона в Фортране - PullRequest
0 голосов
/ 06 сентября 2018

У меня проблемы с реализацией подхода для вызова метода Ньютона в программе на Фортране. Поэтому я хочу использовать метод Ньютона для решения уравнения, следующего за ссылкой

Однако моя программа немного отличается от приведенного выше примера. В моем случае уравнение требует некоторой дополнительной информации, которая создается во время выполнения.

subroutine solve(f, fp, x0, x, iters, debug)

, что означает, что f вычисляется не только на основе x, но также и нескольких других переменных (но x является неизвестным).

У меня есть решение, которое работает только для простого случая: Я использовал модуль, чтобы включить решатель Ньютона. Я также определил производный тип данных для хранения всех аргументов внутри модуля. Теперь это работает хорошо.

Мой вопрос: мне нужно многократно вызывать метод Ньютона, и каждый раз аргументы разные. Как мне спроектировать структуру модулей? Или я должен использовать другое решение?

Я привел простой пример ниже:

module solver
  type argu
    integer :: m
  end type argu
  type(argu):: aArgu_test  !should I put here?
  contains
    subroutine solve(f, fp, x0, x, iters, debug)
       ...
       !m is used inside here
    end subroutine solve
    subroutine set_parameter(m_in)
       aArgu%m = m_in
    end subroutine set_parameter()

end module solver

И вызывающий модуль:

!only one set of argument, but used many times
module A
   use module solver

   do i = 1, 4, 1
     set_parameter(i) 
     !call Newtow method
     ...
   enddo
end module A

!can I use an array for argu type if possible?
module B
   use module solver
   type(argu), dimension(:), allocable :: aArgu ! or should I put here or inside solver module?

end module B

Насколько я понимаю, если я помещу объект аргумента в модуль решателя, то все вызовы решателя будут использовать одни и те же аргументы (я все еще могу сохранить их все в модуле А, используя вышеуказанный метод). В таком случае мне нужно обновлять аргументы во время каждого цикла for?

Поскольку программа работает с использованием MPI / OpenMP, я хочу убедиться, что между потоками нет перезаписей. Спасибо.

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

В современном Фортране есть общий шаблон для проблемы, с которой вы сталкиваетесь ( приложение с частичной функцией ). В отличие от других языков, Fortran не имеет замыканий функций, поэтому создание лексической области видимости для функции немного «запутано» и ограничено.

Вы действительно должны рассмотреть вопрос о повторном посещении всех ссылок @VladmirF на комментарий, большинство из которых применимы непосредственно к вашему делу. Я приведу вам пример решения.

Это решение без использования типа оболочки. Я буду использовать функцию, включенную в стандарт Fortran 2008: передачу внутренней процедуры в качестве аргумента. Он совместим с последними версиями gfortran, Intel и многими другими. Если вы не можете получить доступ к компилятору с этой функцией или предпочитаете решение с производным типом, вы можете обратиться к этому ответу.

module without_custom_type
  use, intrinsic :: iso_fortran_env, only: r8 => real64
  use :: solver

contains
  subroutine solve_quad(a, b, c, x0, x, iters, debug)
    integer, intent(in) :: a, b, c
    real(r8), intent(in) :: x0
    real(r8), intent(out) :: x
    integer, intent(out) :: iters
    logical, intent(in) :: debug

    call solve(f, fp, x0, x, iters, debug)

  contains
    real(r8) function f(x)
      real(r8),intent(in) :: x
      f = a * x * x + b * x + c
    end

    real(r8) function fp(x)
      real(r8),intent(in) :: x
      fp = 2 * a * x + b
    end
  end
end

Обоснование этого кода: поскольку f и fp лежат внутри процедуры solve_quad, они имеют доступ к аргументам a, b и c по ассоциации хоста, не касаясь подписи этих функций. Результирующий эффект похож на изменение арности функции.

Тестируя его с помощью gfortran 8.0 и реализации solver по ссылке, которой вы поделились, я получил следующее:

program test
  use, intrinsic :: iso_fortran_env, only: r8 => real64
  use :: without_custom_type
  implicit none

  real(r8) :: x, x0
  integer :: iters
  integer :: a = 1, b = -5, c = 4

  x0 = 0
  call solve_quad(a, b, c, x0, x, iters, .false.)
  print *, x, iters
  ! output: 1.0000000000000000, 5

  x0 = 7
  call solve_quad(a, b, c, x0, x, iters, .false.)
  print *, x, iters
  ! output: 4.0000000000000000, 6    
end
0 голосов
/ 06 сентября 2018

После обсуждения с коллегой у меня есть решение моего вопроса 2.

Если у нас есть только один объект аргумента для модуля решателя, тогда все вызывающие получат доступ к одним и тем же аргументам, поскольку они совместно используют одно и то же пространство памяти.

Чтобы избежать этого, мы хотим передать объект аргумента в качестве аргумента в решатель. Поэтому вместо того, чтобы использовать подпрограмму решателя по умолчанию, мы переписываем метод Ньютона, чтобы он мог принимать дополнительный аргумент.

(Я использовал простейшую подпрограмму Ньютона ранее, потому что хотел сохранить ее нетронутой.)

Таким образом, мы определим массив объектов аргументов и передадим их во время выполнения.

Спасибо за комментарии.

...