Что не так с моим кодом выделения Dynamin c? - PullRequest
1 голос
/ 25 февраля 2020

Это мой первый вопрос по инте rnet !!! Кроме того, это вопрос Фортана, и я только начал изучать этот язык. Поэтому, пожалуйста, прости мое невежество. В частности, я прошу прощения, если мой пример кода большой. Я сделал все возможное, чтобы уменьшить его размер до минимума, не подрывая его ясность.

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

Модель включает в себя простой запас (P), который уменьшается со временем с постоянной скоростью (10% за раз). Функция экспоненциальной задержки. Он принимает 4 аргумента: (ввод, время задержки, порядок задержки, ввод начальный). Обратите внимание, что выходные данные функции имеют 3 измерения. Первое измерение представляет различные экземпляры вызова задержки в программе. Второе измерение представляет порядок задержки. А третье измерение представляет время моделирования.

Основная задача здесь состояла в том, чтобы динамически распределять массивы, которые будут созданы функцией. Чтобы решить эту проблему, я попытался следовать приведенным здесь рекомендациям: Как увеличить размер массива на лету в Фортране? Программа, которую я написал, в некоторых случаях работает нормально, но не всегда , Например, если вы скомпилируете коды так, как они показаны ниже, вы получите правильный результат (правильное поведение - все переменные должны начинаться с 100 и постепенно уменьшаться). Но если вы измените порядок задержки в U с 5 на 6, тогда результаты будут неправильными (U начинается с 100, но затем колеблется, а иногда go выше 100).

Чего мне здесь не хватает? Что-то не так с тем, как я реализовал move_allo c? Или проблема в другом? Может ли это быть компилятор (gfortran), который выходит из строя? Заранее благодарен за помощь!

program model

  implicit none
  real, parameter :: start = 0, end = 10, dt = 0.25
  integer, parameter :: n = int((end - start)/dt)
  real, dimension(0:n+1) :: time, P, R, S, W, U
  integer :: i
  real, dimension(:,:,:), allocatable :: DN, temp

  P(0) = 100
  time(0) = start

  open (unit=10, file='out.txt', status='replace', action='write', position='rewind')
  write (10, *) 'Time, ', 'P, ', 'R, ', 'S, ', 'W, ', 'U'

  do i = 0, n
     P(i+1) = P(i) - .1*P(i)*dt
     R(i) = delay(P(i), 3.0, 4, P(0))
     S(i) = delay(P(i), 2.0, 4, P(0))
     W(i) = delay(P(i), 4.0, 5, P(0))
     U(i) = delay(P(i), 1.0, 5, P(0))
     time(i+1) = time(i) + dt
     write (10, *) time(i), ',', P(i), ',', R(i), ',', S(i), ',', W(i), ',', U(i)
  end do

  close (10)

contains
  function delay(input, dtime, order, init)
    real :: delay
    real, intent(in) :: input, dtime, init
    integer, save :: j, k
    integer, intent(in) :: order
    integer :: l
    data j /0/
    data k /0/
    if (j == i) then
       k = k + 1
       allocate(temp(1:k, 1:order, 0:n+1))
       if (allocated(DN)) temp(1:k-1, 1:order, 0:n+1) = DN
       call move_alloc(temp, DN)
    else
       k = 1
       j = i
    end if
    if (i == 0) then
       do l = 1, order
          DN(k, l, 0) = init * dtime / order
       end do
    end if
    DN(k, 1, i+1) = DN(k, 1, i) + (input - DN(k, 1, i) * order / dtime) * dt
    if (order > 1) then
       do l = 2, order
          DN(k, l, i+1) = DN(k, l, i) + (DN(k, l-1, i) - DN(k, l, i)) * order * dt / dtime
       end do
    end if
    delay = DN(k, order, i) * order / dtime
  end function delay

end program model

1 Ответ

2 голосов
/ 25 февраля 2020

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

В функции delay вы полагаетесь на состояние, сохраненное в DN, и ссылаться на разделы этого массива, используя фиктивный аргумент order. К сожалению, order неправильно привязан к фактической форме DN.

Рассмотрим строки

   allocate(temp(1:k, 1:order, 0:n+1))
   if (allocated(DN)) temp(1:k-1, 1:order, 0:n+1) = DN
   call move_alloc(temp, DN)

Понятно, что после того, как этот набор строк будет выполнен в первый раз DN выделен и имеет форму [1, 4, 42]. После второго одинаково ясно, что его форма [2 4 42]. Перейдите к третьей записи в функции, и order теперь 5, поэтому формы в назначении не совпадают.

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

...