将数据存储在一维数组中
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
值从 a
到 b
,步长为 dt
-- 您已将 dt
计算为 1/100 a
和 b
之间的距离——因此 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
如果您不知道 x
和 t
需要多少个值(例如,如果您想继续前进直到 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)
下面的代码可以工作,但是我在存储最终结果时遇到了问题。我解决了依赖于 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
值从 a
到 b
,步长为 dt
-- 您已将 dt
计算为 1/100 a
和 b
之间的距离——因此 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
如果您不知道 x
和 t
需要多少个值(例如,如果您想继续前进直到 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)