Fortran:读取输入
Fortran: reading input
我正在尝试 运行 一个非常大的 FORTRAN 模型,所以我无法提供所有涉及的代码,但我希望我能提供足够的信息以使其有意义。
代码编译良好(使用 Intel 2016.0.109 编译器、OpenMPI 1.10.2 和 HDF5 1.8.17)。
当我尝试 运行 它时,它告诉我我的两个输入(称为 NZG 和 NZS)设置为 -999,因此它失败了。
> >>>> opspec_grid error! in your namelist!
> ---> Reason: Too few soil layers. Set it to at least 2. Your nzg is currently set to -999...
> ---> Reason: Too few maximum # of snow layers. Set it to at least 1. Your nzs is currently set to -999.
然而,在输入文件中,它们确实被指定为
NL%NZG = 9
NL%NZS = 1
我遍历了所有与这些变量有某种关系的模块,但找不到任何应该离开 rails 的地方。
所以我现在开始想,也许值的读取方式有问题。输入文件是一个文本文件。变量在读取它们的模块中指定为整数,仅供参考。
我应该检查特殊字符还是什么?我知道 Fortran 对输入很挑剔...
编辑:在追溯错误的代码序列下方
1)主模块开启名单
write (unit=*,fmt='(a)') 'Reading namelist information'
call read_nl(trim(name_name))
read_nl
是
subroutine read_nl(namelist_name)
use ename_coms, only : nl & ! intent(inout)
, init_ename_vars ! ! subroutine
implicit none
!----- Arguments. ----------------------------------------------------------------------!
character(len=*), intent(in) :: namelist_name
!----- Local variables. ----------------------------------------------------------------!
logical :: fexists
!----- Name lists. ---------------------------------------------------------------------!
namelist /ED_NL/ nl
!---------------------------------------------------------------------------------------!
!----- Open the namelist file. ---------------------------------------------------------!
inquire (file=trim(namelist_name),exist=fexists)
if (.not. fexists) then
call fatal_error('The namelist file '//trim(namelist_name)//' is missing.' &
,'read_nl','ed_load_namelist.f90')
end if
!----- Initialise the name list with absurd, undefined values. -------------------------!
call init_ename_vars(nl)
!----- Read grid point and options information from the namelist. ----------------------!
open (unit=10, status='OLD', file=namelist_name)
read (unit=10, nml=ED_NL)
close(unit=10)
return
end subroutine read_nl
2) 然后是关于如何(哪些变量)从名单(输入)中读取的细节
write (unit=*,fmt='(a)') 'Copying namelist'
call copy_nl('ALL_CASES')
if (runtype == 'HISTORY') then
call copy_nl('HISTORY')
else
call copy_nl('NOT_HISTORY')
end if
我的模拟是 'NOT_HISTORY'
:指定了 copy_nl('ALL_CASES')
,因此它读取了一些名单变量,包括变量 'runtype'
- 然后在该 if-else 语句中使用.
3) 然后copy_nl('NOT_HISTORY')
就是下面的,这里是定义nzg和nzs的地方
subroutine copy_nl(copy_type)
use grid_coms , only : time & ! intent(out)
, centlon & ! intent(out)
, centlat & ! intent(out)
, deltax & ! intent(out)
, deltay & ! intent(out)
, nnxp & ! intent(out)
, nnyp & ! intent(out)
, nstratx & ! intent(out)
, nstraty & ! intent(out)
, polelat & ! intent(out)
, polelon & ! intent(out)
, ngrids & ! intent(out)
, timmax & ! intent(out)
, time & ! intent(out)
, nzg & ! intent(out)
, nzs ! ! intent(out)
implicit none
!----- Arguments. ----------------------------------------------------------------------!
character(len=*), intent(in) :: copy_type
!----- Internal variables. -------------------------------------------------------------!
integer :: ifm
!---------------------------------------------------------------------------------------!
!---------------------------------------------------------------------------------------!
! Here we decide which variables we should copy based on the input variable. !
!---------------------------------------------------------------------------------------!
select case (trim(copy_type))
case ('NOT_HISTORY')
itimea = nl%itimea
idatea = nl%idatea
imontha = nl%imontha
iyeara = nl%iyeara
nzg = nl%nzg
nzs = nl%nzs
slz(1:nzgmax) = nl%slz(1:nzgmax)
current_time%year = iyeara
current_time%month = imontha
current_time%date = idatea
current_time%time = real(int(real(itimea) * 0.01)) * hr_sec &
+ (real(itimea) * 0.01 - real(int(real(itimea)*0.01))) &
* 100.0 * min_sec
time = 0.0d0
请注意,我没有将所有模块和变量都放在 use
中,否则 post 会变得非常长。
仅供参考,模块 grid_coms
指定变量的类型。见下面相关部分(整个模块就是一个变量列表,没有别的)
module grid_coms
integer :: nzg ! Number of soil levels
integer :: nzs ! Number of snow/surface water levels
end module grid_coms
4) 回到主模块,然后调用 ed_opspec_grid
来检查变量是否有意义,这就是出错的地方。同样,use
变量在开始时被初始化,我把它留在这里。
subroutine ed_opspec_grid
!---------------------------------------------------------------------------------------!
! Check whether soil layers are reasonable, i.e, enough layers, sorted from the !
! deepest to the shallowest. !
!---------------------------------------------------------------------------------------!
if (nzg < 2) then
write (reason,'(a,1x,i4,a)') &
'Too few soil layers. Set it to at least 2. Your nzg is currently set to' &
,nzg,'...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
elseif (nzg > nzgmax) then
write (reason,'(2(a,1x,i5,a))') &
'The number of soil layers cannot be greater than ',nzgmax,'.' &
,' Your nzg is currently set to',nzg,'.'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
do k=1,nzg
if (slz(k) > -.001) then
write (reason,'(a,1x,i4,1x,a,1x,es14.7,a)') &
'Your soil level #',k,'is not enough below ground. It is currently set to' &
,slz(k),', make it deeper than -0.001...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
end do
do k=1,nzg-1
if (slz(k)-slz(k+1) > .001) then
write (reason,'(2(a,1x,i4,1x),a,2x,a,1x,es14.7,1x,a,1x,es14.7,a)') &
'Soil layers #',k,'and',k+1,'are not enough apart (i.e. > 0.001).' &
,'They are currently set as ',slz(k),'and',slz(k+1),'...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
end do
end subroutine ed_opspec_grid
请注意,这不是此子例程中的第一次检查。在此部分之前检查了其他变量(我将其排除在外),但这是第一条错误消息。这让我觉得也许部分输入可以正常读取,而有些则不能。
最后,再次强调一下,这是一个非常大的项目,我真的无法显示所有代码,这就是为什么我将问题框得很简单:Fortran是否有任何(文本)输入要求,我可能遗漏了(特殊字符,returns,可能因系统不同而不同?)。
另外,这段代码被很多研究人员在不同的平台上使用,所以我非常怀疑代码本身有什么问题......(但如果我错了请告诉我)。
你没有给我们足够的数据来查明问题,所以我只告诉你我在使用名单时遇到的两个问题:
如果您从同一个文件中读取多个(甚至不同的)名称列表,则顺序很重要:如果在文件名称列表中 a
在名称列表 b
之前,但代码读取首先是 b
,然后它将找不到 a
,除非您倒回文件。
如果数据文件中的名单不包含一个或多个值,这些值将保持不变。很可能在代码中这些变量被专门设置为 -999
,以便注意到它们的缺失。所以仔细检查数据文件是否正确。查找可能会过早结束名单的 /
字符
总而言之,为了正确评估正在发生的事情,我们至少需要三件事:
声明块,包括构成此名单一部分的所有变量,以及namelist /.../ ...,...,...
规范
声明此特定名单的名单文件部分,以及
是否有任何其他名称列表也在同一文件中,以及它们是否在此名称列表之前或之后(在文件中和代码中)
我正在尝试 运行 一个非常大的 FORTRAN 模型,所以我无法提供所有涉及的代码,但我希望我能提供足够的信息以使其有意义。 代码编译良好(使用 Intel 2016.0.109 编译器、OpenMPI 1.10.2 和 HDF5 1.8.17)。
当我尝试 运行 它时,它告诉我我的两个输入(称为 NZG 和 NZS)设置为 -999,因此它失败了。
> >>>> opspec_grid error! in your namelist!
> ---> Reason: Too few soil layers. Set it to at least 2. Your nzg is currently set to -999...
> ---> Reason: Too few maximum # of snow layers. Set it to at least 1. Your nzs is currently set to -999.
然而,在输入文件中,它们确实被指定为
NL%NZG = 9
NL%NZS = 1
我遍历了所有与这些变量有某种关系的模块,但找不到任何应该离开 rails 的地方。 所以我现在开始想,也许值的读取方式有问题。输入文件是一个文本文件。变量在读取它们的模块中指定为整数,仅供参考。 我应该检查特殊字符还是什么?我知道 Fortran 对输入很挑剔...
编辑:在追溯错误的代码序列下方
1)主模块开启名单
write (unit=*,fmt='(a)') 'Reading namelist information'
call read_nl(trim(name_name))
read_nl
是
subroutine read_nl(namelist_name)
use ename_coms, only : nl & ! intent(inout)
, init_ename_vars ! ! subroutine
implicit none
!----- Arguments. ----------------------------------------------------------------------!
character(len=*), intent(in) :: namelist_name
!----- Local variables. ----------------------------------------------------------------!
logical :: fexists
!----- Name lists. ---------------------------------------------------------------------!
namelist /ED_NL/ nl
!---------------------------------------------------------------------------------------!
!----- Open the namelist file. ---------------------------------------------------------!
inquire (file=trim(namelist_name),exist=fexists)
if (.not. fexists) then
call fatal_error('The namelist file '//trim(namelist_name)//' is missing.' &
,'read_nl','ed_load_namelist.f90')
end if
!----- Initialise the name list with absurd, undefined values. -------------------------!
call init_ename_vars(nl)
!----- Read grid point and options information from the namelist. ----------------------!
open (unit=10, status='OLD', file=namelist_name)
read (unit=10, nml=ED_NL)
close(unit=10)
return
end subroutine read_nl
2) 然后是关于如何(哪些变量)从名单(输入)中读取的细节
write (unit=*,fmt='(a)') 'Copying namelist'
call copy_nl('ALL_CASES')
if (runtype == 'HISTORY') then
call copy_nl('HISTORY')
else
call copy_nl('NOT_HISTORY')
end if
我的模拟是 'NOT_HISTORY'
:指定了 copy_nl('ALL_CASES')
,因此它读取了一些名单变量,包括变量 'runtype'
- 然后在该 if-else 语句中使用.
3) 然后copy_nl('NOT_HISTORY')
就是下面的,这里是定义nzg和nzs的地方
subroutine copy_nl(copy_type)
use grid_coms , only : time & ! intent(out)
, centlon & ! intent(out)
, centlat & ! intent(out)
, deltax & ! intent(out)
, deltay & ! intent(out)
, nnxp & ! intent(out)
, nnyp & ! intent(out)
, nstratx & ! intent(out)
, nstraty & ! intent(out)
, polelat & ! intent(out)
, polelon & ! intent(out)
, ngrids & ! intent(out)
, timmax & ! intent(out)
, time & ! intent(out)
, nzg & ! intent(out)
, nzs ! ! intent(out)
implicit none
!----- Arguments. ----------------------------------------------------------------------!
character(len=*), intent(in) :: copy_type
!----- Internal variables. -------------------------------------------------------------!
integer :: ifm
!---------------------------------------------------------------------------------------!
!---------------------------------------------------------------------------------------!
! Here we decide which variables we should copy based on the input variable. !
!---------------------------------------------------------------------------------------!
select case (trim(copy_type))
case ('NOT_HISTORY')
itimea = nl%itimea
idatea = nl%idatea
imontha = nl%imontha
iyeara = nl%iyeara
nzg = nl%nzg
nzs = nl%nzs
slz(1:nzgmax) = nl%slz(1:nzgmax)
current_time%year = iyeara
current_time%month = imontha
current_time%date = idatea
current_time%time = real(int(real(itimea) * 0.01)) * hr_sec &
+ (real(itimea) * 0.01 - real(int(real(itimea)*0.01))) &
* 100.0 * min_sec
time = 0.0d0
请注意,我没有将所有模块和变量都放在 use
中,否则 post 会变得非常长。
仅供参考,模块 grid_coms
指定变量的类型。见下面相关部分(整个模块就是一个变量列表,没有别的)
module grid_coms
integer :: nzg ! Number of soil levels
integer :: nzs ! Number of snow/surface water levels
end module grid_coms
4) 回到主模块,然后调用 ed_opspec_grid
来检查变量是否有意义,这就是出错的地方。同样,use
变量在开始时被初始化,我把它留在这里。
subroutine ed_opspec_grid
!---------------------------------------------------------------------------------------!
! Check whether soil layers are reasonable, i.e, enough layers, sorted from the !
! deepest to the shallowest. !
!---------------------------------------------------------------------------------------!
if (nzg < 2) then
write (reason,'(a,1x,i4,a)') &
'Too few soil layers. Set it to at least 2. Your nzg is currently set to' &
,nzg,'...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
elseif (nzg > nzgmax) then
write (reason,'(2(a,1x,i5,a))') &
'The number of soil layers cannot be greater than ',nzgmax,'.' &
,' Your nzg is currently set to',nzg,'.'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
do k=1,nzg
if (slz(k) > -.001) then
write (reason,'(a,1x,i4,1x,a,1x,es14.7,a)') &
'Your soil level #',k,'is not enough below ground. It is currently set to' &
,slz(k),', make it deeper than -0.001...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
end do
do k=1,nzg-1
if (slz(k)-slz(k+1) > .001) then
write (reason,'(2(a,1x,i4,1x),a,2x,a,1x,es14.7,1x,a,1x,es14.7,a)') &
'Soil layers #',k,'and',k+1,'are not enough apart (i.e. > 0.001).' &
,'They are currently set as ',slz(k),'and',slz(k+1),'...'
call opspec_fatal(reason,'opspec_grid')
ifaterr=ifaterr+1
end if
end do
end subroutine ed_opspec_grid
请注意,这不是此子例程中的第一次检查。在此部分之前检查了其他变量(我将其排除在外),但这是第一条错误消息。这让我觉得也许部分输入可以正常读取,而有些则不能。
最后,再次强调一下,这是一个非常大的项目,我真的无法显示所有代码,这就是为什么我将问题框得很简单:Fortran是否有任何(文本)输入要求,我可能遗漏了(特殊字符,returns,可能因系统不同而不同?)。 另外,这段代码被很多研究人员在不同的平台上使用,所以我非常怀疑代码本身有什么问题......(但如果我错了请告诉我)。
你没有给我们足够的数据来查明问题,所以我只告诉你我在使用名单时遇到的两个问题:
如果您从同一个文件中读取多个(甚至不同的)名称列表,则顺序很重要:如果在文件名称列表中
a
在名称列表b
之前,但代码读取首先是b
,然后它将找不到a
,除非您倒回文件。如果数据文件中的名单不包含一个或多个值,这些值将保持不变。很可能在代码中这些变量被专门设置为
-999
,以便注意到它们的缺失。所以仔细检查数据文件是否正确。查找可能会过早结束名单的/
字符
总而言之,为了正确评估正在发生的事情,我们至少需要三件事:
声明块,包括构成此名单一部分的所有变量,以及
namelist /.../ ...,...,...
规范声明此特定名单的名单文件部分,以及
是否有任何其他名称列表也在同一文件中,以及它们是否在此名称列表之前或之后(在文件中和代码中)