fortran90处理nc文件的学习笔记
fortran90下netcdf库的使用
编译器为 cygwin下的 gfortran
netcdf库fortran90使用的官方文档
!!! 一定要注意使用的netcdf.a和netcdff.a的区别
!!! 检查你指定的lib文件夹中有没有相对应的.a库 以及 include文件夹中有没有相应的头文件
!运行方式: gfortran.exe ReadAndWriteNC.f90 -I /usr/include -L /usr/lib -lnetcdff
program ReadAndWriteNC
use NETCDF ! 使用netcdf库
!!! 在F90中 通过use语句使用 NETCDF模块后不必再使用 include "netcdf.inc"
! 但要指定 netcdf.mod头文件的位置 和 netcdff.a库的位置
IMPLICIT NONE
INTEGER :: 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
! 定义储存经、纬度、时间以及变量的数值的向量、矩阵或者数组
REAL, DIMENSION(nlon) :: lonVarValue
REAL, DIMENSION(nlat) :: latVarValue
! REAL, DIMENSION(12) :: timeVarValue !用于方法1 和 无限维度使用start方法
REAL, DIMENSION(nlon, nlat) :: tmp
! REAL, DIMENSION(nlon, nlat, 12) :: tmp !用于方法1 可选
! 输出文件名称
CHARACTER*10, PARAMETER :: fileName = "ncFile2.nc"
print*, '开始运行!'
! 创建nc文件
CALL CHECK(NF90_CREATE(trim(fileName),nf90_clobber, ncID))
! ! 定义经度、纬度和时间维度
CALL CHECK(NF90_DEF_DIM(ncID, 'lon', nlon, lonDimID))
CALL CHECK(NF90_DEF_DIM(ncID, 'lat', nlat, latDimID))
! CALL CHECK(NF90_DEF_DIM(ncID, 'time', 12, timeDimID)) !用于方法1
CALL CHECK(NF90_DEF_DIM(ncID, 'time', NF90_UNLIMITED, timeDimID)) !无限维度
! 定义变量添加属性
CALL CHECK(NF90_DEF_VAR(ncID, "lon", NF90_FLOAT, lonDimID, lonVarID))
CALL CHECK(NF90_PUT_ATT(ncID, lonVarID, "long_name", "longitude"))
CALL CHECK(NF90_PUT_ATT(ncID, lonVarID, "units", "degrees_east"))
CALL CHECK(NF90_DEF_VAR(ncID, "lat", NF90_FLOAT, latDimID, latVarID))
CALL CHECK(NF90_PUT_ATT(ncID, latVarID, "long_name", "latitude"))
CALL CHECK(NF90_PUT_ATT(ncID, latVarID, "units", "degrees_north"))
CALL CHECK(NF90_DEF_VAR(ncID, "time", NF90_FLOAT, timeDimID, timeVarID))
CALL CHECK(NF90_PUT_ATT(ncID, timeVarID, "long_name", "date"))
CALL CHECK(NF90_PUT_ATT(ncID, timeVarID, "units", "month since 1999-12-31"))
ncVarDims = (/ lonDimID, latDimID, timeDimID /)
CALL CHECK(NF90_DEF_VAR(ncID, "temp", NF90_FLOAT, ncVarDims, ncVarID))
CALL CHECK(NF90_PUT_ATT(ncID, ncVarID, "long_name", "sure temperature of world"))
CALL CHECK(NF90_PUT_ATT(ncID, ncVarID, "units", "degreeC"))
! 添加全局属性
CALL CHECK(NF90_PUT_ATT(ncID, NF90_GLOBAL,"contact","ZhangDaJiang"))
! 结束定义模式
CALL CHECK(NF90_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
CALL CHECK(NF90_PUT_VAR(ncID, lonVarID, lonVarValue))
CALL CHECK(NF90_PUT_VAR(ncID, latVarID, latVarValue))
! 方法1 将tmp数据全部的放入时,你需要将其定义为相应维度大小的数组。(推荐使用处理)
! 将代码中相应方法1的代码注释取消 注释掉方法二的部分
! 定义tmp多维数组 REAL, DIMENSION(nlon, nlat, 12 ) :: tmp !假设时间长度为12
! 定义时间维度 参考经纬度的处理方法
! do t = 1, 12
! do i = 1, 360
! do j = 1, 180
! tmp2(i,j,t)=5.0*t ! tmp数据
! end do
! end do
! end do
! do t = 1, 12
! timeVarValue(t) = t
! end do
! CALL CHECK(NF90_PUT_VAR(ncID, timeVarID, timeVarValue))
! CALL CHECK(NF90_PUT_VAR(ncID, ncVarID, tmp))
!====================================================================
! 方法2 使用start和count的方法 适用于多维数组和无限维度
! (仅仅是学习一下,电脑内存有限的话可以用这种方法, 由于重复循环写入数据,处理速度可能会慢点。)
do i = 1, 360
do j = 1, 180
tmp(i,j)=5.0 ! tmp数据
end do
end do
do t = 1, 12 ! 假定时间长度为12
CALL CHECK(NF90_PUT_VAR(ncID, ncVarID, tmp*t, start=(/1,1,t/),&
count=(/nlon,nlat,1/)))
CALL CHECK(NF90_PUT_VAR(ncID, timeVarID, t, start=(/t/)))
end do
! 记录维度不能有重复值和空值,比如时间维度存在相同数字会报错
! 注意start和count的使用 默认start和count都是1 因此当增加量为1时不需指定count
! 当增加量为多个时,前面增加的值个数应与count保持一致!
! 例如增加量为count=(/2/),前面的值应该有两个值
! do t = 1, 12
! timeVarValue(t) = t
! end do
! do t = 1, 6
! CALL CHECK(NF90_PUT_VAR(ncID, timeVarID,timeVarValue((2*t-1):(2*t)),&
! start=(/(2*t-1)/), count=(/2/)))
! print*, timeVarValue((2*t-1):(2*t))
! end do
!====================================================================
! 将数据同步至硬盘 (可选)
CALL CHECK(NF90_SYNC(ncID))
! 关闭文件
CALL CHECK(NF90_CLOSE(ncid))
print*, '运行完毕!'
contains
subroutine CHECK(STATUS)
INTEGER, intent (in) :: STATUS
if (STATUS .NE. NF90_NOERR) then ! nf_noerr=0 表示没有错误
print *, NF90_STRERROR(STATUS)
stop 'stopped'
endif
end subroutine CHECK
end program ReadAndWriteNC