FV3-JEDI
fv3jedi_io_latlon_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2017-2020 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 
7 
8 use iso_c_binding
9 
10 use netcdf
11 use mpi
12 
13 use atlas_module, only: atlas_field, atlas_fieldset
14 
15 use datetime_mod
16 
17 use fckit_configuration_module, only: fckit_configuration
18 use fckit_log_module, only : log
19 use fckit_mpi_module
21 
22 use type_bump, only: bump_type
23 
31 
32 implicit none
33 
34 private
35 public fv3jedi_llgeom!, create_latlon, delete_latlon, write_latlon_metadata, write_latlon_fields, &
36 
37 
38 !Module level type
40  type(fckit_mpi_comm) :: f_comm
41  type(fv3jedi_bump_interp) :: bump
42  integer :: llcomm
43  integer :: layout(2)
44  logical :: thispe = .false.
45  integer :: nx, ny, nxg, nyg
46  integer :: npes
47  real(kind=kind_real), allocatable :: lons(:)
48  real(kind=kind_real), allocatable :: lats(:)
49  character(len=1024) :: filename
50  integer, allocatable :: istart2(:), icount2(:)
51  integer, allocatable :: istart3(:), icount3(:)
52  integer, allocatable :: istarte(:), icounte(:)
53  contains
54  procedure :: setup_conf
55  procedure :: setup_date
56  procedure :: write
57  procedure :: delete
58  final :: dummy_final
59 end type fv3jedi_llgeom
60 
61 contains
62 
63 ! --------------------------------------------------------------------------------------------------
64 subroutine setup_conf(self, geom)
65 
66 implicit none
67 
68 !Arguments
69 class(fv3jedi_llgeom), intent(inout) :: self
70 type(fv3jedi_geom), intent(in) :: geom !< Geometry
71 
72 call log%debug("fv3jedi_io_latlon_mod%setup_conf starting")
73 
74 call create_latlon(self, geom)
75 
76 call log%debug("fv3jedi_io_latlon_mod%setup_conf done")
77 
78 end subroutine setup_conf
79 
80 ! --------------------------------------------------------------------------------------------------
81 
82 subroutine setup_date(self, vdate)
83 
84 implicit none
85 
86 !Arguments
87 class(fv3jedi_llgeom), intent(inout) :: self
88 type(datetime), intent(in) :: vdate !< DateTime
89 
90 integer :: n
91 character(len=4) :: yyyy
92 character(len=2) :: mm, dd, hh, min, ss
93 
94 call log%debug("fv3jedi_io_latlon_mod%setup_date starting")
95 
96 call log%debug("fv3jedi_io_latlon_mod%setup_date done")
97 
98 end subroutine setup_date
99 
100 ! --------------------------------------------------------------------------------------------------
101 
102 subroutine delete(self)
103 
104 implicit none
105 class(fv3jedi_llgeom), intent(inout) :: self
106 
107 call log%debug("fv3jedi_io_latlon_mod%delete starting")
108 
109 call delete_latlon(self)
110 
111 call log%debug("fv3jedi_io_latlon_mod%delete done")
112 
113 end subroutine delete
114 
115 ! --------------------------------------------------------------------------------------------------
116 
117 subroutine write(self, geom, fields, f_conf, vdate)
118 
119 implicit none
120 class(fv3jedi_llgeom), intent(inout) :: self
121 type(fv3jedi_geom), intent(in) :: geom !< Geom
122 type(fv3jedi_field), intent(in) :: fields(:) !< Fields to be written
123 type(fckit_configuration), intent(in) :: f_conf !< Configuration
124 type(datetime), intent(in) :: vdate !< DateTime
125 
126 integer :: var
127 
128 call log%debug("fv3jedi_io_latlon_mod%write starting")
129 
130 call write_latlon_metadata(self, geom, f_conf, vdate)
131 
132 call write_latlon_fields(self, geom, fields)
133 
134 call log%debug("fv3jedi_io_latlon_mod%write done")
135 
136 end subroutine write
137 
138 ! --------------------------------------------------------------------------------------------------
139 
140 subroutine create_latlon(llgeom, geom)
141 
142 implicit none
143 
144 !Arguments
145 type(fv3jedi_llgeom), intent(inout) :: llgeom !< LatLon Geometry
146 type(fv3jedi_geom), intent(in) :: geom !< Geometry
147 
148 integer :: color
149 
150 real(kind=kind_real) :: dx, dy
151 integer :: i, j, ji, jj, ii, locs_nlocs, ierr
152 real(kind=kind_real), allocatable :: locs_lat(:), locs_lon(:)
153 
154 ! Create lat lon grid and interpolation object for going from cube to lat-lon
155 ! --------------------------------------------------------------------------
156 
157 llgeom%f_comm = geom%f_comm
158 
159 !Maximum of 12 IO processors
160 if (llgeom%f_comm%size() >= 12) then
161  llgeom%layout(1) = 12
162  llgeom%layout(2) = 1
163 elseif (llgeom%f_comm%size() >= 6) then
164  llgeom%layout(1) = 6
165  llgeom%layout(2) = 1
166 else
167  call abor1_ftn("create_latlon error: fewer than 6 npes not anticipated")
168 endif
169 llgeom%npes = llgeom%layout(1) * llgeom%layout(2)
170 
171 !Since the lat lon grid is only for IO purposes it is only
172 !defined on a subset of PEs - those that will do the writing.
173 !This is generally more efficient than having many PEs trying
174 !to write to the same file.
175 
176 llgeom%nxg = 4*(geom%npx - 1)
177 llgeom%nyg = 2*(geom%npy - 1) + 1
178 llgeom%nx = 0
179 llgeom%ny = 0
180 
181 color = mpi_undefined
182 
183 if (llgeom%f_comm%rank() <= llgeom%npes-1) then
184 
185  !Split communicator
186  color = int(llgeom%f_comm%communicator() / 2)
187 
188  llgeom%thispe = .true.
189 
190  !Resolution
191  dx = 360.0_kind_real / (real(llgeom%nxg,kind_real) - 1.0_kind_real)
192  dy = 180.0_kind_real / (real(llgeom%nyg,kind_real) - 1.0_kind_real)
193 
194  llgeom%nx = llgeom%nxg / llgeom%layout(1)
195  llgeom%ny = llgeom%nyg / llgeom%layout(2)
196 
197  allocate(llgeom%lons(llgeom%nx))
198  allocate(llgeom%lats(llgeom%ny))
199 
200  !Each processor has subset of lons
201  llgeom%lons(1) = dx * llgeom%nx * llgeom%f_comm%rank()
202  do i = 2,llgeom%nx
203  llgeom%lons(i) = llgeom%lons(i-1) + dx
204  enddo
205 
206  !Each processor has all lats
207  llgeom%lats(1) = -90.0_kind_real
208  do i = 2,llgeom%ny
209  llgeom%lats(i) = llgeom%lats(i-1) + dy
210  enddo
211 
212  locs_nlocs = llgeom%nx*llgeom%ny
213  allocate(locs_lon(locs_nlocs))
214  allocate(locs_lat(locs_nlocs))
215 
216  ii = 0
217  do jj = 1,llgeom%ny
218  do ji = 1,llgeom%nx
219  ii = ii + 1
220  locs_lon(ii) = llgeom%lons(ji)
221  locs_lat(ii) = llgeom%lats(jj)
222  enddo
223  enddo
224 
225 else
226 
227  locs_nlocs = 0
228  allocate(locs_lon(0))
229  allocate(locs_lat(0))
230 
231 endif
232 
233 call llgeom%bump%setup(geom%f_comm, geom%isc, geom%iec, geom%jsc, geom%jec, geom%npz, &
234  geom%grid_lon(geom%isc:geom%iec, geom%jsc:geom%jec), &
235  geom%grid_lat(geom%isc:geom%iec, geom%jsc:geom%jec), &
236  locs_nlocs, locs_lon, locs_lat)
237 
238 deallocate(locs_lon)
239 deallocate(locs_lat)
240 
241 !IO communicator
242 !call MPI_Comm_split(llgeom%f_comm%communicator(), color, llgeom%f_comm%rank(), llgeom%llcomm, ierr)
243 
244 ! NC arrays
245 allocate(llgeom%istart3(4),llgeom%icount3(4))
246 allocate(llgeom%istarte(4),llgeom%icounte(4))
247 allocate(llgeom%istart2(3),llgeom%icount2(3))
248 llgeom%istart3(1) = llgeom%nx * llgeom%f_comm%rank() + 1; llgeom%icount3(1) = llgeom%nx
249 llgeom%istart3(2) = 1; llgeom%icount3(2) = llgeom%ny
250 llgeom%istart3(3) = 1; llgeom%icount3(3) = geom%npz
251 llgeom%istart3(4) = 1; llgeom%icount3(4) = 1
252 llgeom%istart2(1) = llgeom%istart3(1); llgeom%icount2(1) = llgeom%icount3(1)
253 llgeom%istart2(2) = llgeom%istart3(2); llgeom%icount2(2) = llgeom%icount3(2)
254 llgeom%istart2(3) = llgeom%istart3(4); llgeom%icount2(3) = llgeom%icount3(4)
255 
256 llgeom%istarte = llgeom%istarte
257 llgeom%icounte = llgeom%icount3
258 llgeom%istarte(3) = geom%npz + 1
259 
260 end subroutine create_latlon
261 
262 ! --------------------------------------------------------------------------------------------------
263 
264 subroutine delete_latlon(llgeom)
265 
266 implicit none
267 
268 !Arguments
269 type(fv3jedi_llgeom), intent(inout) :: llgeom !< LatLon Geometry
270 
271 if (llgeom%thispe) then
272  deallocate(llgeom%lons)
273  deallocate(llgeom%lats)
274 
275  deallocate ( llgeom%istart2, llgeom%icount2 )
276  deallocate ( llgeom%istart3, llgeom%icount3 )
277  deallocate ( llgeom%istarte, llgeom%icounte )
278 endif
279 
280 call llgeom%bump%delete()
281 
282 
283 end subroutine delete_latlon
284 
285 ! --------------------------------------------------------------------------------------------------
286 
287 subroutine write_latlon_metadata(llgeom, geom, f_conf, vdate)
288 
289 implicit none
290 
291 !Arguments
292 type(fv3jedi_llgeom), intent(inout) :: llgeom !< LatLon Geometry
293 type(fv3jedi_geom), intent(in) :: geom !< Geometry
294 type(fckit_configuration), intent(in) :: f_conf !< Configuration
295 type(datetime), intent(in) :: vdate !< DateTime
296 
297 integer :: date(6)
298 integer(kind=c_int) :: idate, isecs
299 character(len=64) :: datefile
300 
301 integer :: ncid, varid(2)
302 integer :: x_dimid, y_dimid, z_dimid, e_dimid, t_dimid
303 character(len=:), allocatable :: str
304 
305 ! Current date
306 call datetime_to_ifs(vdate, idate, isecs)
307 date(1) = idate/10000
308 date(2) = idate/100 - date(1)*100
309 date(3) = idate - (date(1)*10000 + date(2)*100)
310 date(4) = isecs/3600
311 date(5) = (isecs - date(4)*3600)/60
312 date(6) = isecs - (date(4)*3600 + date(5)*60)
313 
314 ! Naming convention for the file
315 llgeom%filename = 'Data/fv3jedi.latlon.'
316 if (f_conf%has("filename")) then
317  call f_conf%get_or_die("filename",str)
318  llgeom%filename = str
319  deallocate(str)
320 endif
321 
322 ! Append filename with the curent datetime from fv3jedi
323 write(datefile,'(I4,I0.2,I0.2,A1,I0.2,I0.2,I0.2)') date(1),date(2),date(3),"_",date(4),date(5),date(6)
324 llgeom%filename = trim(llgeom%filename)//trim(datefile)//trim("z.nc4")
325 
326 call nccheck( nf90_create( llgeom%filename, ior(nf90_netcdf4, nf90_mpiio), ncid, &
327  comm = llgeom%f_comm%communicator(), info = mpi_info_null), "nf90_create" )
328 
329 ! Create dimensions
330 call nccheck ( nf90_def_dim(ncid, "lon" , llgeom%nxg , x_dimid), "nf90_def_dim lon" )
331 call nccheck ( nf90_def_dim(ncid, "lat" , llgeom%nyg , y_dimid), "nf90_def_dim lat" )
332 call nccheck ( nf90_def_dim(ncid, "lev" , geom%npz , z_dimid), "nf90_def_dim lev" )
333 call nccheck ( nf90_def_dim(ncid, "edge", geom%npz+1 , e_dimid), "nf90_def_dim lev" )
334 call nccheck ( nf90_def_dim(ncid, "time", 1 , t_dimid), "nf90_def_dim time" )
335 
336 ! Define fields to be written (geom)
337 call nccheck( nf90_def_var(ncid, "lons", nf90_double, x_dimid, varid(1)), "nf90_def_var lons" )
338 call nccheck( nf90_def_var(ncid, "lats", nf90_double, y_dimid, varid(2)), "nf90_def_var lats" )
339 
340 call nccheck( nf90_enddef(ncid), "nf90_enddef" )
341 
342 if (llgeom%thispe) then
343 
344  ! Write fields (geom)
345  call nccheck( nf90_put_var( ncid, varid(1), llgeom%lons, &
346  start = llgeom%istart2(1:1), count = llgeom%icount2(1:1) ), "nf90_put_var lons" )
347  call nccheck( nf90_put_var( ncid, varid(2), llgeom%lats, &
348  start = llgeom%istart2(2:2), count = llgeom%icount2(2:2) ), "nf90_put_var lats" )
349 
350 endif
351 
352 ! Close file
353 call nccheck( nf90_close(ncid), "nf90_close" )
354 
355 !Let LatLon PEs catch up
356 call llgeom%f_comm%barrier()
357 
358 end subroutine write_latlon_metadata
359 
360 ! --------------------------------------------------------------------------------------------------
361 
362 subroutine write_latlon_fields(llgeom, geom, fields)
363 
364 implicit none
365 
366 !Arguments
367 type(fv3jedi_llgeom), target, intent(inout) :: llgeom !< LatLon Geometry
368 type(fv3jedi_geom), intent(in) :: geom !< Geometry
369 type(fv3jedi_field), intent(in) :: fields(:) !< Field to write
370 
371 integer :: var, ji, jj, jk, csngrid, llngrid, ii, i, j, k, n
372 real(kind=kind_real), allocatable :: llfield_bump(:,:)
373 real(kind=kind_real), allocatable :: llfield(:,:,:)
374 
375 integer :: ncid, varid
376 integer :: x_dimid, y_dimid, z_dimid, e_dimid, t_dimid
377 integer, target :: dimids3(4), dimids2(3), dimidse(4)
378 integer, pointer :: dimids(:), istart(:), icount(:)
379 
380 ! Loop over fields
381 ! ----------------
382 do var = 1, size(fields)
383 
384  ! Only certain fields can be written for now
385  ! ------------------------------------------
386  if ( trim(fields(var)%space) == 'magnitude' .and. &
387  trim(fields(var)%staggerloc) == 'center' .and. &
388  .not. fields(var)%integerfield ) then
389 
390  ! Interpolate the field to the lat-lon grid
391  ! -----------------------------------------
392  if (llgeom%thispe) then
393  allocate(llfield(1:llgeom%nx,1:llgeom%ny,1:geom%npz))
394  else
395  allocate(llfield(0,0,0))
396  endif
397  llfield = 0.0_kind_real
398 
399  csngrid = (geom%iec-geom%isc+1)*(geom%jec-geom%jsc+1)
400  llngrid = llgeom%nx*llgeom%ny
401 
402  !Allocate fields with BUMP arrangement
403  allocate(llfield_bump(llngrid,geom%npz))
404 
405  !Bilinear interpolation to latlon grid
406  call llgeom%bump%apply(geom%npz, fields(var)%array, llngrid, llfield_bump)
407 
408  !Unpack BUMP latlon field
409  if (llgeom%thispe) then
410  do jk = 1, geom%npz
411  ii = 0
412  do jj = 1,llgeom%ny
413  do ji = 1,llgeom%nx
414  ii = ii + 1
415  llfield(ji,jj,jk) = llfield_bump(ii,jk)
416  enddo
417  enddo
418  enddo
419  endif
420 
421  !Open file
422  call nccheck( nf90_open( llgeom%filename, ior(nf90_write, nf90_mpiio), ncid, &
423  comm = llgeom%f_comm%communicator(), info = mpi_info_null), "nf90_open" )
424 
425  !Dimension ID
426  call nccheck( nf90_inq_dimid(ncid, "lon" , x_dimid), "nf90_inq_dimid lon" )
427  call nccheck( nf90_inq_dimid(ncid, "lat" , y_dimid), "nf90_inq_dimid lat" )
428  call nccheck( nf90_inq_dimid(ncid, "lev" , z_dimid), "nf90_inq_dimid lev" )
429  call nccheck( nf90_inq_dimid(ncid, "edge", e_dimid), "nf90_inq_dimid edge" )
430  call nccheck( nf90_inq_dimid(ncid, "time", t_dimid), "nf90_inq_dimid time" )
431 
432  dimids3 = (/ x_dimid, y_dimid, z_dimid, t_dimid /)
433  dimidse = (/ x_dimid, y_dimid, e_dimid, t_dimid /)
434  dimids2 = (/ x_dimid, y_dimid, t_dimid /)
435 
436  ! Pointer to dimensions based on number of levels
437  if (associated(dimids)) nullify(dimids)
438  if (associated(istart)) nullify(istart)
439  if (associated(icount)) nullify(icount)
440  if (fields(var)%npz == geom%npz) then
441  dimids => dimids3
442  istart => llgeom%istart3
443  icount => llgeom%icount3
444  elseif (fields(var)%npz == 1) then
445  dimids => dimids2
446  istart => llgeom%istart2
447  icount => llgeom%icount2
448  elseif (fields(var)%npz == geom%npz+1) then
449  dimids => dimidse
450  istart => llgeom%istarte
451  icount => llgeom%icounte
452  endif
453 
454  if (associated(dimids)) then
455 
456  ! Write field to the file
457  call nccheck( nf90_def_var( ncid, trim(fields(var)%short_name), nf90_double, dimids, varid), &
458  "nf90_def_var"//trim(fields(var)%short_name) )
459  call nccheck( nf90_put_att(ncid, varid, "long_name", trim(fields(var)%long_name) ), "nf90_put_att" )
460  call nccheck( nf90_put_att(ncid, varid, "units" , trim(fields(var)%units) ), "nf90_put_att" )
461  call nccheck( nf90_enddef(ncid), "nf90_enddef" )
462 
463  if (llgeom%thispe) then
464  call nccheck( nf90_put_var( ncid, varid, llfield, start = istart, count = icount), &
465  "nf90_put_var"//trim(fields(var)%short_name) )
466  endif
467 
468  endif
469 
470  ! Close file
471  call nccheck( nf90_close(ncid), "nf90_close" )
472 
473  !Let LatLon PEs catch up
474  call llgeom%f_comm%barrier()
475 
476  deallocate(llfield)
477  deallocate(llfield_bump)
478 
479  endif
480 
481 enddo
482 
483 end subroutine write_latlon_fields
484 
485 ! --------------------------------------------------------------------------------------------------
486 
487 subroutine dummy_final(self)
488 type(fv3jedi_llgeom), intent(inout) :: self
489 end subroutine dummy_final
490 
491 ! --------------------------------------------------------------------------------------------------
492 
493 end module fv3jedi_io_latlon_mod
fv3jedi_io_utils_mod::replace_text
character(len(inputstr)+100) function replace_text(inputstr, search, replace)
Definition: fv3jedi_io_utils_mod.f90:93
fv3jedi_field_mod
Definition: fv3jedi_field_mod.f90:6
fv3jedi_io_latlon_mod::write_latlon_fields
subroutine write_latlon_fields(llgeom, geom, fields)
Definition: fv3jedi_io_latlon_mod.f90:363
fv3jedi_io_latlon_mod::setup_date
subroutine setup_date(self, vdate)
Definition: fv3jedi_io_latlon_mod.f90:83
fv3jedi_netcdf_utils_mod
Definition: fv3jedi_netcdf_utils_mod.F90:6
fv3jedi_io_latlon_mod::fv3jedi_llgeom
Definition: fv3jedi_io_latlon_mod.f90:39
fv3jedi_bump_interp_mod::fv3jedi_bump_interp
Definition: fv3jedi_bump_interp_mod.f90:31
fv3jedi_constants_mod::rad2deg
real(kind=kind_real), parameter, public rad2deg
Definition: fv3jedi_constants_mod.f90:13
fv3jedi_io_utils_mod
Definition: fv3jedi_io_utils_mod.f90:6
fv3jedi_geom_mod
Fortran module handling geometry for the FV3 model.
Definition: fv3jedi_geom_mod.f90:8
fv3jedi_io_latlon_mod
Definition: fv3jedi_io_latlon_mod.f90:6
fv3jedi_geom_mod::fv3jedi_geom
Fortran derived type to hold geometry data for the FV3JEDI model.
Definition: fv3jedi_geom_mod.f90:46
fv3jedi_netcdf_utils_mod::nccheck
subroutine, public nccheck(status, iam)
Definition: fv3jedi_netcdf_utils_mod.F90:21
fv3jedi_io_latlon_mod::write
subroutine write(self, geom, fields, f_conf, vdate)
Definition: fv3jedi_io_latlon_mod.f90:118
fv3jedi_io_latlon_mod::delete
subroutine delete(self)
Definition: fv3jedi_io_latlon_mod.f90:103
fv3jedi_kinds_mod::kind_int
integer, parameter, public kind_int
Definition: fv3jedi_kinds_mod.f90:13
fv3jedi_io_latlon_mod::setup_conf
subroutine setup_conf(self, geom)
Definition: fv3jedi_io_latlon_mod.f90:65
fv3jedi_constants_mod
Definition: fv3jedi_constants_mod.f90:6
fv3jedi_bump_interp_mod
Definition: fv3jedi_bump_interp_mod.f90:7
fv3jedi_io_latlon_mod::write_latlon_metadata
subroutine write_latlon_metadata(llgeom, geom, f_conf, vdate)
Definition: fv3jedi_io_latlon_mod.f90:288
fv3jedi_kinds_mod::kind_real
integer, parameter, public kind_real
Definition: fv3jedi_kinds_mod.f90:14
fv3jedi_io_utils_mod::vdate_to_datestring
subroutine vdate_to_datestring(vdate, datest, date, yyyy, mm, dd, hh, min, ss)
Definition: fv3jedi_io_utils_mod.f90:48
fv3jedi_io_latlon_mod::delete_latlon
subroutine delete_latlon(llgeom)
Definition: fv3jedi_io_latlon_mod.f90:265
fv3jedi_field_mod::fv3jedi_field
Definition: fv3jedi_field_mod.f90:36
fv3jedi_io_latlon_mod::create_latlon
subroutine create_latlon(llgeom, geom)
Definition: fv3jedi_io_latlon_mod.f90:141
fv3jedi_kinds_mod
Definition: fv3jedi_kinds_mod.f90:6
fv3jedi_io_latlon_mod::dummy_final
subroutine dummy_final(self)
Definition: fv3jedi_io_latlon_mod.f90:488