将数据存储在一维数组中

storing data in a 1D array

下面的代码可以工作,但是我在存储最终结果时遇到了问题。我解决了依赖于 t 的变量 x,所以我想将 x(t) 存储为一维数组。对于 t 的每个值,我都有不同的 x 值。

我在这样做时遇到了麻烦,因为我不知道 DO WHILE 循环必须进行多少次迭代,所以我不知道如何将数据写入可变大小的数组文件。截至目前,我只是将 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

您想将 x(t) 存储为单个变量——这实际上不可能1,因为 t 不是整数。您可以做的最好的事情是存储两个数组,t_array 用于所有 t 值,x_array 具有相应的 x 值。

您的 t 值从 ab,步长为 dt -- 您已将 dt 计算为 1/100 ab 之间的距离——因此 x 和 t 正好有 101 个值。 (没有舍入错误,您可能希望避免这种错误。)您可以将数组做得那么大。如果你想更灵活地使用数组长度,你可以使用可分配数组:

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

如果您不知道 xt 需要多少个值(例如,如果您想继续前进直到 phi 足够小或其他),然后您可以使用 move_alloc 命令在填充数组时增加数组。但这更复杂,请看这里:How to increase array size on-the-fly in Fortran? , a specific example of this you can see in my answer to the question Fortran array input

1您可以创建自定义类型,但我认为这太过分了。

假设函数的解计算了 N 次,每次都使用一组不同的自变量。每个解决方案都可以存储在一个数组中。

假设您不知道函数将被调用的次数 - 例如,您的函数计算的步长可能取决于收敛特性。在这种情况下,N 可能会超出您最初的预期。如果是这样,您可以将数据移动到一个新的更大的数组中(如 )。

或者,您可以将每个解决方案的输出存储在临时“临时”文件中,跟踪结果存储在那里的次数。一旦每次迭代都获得了解决方案并且 N 已知,我们就可以将输出数据读入适当大小的可分配数组中。然后,可以根据需要访问(通过索引号 1<=index<=N)每次迭代的输出。注意scratch文件关闭后会自动删除

例如:

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)