最近在学习如何用Fortran语言读写netcdf文件。在学习过程中遇到了一大堆问题,特此记录。
问题一:在使用 gfortran 对 fortran代码编译时总是提示 Rank mismatch… (scalar and rank-1) 的错误信息。搞了好久终于搞定了。
相似问题的截图可见这个提问链接https://ask.csdn.net/questions/1093237
解决小伙伴问题的方法如下:
方法1. 使用gfortan编译时,加入-fallow-argument-mismatch 参数解决 Rank mismatch 编译错误。 如下:gfortran -g -fallow-argument-mismatch ReadAndWriteNC.f90 -I/usr/local/include -L/usr/local/bin -lnetcdf -o ReadAndWriteNC
方法2. 在你的代码中进行修改。使用 dim1pass(1) 替换 135 行中 status=nf_def_var(ncid,‘longitude’,nf_real,1,nlon1id,nlongit1id) 的nlon1id。同理使用dim1pass(2) 替换nlat1id;dim1pass(3)替换ndep1id等
造成这种问题出现的原因,可能与F77和F90参数传递时的要求不一样有关。低版本的编译器中对参数要求较低,但在高版本的编译器中,你传递的参数类型不一致时编译器会报错。我自己理解的,不对之处,希望大神批评指正!
看到了官方网站给出导致该问题出现的原因及解决方案,跟我给出的方案原理一致。重新在这里补充下。希望对你们有用。https://gcc.gnu.org/gcc-10/porting_to.html。
大概意思就是:发生编译错误的位置,其参数需要传递的是数组,而你传递的是标量。这样高版本的编译器是不允许的,因此就会提示编译错误。我们可以通过方法一的方式将该错误降为警告提示,从而顺利编译。或者通过将标量转为一个数组来消除错误。
太懒了。就不写我运行代码的错误案例了。直接写我改好的得了。注释里写的应该比较清楚了。
program ReadAndWriteNC
implicit none
include "netcdf.inc"
INTEGER :: STATUS, & !状态码 用于检查错误
ncID !nc文件的ID
! 经、纬度、时间以及变量的ID
INTEGER :: latVarID, & !
lonVarID, & !
timeVarID, &
ncVarID
! 经、纬度、时间等维度的ID
INTEGER :: latDimID, &
lonDimID, &
timeDimID
! 变量的维度(包括经、纬度、时间、level、海拔等等)
INTEGER :: ncVarDims(3)
INTEGER :: i, j, t
INTEGER, PARAMETER :: nlat=180, nlon=360, ntime=12
! 定义储存经、纬度、时间以及变量的数值的向量、矩阵或者数组
REAL, DIMENSION(nlon) :: lonVarValue
REAL, DIMENSION(nlat) :: latVarValue
REAL, DIMENSION(ntime) :: timeVarValue
REAL, DIMENSION(nlon, nlat, ntime) :: tmp
CHARACTER*9, PARAMETER :: fileName = "ncFile.nc"
print*, '开始运行!'
! 创建nc文件
STATUS = NF_CREATE(TRIM(fileName), 0, ncID)
IF (STATUS .NE. NF_NOERR) CALL CHECK(STATUS)
! ! 定义经度、纬度和时间维度
! NF_DEF_DIM (INTEGER NCID, CHARACTER*(*) NAME, INTEGER LEN, INTEGER dimid)
STATUS = NF_DEF_DIM(ncID, 'lon', nlon, lonDimID)
IF (STATUS .NE. NF_NOERR) CALL CHECK(STATUS)
STATUS = NF_DEF_DIM(ncID, 'lat', nlat, latDimID)
IF (STATUS .NE. NF_NOERR) CALL CHECK(STATUS)
STATUS = NF_DEF_DIM(ncID, 'time', ntime, timeDimID) ! 用NF_UNLIMITED替换LEN(ntime)表示无限维
IF (STATUS .NE. NF_NOERR) CALL CHECK(STATUS)
! ! 定义经度、纬度和时间变量 并 写入相关属性
! NF_DEF_VAR(INTEGER NCID, CHARACTER*(*) NAME, INTEGER XTYPE, INTEGER NVDIMS, INTEGER VDIMS(*), INTEGER varid)
! 并 写入相关属性
! ncVarDims(1) = lonDimID
! ncVarDims(2) = latDimID
! ncVarDims(3) = timeDimID
! 与以下代码 ncVarDims = (/ lonDimID, latDimID, timeDimID /) 相同
ncVarDims = (/ lonDimID, latDimID, timeDimID /)
! !!!!!!! 特别注意 !!!!!!!!
! 如果直接将lonDimID填入下面ncVarDims(1)的位置,高版本的gfortran会提示 Rank mismatch 编译错误
! 也可以在编译时加入-fallow-argument-mismatch 解决 Rank mismatch 编译错误的问题 如下:
! gfortran -g -fallow-argument-mismatch ReadAndWriteNC.f90 -I/usr/local/include -L/usr/local/bin -lnetcdf -o
! 导致问题的原因可能在于F77和F90参数接口的问题
CALL CHECK(nf_def_var(ncID, "lon", NF_FLOAT, 1, ncVarDims(1), lonVarID)) ! ncVarDims(1) = lonDimID
CALL CHECK(nf_put_att_text(ncID, lonVarID, "long_name", 9,"longitude"))
CALL CHECK(nf_put_att_text(ncID, lonVarID, "units", 12, "degrees_east"))
CALL CHECK(nf_def_var(ncID, "lat", NF_FLOAT, 1, ncVarDims(2), latVarID)) ! ncVarDims(2) = latDimID
CALL CHECK(nf_put_att_text(ncID, latVarID, "long_name", 8,"latitude"))
CALL CHECK(nf_put_att_text(ncID, latVarID, "units", 13, "degrees_north"))
CALL CHECK(nf_def_var(ncID, "time", NF_FLOAT, 1, ncVarDims(3), timeVarID)) ! ncVarDims(3) = timeDimID
CALL CHECK(nf_put_att_text(ncID, timeVarID, "long_name", 22,"month since 2010-01-01"))
CALL CHECK(nf_put_att_text(ncID, timeVarID, "units", 5, "month"))
STATUS = NF_DEF_VAR (ncID, 'tmp', NF_FLOAT, 3, ncVarDims, ncVarID) ! ncVarDims = (/ lonDimID, latDimID, timeDimID /)
IF (STATUS .NE. NF_NOERR) CALL CHECK(STATUS)
CALL CHECK(nf_put_att_text(ncID, ncVarID, "long_name", 20, "temperature of China"))
CALL CHECK(nf_put_att_text(ncID, ncVarID, "units", 8, "degree_C"))
! 添加全局属性
CALL CHECK(nf_put_att_text(ncID, nf_global, "Source", 23, "Created by ZhangDaJiang"))
! 结束定义模式
CALL CHECK(nf_enddef(ncID))
! 将经度、纬度、时间以及数据变量的数值放入定义好的变量中
! 经度值
do i = 1, 360
lonVarValue(i) = -180.0+(i-1.0)*1.0
end do
! 维度值
do j = 1, 180
latVarValue(j) = -90.0+(j-1.0)*1.0
end do
! 时间值
do t = 1, 12
timeVarValue(t) = t*1.0
end do
! 变量值
do t = 1, 12
do i = 1, 360
do j = 1, 180
tmp(i,j,t)=5.0*t
end do
end do
end do
! 将经度、纬度、时间以及数据变量的数值放入定义好的变量中
CALL CHECK(nf_put_var_real(ncID, lonVarID, lonVarValue))
CALL CHECK(nf_put_var_real(ncID, latVarID, latVarValue))
CALL CHECK(nf_put_var_real(ncID, timeVarID, timeVarValue))
CALL CHECK(nf_put_var_real(ncID, ncVarID, tmp))
! 关闭文件
CALL CHECK(nf_close(ncid))
print*, '运行完毕!'
contains
subroutine CHECK(STATUS)
INTEGER, intent (in) :: STATUS
if (STATUS .NE. nf_noerr) then ! nf_noerr=0 表示没有错误
print *, nf_strerror(STATUS)
stop 'stopped'
endif
end subroutine CHECK
! -----
end program ReadAndWriteNC