Fortran 2D数组保存

3

我想在每次运行后保存和复用一个二维变量,但是出现了一些错误,比如无法保存自动对象等。下面是子程序:

subroutine dust_sum_test(ngrid,count,dust_in,dust_out)

!Subroutine to accumulate and release dust in timely manner
implicit none
integer,intent(in)::ngrid
integer,intent(in)::count
real,intent(in)::dust_in(ngrid)
real,intent(out)::dust_out(ngrid)

real,save::dmsdust(ngrid,99999) ! dummy local variable
integer::i
if (count.gt.1) then
  dmsdust(:,count)=dmsdust(:,count-1)+dust_in
  dust_out=dmsdust(:,count)
else
dust_out=dust_in
dmsdust(:,count)=0.0
endif

write(*,*)'The current count is = ', count
end subroutine dust_sum_test

我需要将当前值与先前的dmsdust值相加。请告诉我如何解决这个问题。

2个回答

8

Ross解释了错误的来源,并提供了一些明智的其他方法。除此之外,还有一个额外的方法没有在那个答案中提到。虽然我不说它更好,也不推荐它。

虽然自动对象不能有save属性,但可分配数组可以有。保存的本地可分配对象保留其分配状态,如果分配,则保留其形状(如果是数组)和值。

real, allocatable, save :: dmsdust(:,:)  ! Initially not allocated
...
! Our first-time initialization and subsequent consistency check follows
if (.not.allocated(dmsdust)) then
  allocate(dmsdust(ngrid,99999), source=0.)
else
  if (size(dmsdust,1).ne.ngrid) error stop ! or some other handling
end if

7
错误是正确的——您无法保存自动数组。这个特定错误的原因是:
每次执行dust_sum_test时,dmsdust都会根据输入形成“自动”数组,并且大小基于dmsdust。因此,dmsdust是自动数组。 您的子例程dust_sum_test每次运行时都会带入ngrid的值,但不能保证每次ngrid都相同。如果第一次运行时ngrid为1,第二次为2怎么办?如何保存dmsdust并改变形状?因此,编译器不允许您犯这个错误。
您问题的真正解决方案是改变您的方法。您的问题没有说明为什么需要存储dust的历史记录,但我认为您确实需要。但事实上,您没有必要在这个子例程中存储它!实际上,在子例程中存储它(作为save的值)意味着很难访问它。相反,我认为有两个其他的好选择。
使用模块
模块是现代Fortran的基石,可以存储数据和子例程。您可以在此模块中保留dust的历史记录,并在模块内外都可以访问它。实现将类似于:
module mymod
   implicit none
   real, allocatable :: dmsdust(:,:)
contains

subroutine init_dmsdust(ngrid)
   integer, intent(IN) :: ngrid
   allocate(dmsdust(ngrid,9999))
end subroutine init_dmsdust

subroutine dust_sum_test(ngrid,count,dust_in,dust_out)
   ! -- all your other code, but now dmsdust is not an automatic array
end subroutine dust_sum_test
end module mymod

在这种实现中,您必须在开始时调用init_dmsdust一次以分配存储空间。然后,在每次调用dmsdust时都会使用它。您可以通过向mymod添加访问子例程或从代码的另一部分use-ing变量dmsdust来访问dmsdust

将历史记录存储在调用例程中

这种解决方案更简单,但不够可扩展或优雅。不要把保持dmsdust的工作交给dust_sum_test,而是让负责调用dust_sum_test的任何例程分配和传递dmsdust。您的调用例程的一部分如下所示:
allocate(dmsdust(ngrid,9999))
do count=1,max  ! -- The main loop
   call dust_sum_test(ngrid,count,dust_in,dust_out,dmsdust)
   ! some other stuff
enddo

然后子程序看起来像这样:

subroutine dust_sum_test(ngrid,count,dust_in,dust_out,dmsdust)
   implicit none
   real, intent(INOUT) :: dmsdust(:,:)

   ! -- All the other stuff
end subroutine dust_sum_test

这样,调用程序就可以访问dmsdust,并且它的大小始终保持不变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接