хранение данных в одномерном массиве - PullRequest
0 голосов
/ 07 августа 2020

Приведенный ниже код работает, однако у меня проблемы с сохранением окончательного результата, как хотелось бы. Я решаю переменную x, которая зависит от t, поэтому я хочу сохранить x (t) как одномерный массив. Для каждого значения t у меня есть другое значение x.

У меня проблемы с этим, так как я не знаю, сколько итераций обязательно займет DO WHILE l oop, поэтому я не знаю как записать данные в файл массива переменного размера. На данный момент я просто записываю результаты для x и t на экран.

Как я могу сохранить решение x (t) в одном одномерном массиве? Я хочу иметь такой массив, который, учитывая входное значение времени t, давал мне значение x в это время.

program RK4

implicit none

real :: a,b,x,dt,t,f,xn,k1,k2,k3,k4,phi
integer :: n=100.

write(*,*) 'enter an initial time, final time, x(0) = '
read(*,*) a,b,x

t = a !start time here... initial time
dt = (b-a)/real(n)

do while (t < b) 

k1 = f(x,t) 
k2 = f(x+k1*dt/2., t+dt/2.) 
k3 = f(x+k2*dt/2., t+dt/2.)
k4 = f(x+k3*dt, t+dt)
phi = (1./6.)*(k1+2.*k2+2.*k3+k4)

xn = x + dt*phi
t = t + dt 
x = xn 

write(*,*) 'the results for position and time are given by', x,t !This prints out the results, but I want to store this in a single variable as x(t).

end do


end program RK4

function f(x,t)
real, intent(in) :: x,t
f = -2*x
end function f

Ответы [ 2 ]

1 голос
/ 08 августа 2020

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

Предположим, вы не знаете, сколько раз функция будет вызываться - например, возможно, размер шага, на котором оценивается ваша функция, зависит от свойств сходимости. В этом случае N может превзойти ваши первоначальные ожидания. Если это так, вы можете переместить свои данные в новый массив большего размера (как указано chw21 ).

В качестве альтернативы вы можете сохранить вывод каждого решения во временном «рабочем» файле , отслеживая, сколько раз результаты сохраняются там. После того как решение было получено для каждой итерации и стало известно N, мы можем считывать выходные данные в выделяемый массив подходящего размера. Затем можно получить доступ к выходным данным каждой итерации (по номеру индекса 1<=index<=N) по мере необходимости. Обратите внимание, что рабочий файл будет автоматически удален после закрытия.

Например:

integer :: tmpfile                 !! scratch file logical unit number
integer :: n                       !! number of iterations
integer :: i                       !! index counter
real :: x,y,z                      !! output results 
real, allocatable :: results(:,:)  !! 2D array to store multiple values from each iteration

n = 0
open(newunit=tmpfile, status="scratch")
do while (...condition...)
  ...(get function output from the current iteration)...
  n = n + 1                        !! update the number of output iterations
  write(tmpfile, *) x,y,z          !! write your output values to the scratch file
enddo

allocate(results(n,3))             !! n is known. allocate storage array
rewind(tmpfile)                    !! important! return to the beginning of the scratch file
do i = 1,n
  read(tmpfile,*) results(i,:)     !! simplest, but list-directed 'read' is not only option
enddo
close(tmpfile)

  
1 голос
/ 07 августа 2020

Вы хотите сохранить x(t) как единственную переменную - это невозможно 1 , поскольку t не является целым числом. Лучшее, что вы можете сделать, - это сохранить два массива: t_array для всех значений t и x_array с соответствующими значениями x.

Ваши значения для t go из От a до b с шагом dt - и вы рассчитали dt как 1/100 расстояния между a и b - так что у вас будет ровно 101 значение для x и t . (Отсутствие ошибок округления, от которых вы, возможно, захотите защититься.) Вы можете просто сделать свой массив таким большим. Если вы хотите быть более гибкими с длиной массива, вы можете использовать распределяемые массивы:

real, allocatable :: t_array(:), x_array(:)
integer :: i

read (*,*) a, b, x, n

allocate(x_array(0:n), t_array(0:n))
dt = (b-a)/real(n)
t_array(:) = [(a + i*dt, i=0, n)]
x_array(0) = x

do i = 1, n
    t = t_array(i-1)    ! Makes it easier to type
    k1 = f(x, t)
    ...
    x = xn
    x_array(i) = xn
    print *, "Step: ", i, x_array(i), t_array(i)
end do

Если вы не знаете, сколько значений для x и t вам нужно (например, если вы хотите продолжать, пока phi не станет достаточно маленьким или что-то в этом роде), тогда вы можете использовать команду move_alloc для увеличения вашего массива по мере его заполнения. Но это более запутанно, см. Здесь: Как увеличить размер массива на лету в Фортране? , конкретный пример c этого вы можете увидеть в моем ответе на вопрос Массив Fortran input

1 Вы можете создавать собственные типы, но я думаю, что это будет излишним.

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