FV3 Bundle
netcdf_to_odb.F90
Go to the documentation of this file.
1 ! (C) Copyright 2018 UCAR
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 
6 !> Fortran program to convert the existing NetCDF file into an ODB-1
7 
8 program netcdf_to_odb
9 
10 use netcdf, only: &
11  nf90_close, &
12  nf90_get_att, &
13  nf90_global, &
14  nf90_noerr, &
15  nf90_nowrite, &
16  nf90_open, &
17  nf90_strerror
18 
19 use odb_module, only: &
20  odb_close, &
21  odb_end, &
22  odb_getsize, &
23  odb_open, &
24  odb_put
25 
26 use, intrinsic :: iso_c_binding, only: &
27  c_double, &
28  c_int, &
29  c_null_char
30 
31 implicit none
32 
33 character(len=1000) :: filename
34 character(len=1000) :: output_filename
35 integer :: rc
36 integer :: file_id
37 character(len=7000) :: messages(4)
38 real, allocatable :: latitudes(:)
39 real, allocatable :: longitudes(:)
40 real, allocatable :: times_netcdf(:)
41 real, allocatable :: observations(:)
42 real, allocatable :: pressures(:)
43 integer, allocatable :: times(:)
44 integer, allocatable :: dates(:)
45 integer(kind=c_int) :: odb_rc
46 integer :: iob
47 integer :: date_time
48 integer :: handle
49 integer :: dummy_num_rows
50 integer :: num_columns
51 real(kind=c_double), allocatable :: desc(:,:)
52 real(kind=c_double), allocatable :: hdr(:,:)
53 real(kind=c_double), allocatable :: body(:,:)
54 integer :: num_pools
55 integer :: pool_number
56 
57 interface
58  function setenv (envname, envval, overwrite) bind (c, name = "setenv")
59  use, intrinsic :: iso_c_binding, only: &
60  c_char, &
61  c_int
62  character(kind=c_char) :: envname(*)
63  character(kind=c_char) :: envval(*)
64  integer(kind=c_int), value :: overwrite
65  integer(kind=c_int) :: setenv
66  end function setenv
67 end interface
68 
69 call get_command_argument (1, filename)
70 call get_command_argument (2, output_filename)
71 
72 if (filename == "" .or. output_filename == "") then
73  write (messages(1), '(a,i0)') "Please provide two arguments, input-filename output-filename"
74  call fail (messages(1:1))
75 end if
76 
77 rc = nf90_open(filename, nf90_nowrite, file_id)
78 if (rc /= nf90_noerr) then
79  write (messages(1), '(a,i0)') "nf90_open failed with rc = ", rc
80  write (messages(2), '(2a)') "file name = ", trim(filename)
81  messages(3) = nf90_strerror(rc)
82  call fail (messages(1:3))
83 end if
84 
85 call get_netcdf_array (file_id, 'Latitude', latitudes)
86 call get_netcdf_array (file_id, 'Longitude', longitudes)
87 call get_netcdf_array (file_id, 'Time', times_netcdf)
88 
89 allocate (times(size(times_netcdf)))
90 allocate (dates(size(times_netcdf)))
91 
92 rc = nf90_get_att(file_id, nf90_global, "date_time", date_time)
93 if (rc /= nf90_noerr) then
94  write (messages(1), '(a,i0)') "nf90_get_at failed for date_time with rc = ", rc
95  write (messages(2), '(a,i0)') "file id = ", file_id
96  messages(3) = nf90_strerror(rc)
97  call fail (messages(1:3))
98 end if
99 
100 dates = date_time / 100
101 times = (date_time - (date_time / 100) * 100) * 10000
102 times = times + 10000 * int(times_netcdf)
103 times_netcdf = times_netcdf - int(times_netcdf)
104 where (times_netcdf >= 0)
105  times = times + nint(60 * times_netcdf) * 100
106 elsewhere
107  times = times - 10000
108  times = times + nint(60 * (1 - abs(times_netcdf))) * 100
109 end where
110 
111 call get_netcdf_array (file_id, 'Observation', observations)
112 call get_netcdf_array (file_id, 'Pressure', pressures)
113 
114 rc = nf90_close(file_id)
115 if (rc /= nf90_noerr) then
116  write (messages(1), '(a,i0)') "nf90_close failed with rc = ", rc
117  write (messages(2), '(a,i0)') "file id = ", file_id
118  messages(3) = nf90_strerror(rc)
119  call fail (messages(1:3))
120 end if
121 
122 odb_rc = setenv("ODB_DATAPATH_OOPS" // c_null_char, &
123  trim(output_filename) // c_null_char, &
124  1_c_int)
125 
126 odb_rc = setenv("ODB_SRCPATH_OOPS" // c_null_char, &
127  trim(output_filename) // c_null_char, &
128  1_c_int)
129 
130 odb_rc = setenv("IOASSIGN" // c_null_char, &
131  trim(output_filename) // "/IOASSIGN" // c_null_char, &
132  1_c_int)
133 
134 call execute_command_line ("unset ODB_COMPILER_FLAGS && &
135  &create_ioassign -l OOPS -d " // trim(output_filename))
136 
137 num_pools = 1
138 handle = odb_open("OOPS", "NEW", num_pools)
139 
140 odb_rc = odb_getsize(handle, "@desc", dummy_num_rows, num_columns)
141 allocate (desc(1,0:num_columns))
142 desc = -32768
143 odb_rc = odb_getsize(handle, "@hdr", dummy_num_rows, num_columns)
144 allocate (hdr(size(latitudes),0:num_columns))
145 hdr = -32768
146 odb_rc = odb_getsize(handle, "@body", dummy_num_rows, num_columns)
147 allocate (body(size(latitudes),0:num_columns))
148 body = -32768
149 
150 desc(:,1) = 20160308
151 desc(:,2) = 1200
152 desc(:,3) = 0
153 desc(:,4) = size(latitudes)
154 
155 do iob = 1, size(latitudes)
156  hdr(iob,1) = iob
157  hdr(iob,2) = dates(iob)
158  hdr(iob,3) = times(iob)
159  hdr(iob,4) = latitudes(iob)
160  hdr(iob,5) = longitudes(iob)
161  hdr(iob,6) = iob - 1
162  hdr(iob,7) = 1
163 end do
164 
165 do iob = 1, size(latitudes)
166  body(iob,1) = 2
167  body(iob,2) = observations(iob)
168  body(iob,3) = 1
169  body(iob,4) = pressures(iob)
170 end do
171 
172 pool_number = 1
173 num_columns = size(desc,dim=2)-1
174 odb_rc = odb_put(handle, "@desc", desc, 1, poolno = pool_number)
175 num_columns = size(hdr,dim=2)-1
176 odb_rc = odb_put(handle, "@hdr", hdr, size(latitudes), poolno = pool_number)
177 num_columns = size(body,dim=2)-1
178 odb_rc = odb_put(handle, "@body", body, size(latitudes), poolno = pool_number)
179 
180 odb_rc = odb_close(handle, save = .true.)
181 odb_rc = odb_end()
182 
183 contains
184 
185 subroutine fail (messages)
187 character(len=*), intent(in) :: messages(:)
188 
189 integer :: i
190 
191 do i = 1, size(messages)
192  write (0, '(a)') trim(messages(i))
193  write (*, '(a)') trim(messages(i))
194 end do
195 call exit (1)
196 
197 end subroutine fail
198 
199 subroutine get_netcdf_array (file_id, var_name, output_array)
201 use netcdf, only: &
202  nf90_get_var, &
203  nf90_inq_varid, &
204  nf90_inquire_dimension, &
205  nf90_inquire_variable, &
206  nf90_noerr, &
207  nf90_strerror
208 
209 integer, intent(in) :: file_id
210 character(len=*), intent(in) :: var_name
211 real, allocatable, intent(out) :: output_array(:)
212 
213 integer :: var_id, rc, ndims, length, dimids(1)
214 character(len=7000) :: messages(5)
215 
216 rc = nf90_inq_varid(file_id, var_name, var_id)
217 if (rc /= nf90_noerr) then
218  write (messages(1), '(a,i0)') "nf90_inq_varid failed for " // trim(var_name) // " with rc = ", rc
219  write (messages(2), '(a,i0)') "file id = ", file_id
220  messages(3) = nf90_strerror(rc)
221  call fail (messages(1:3))
222 end if
223 
224 rc = nf90_inquire_variable(file_id, var_id, ndims = ndims, dimids = dimids)
225 if (rc /= nf90_noerr) then
226  write (messages(1), '(a,i0)') "nf90_inquire_variable failed for " // trim(var_name) // " with rc = ", rc
227  write (messages(2), '(a,i0)') "file id = ", file_id
228  write (messages(3), '(a,i0)') "var id = ", var_id
229  messages(4) = nf90_strerror(rc)
230  call fail (messages(1:4))
231 end if
232 
233 if (ndims /= 1) then
234  write (messages(1), '(a,i0)') "Should be a 1d arrays for " // trim(var_name)
235  write (messages(2), '(a,i0,a)') "Actually got ", ndims, "d array"
236  write (messages(3), '(a,i0)') "file id = ", file_id
237  write (messages(4), '(a,i0)') "var id = ", var_id
238  call fail (messages(1:4))
239 end if
240 
241 rc = nf90_inquire_dimension(file_id, dimids(1), len = length)
242 if (rc /= nf90_noerr) then
243  write (messages(1), '(a,i0)') "nf90_inquire_dimension failed for " // trim(var_name) // " with rc = ", rc
244  write (messages(2), '(a,i0)') "file id = ", file_id
245  write (messages(3), '(a,i0)') "var id = ", var_id
246  write (messages(4), '(a,i0)') "dim id = ", dimids(1)
247  messages(5) = nf90_strerror(rc)
248  call fail (messages(1:5))
249 end if
250 
251 allocate (output_array(length))
252 
253 rc = nf90_get_var(file_id, var_id, output_array)
254 if (rc /= nf90_noerr) then
255  write (messages(1), '(a,i0)') "nf90_get_var failed for " // trim(var_name) // " with rc = ", rc
256  write (messages(2), '(a,i0)') "file id = ", file_id
257  write (messages(2), '(a,i0)') "var id = ", var_id
258  messages(4) = nf90_strerror(rc)
259  call fail (messages(1:4))
260 end if
261 
262 end subroutine get_netcdf_array
263 
264 end program netcdf_to_odb
subroutine get_netcdf_array(file_id, var_name, output_array)
subroutine fail(messages)
program netcdf_to_odb
Fortran program to convert the existing NetCDF file into an ODB-1.