Fortran处理nc文件基于netcdf库

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
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值