【问题标题】:storing data in a 1D array将数据存储在一维数组中
【发布时间】:2020-08-07 02:15:59
【问题描述】:

下面的代码有效,但是我无法按照我的意愿存储最终结果。我求解取决于 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

【问题讨论】:

  • 在 do-loop 结束之前是否需要一维数组的内容来进行任何计算,或者这只是为了存储?
  • 我不需要循环结束之前的内容。 DO WHILE 循环结束后,我需要将数据用于代码中的其他计算。所以我想在我这样做之前把它保存好。感谢您的帮助。
  • 最简单的方法可能是使用临时文件。跟踪那里存储了多少项目,然后一旦完成,将其读入适当大小的可分配数组...
  • 好吧,这听起来很合理。你能提供一个基本的代码吗?如果是这样,我将能够将它应用到我的真实代码中。这段代码只是一个示例,我的实际代码有点复杂,我试图存储的函数是一个 5D 数组,而不是 1D 数组。非常感谢您对我的问题的帮助!

标签: fortran


【解决方案1】:

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

t 的值以dt 为单位从a 变为b -- 并且您将dt 计算为ab 之间距离的1/100 --因此,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?,您可以在我对问题Fortran array input 的回答中看到一个具体示例

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

【讨论】:

    【解决方案2】:

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

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

    或者,您可以将每个解决方案的输出存储在临时“临时”文件中,跟踪结果存储在那里的次数。一旦每次迭代都获得了解决方案并且知道N,我们就可以将输出数据读入适当大小的可分配数组。然后,可以根据需要访问每次迭代的输出(通过索引号1&lt;=index&lt;=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)
    
      
    

    【讨论】:

      猜你喜欢
      • 2019-08-08
      • 1970-01-01
      • 1970-01-01
      • 2016-07-10
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2018-02-12
      • 2019-11-27
      相关资源
      最近更新 更多