Fortran

Fortran으로 netCDF 파일 읽고 평균 구하기(gfortran 컴파일 에러)

이석사 중 2023. 8. 24. 13:23
728x90

이번 포스팅은 정말 오랜만에 포트란입니다

 

WRF 결과물인 netCDF 파일을 읽고 격자들 전체의 평균 값을 구하는 코드를 해보겠습니다


전체 코드입니다

  1 PROGRAM net1
  2         use netcdf
  3
  4         IMPLICIT NONE
  5
  6         CHARACTER(len = 256) :: fi
  7         REAL, ALLOCATABLE :: T2(:,:,:)
  8
  9         INTEGER :: dx, dy
 10         INTEGER :: ncid, varid
 11         INTEGER :: start(3), count(3)
 12
 13
 14         fi = "wrfout_d01_2016-10-06_00.nc"
 15         dx = 209
 16         dy = 209
 17
 18         call check(nf90_open(fi, NF90_NOWRITE, ncid), "opening T2 file")
 19         call check(nf90_inq_varid(ncid, "T2", varid), "getting T2 varid")
 20
 21         allocate(T2(209, 209, 1))
 22         start = [1, 1, 1]
 23         count   = [209, 209, 1]
 24
 25         WRITE(*, *) "Reading Grid T2"
 26         call check(nf90_get_var(ncid, varid, T2, start = start, count = count), "reading T2")
 27         WRITE(*, *) "Mean T2 : ", sum(T2) / size(T2)
 28
 29         call check(nf90_close(ncid), "closing T2 file")
 30         deallocate(T2)
 31
 32         contains
 33                 SUBROUTINE check(status, loc)
 34                         INTEGER, INTENT(in) :: status
 35                         CHARACTER(len = *), INTENT(in) :: loc
 36
 37                         if(status /= NF90_NOERR) then
 38                                 WRITE(*, *) "Error at ", loc
 39                                 WRITE(*, *) NF90_STRERROR(status)
 40                         end if
 41                         END SUBROUTINE check
 42 END PROGRAM

이번 작업을 하면서 코딩보다는 실행 부분에서 에러가 많이 발생했습니다


첫 번째로 발생한 에러는 두 번째 줄에 있는 use netcdf  부분이었습니다

 

코드를 다 짠 후에 gfortran으로 컴파일을 하면 

 

Fatal Error: Can't open module file ‘netcdf.mod’ for reading at (1): No such file or directory compilation terminated.

 

에러가 발생했습니다

 

이것에 해결법은 netcdf fortran을 설치한 디렉토리와 링크를 해줘야합니다

 

nc-config --fflags
 -I/home/lsh/WRF/Library/include -I/home/lsh/WRF/Library/include

nc-config --flibs
 -L/home/lsh/WRF/Library/lib -lnetcdff -L/home/lsh/WRF/Library/lib -lnetcdf -ldl -lm -lnetcdf -lhdf5_hl -lhdf5 -lz

이렇게 하나씩 순서대로 실행해보면 긴 path가 나옵니다

 

위에 fflags는 2가지로 나오지만 하나만 복사해서 쓰시면 되고 lib 경로는 그대로 복사하면 됩니다

 

그 후에 gfortran으로 컴파일을 할 때 뒤에 경로 2개를 include lib 순서로 붙여넣기하면 됩니다

 

결과적으로 아래 코드처럼 실행하면 됩니다

gfortran net1.f90 -I/home/lsh/WRF/Library/include -L/home/lsh/WRF/Library/lib -lnetcdff -L/home/lsh/WRF/Library/lib -lnetcdf -ldl -lm -lnetcdf -lhdf5_hl -lhdf5 -lz

 

저는 이렇게 해결했지만 다른 방법이 있으신 분은 댓글 부탁드립니다 ㅠㅠ

(아직 리눅스에 적응을 다 못했어요ㅠㅠ)

 

이 글을 쓰면서 변수를 선언해서 쓰는법도 생각해봤는데 이것도 해보겠습니다!


두 번째로 발생한 에러는

 

undefined reference to nf_{}와 check였는데 nf90_{} 명령어들은 라이브러리 링크로 해결이 됐고

 

check는 단순히 제가 subroutine을 만들지 않아서 발생했던 에러였습니다


세 번째로 발생한 에러는 

 

NetCDF: Start+count exceeds dimension bound

 

였습니다

 

이 에러는 격자 형태로 netCDF 파일을 읽는 과정에서 array를 사용하는데

 

start array와 count array의 크기가 맞지 않은 겁니다

 

이는 제가 포트란 array가 뒤에서부터 읽는 것을 몰랐어서 발생한 에러였습니다

 

제가 읽은 데이터는 T2로 2m 높이에서 관측한 기온으로 데이터 형태를 이렇습니다

 

 float T2(Time, south_north, west_east) ;
                T2:FieldType = 104 ;
                T2:MemoryOrder = "XY " ;
                T2:description = "TEMP at 2 M" ;
                T2:units = "K" ;
                T2:stagger = "" ;
                T2:coordinates = "XLONG XLAT XTIME" ;

 

기존에는 count = [1, 209, 209]로 array를 만들었는데 포트란은 뒤에서부터 읽다보니까 발생한 에러였습니다


이렇게 모든 에러들을 해결하고 나온 결과입니다

(base) lsh@DESKTOP-8N2HJ5V:~$ ./a.out
 Reading Grid T2
 Mean T2 :    288.110718
728x90