FV3 Bundle
type_io.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_io
3 ! Purpose: I/O derived type
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS and METEO-FRANCE
7 !----------------------------------------------------------------------
8 module type_io
9 
10 use netcdf
12 use tools_kinds, only: kind_real
13 use tools_missing, only: msi,msr,isanymsi
14 use tools_nc, only: ncfloat
15 use tools_qsort, only: qsort
16 use type_com, only: com_type
17 use type_geom, only: geom_type
18 use type_linop, only: linop_type
19 use type_mpl, only: mpl_type
20 use type_nam, only: nam_type
21 use type_rng, only: rng_type
22 use fckit_mpi_module, only: fckit_mpi_status
23 
24 implicit none
25 
26 ! I/O derived type
27 type io_type
28  integer :: nlon ! Number of output grid longitudes
29  integer :: nlat ! Number of output grid latitudes
30  real(kind_real),allocatable :: lon(:) ! Output grid longitudes
31  real(kind_real),allocatable :: lat(:) ! Output grid latitudes
32  integer,allocatable :: og_to_lon(:) ! Output grid to longitude index
33  integer,allocatable :: og_to_lat(:) ! Output grid to latitude index
34  integer :: nog ! Output grid size
35  integer :: noga ! Output grid size, halo A
36  integer :: nc0b ! Subset Sc0 size, halo B
37  integer,allocatable :: og_to_proc(:) ! Output grid to processor
38  integer,allocatable :: proc_to_noga(:) ! Number of points in output grid, halo A, for each processor
39  integer,allocatable :: oga_to_og(:) ! Output grid, halo A to global
40  integer,allocatable :: og_to_oga(:) ! Output grid, global to halo A
41  integer,allocatable :: c0b_to_c0(:) ! Subset Sc0, halo B to global
42  integer,allocatable :: c0_to_c0b(:) ! Subset Sc0, global to halo B
43  integer,allocatable :: c0a_to_c0b(:) ! Subset Sc0, halo A to halo B
44  type(linop_type) :: og ! Subset Sc0 to grid interpolation
45  type(com_type) :: com_ab ! Communication between halos A and B
46  logical,allocatable :: mask(:,:) ! Mask on output grid
47 contains
48  procedure :: dealloc => io_dealloc
49  procedure :: fld_read => io_fld_read
50  procedure :: fld_write => io_fld_write
51  procedure :: grid_init => io_grid_init
52  procedure :: grid_write => io_grid_write
53 end type io_type
54 
55 private
56 public :: io_type
57 
58 contains
59 
60 !----------------------------------------------------------------------
61 ! Subroutine: io_dealloc
62 ! Purpose: deallocate I/O
63 !----------------------------------------------------------------------
64 subroutine io_dealloc(io)
65 
66 implicit none
67 
68 ! Passed variables
69 class(io_type),intent(inout) :: io ! I/O
70 
71 ! Release memory
72 if (allocated(io%lon)) deallocate(io%lon)
73 if (allocated(io%lat)) deallocate(io%lat)
74 if (allocated(io%og_to_lon)) deallocate(io%og_to_lon)
75 if (allocated(io%og_to_lat)) deallocate(io%og_to_lat)
76 if (allocated(io%og_to_proc)) deallocate(io%og_to_proc)
77 if (allocated(io%proc_to_noga)) deallocate(io%proc_to_noga)
78 if (allocated(io%oga_to_og)) deallocate(io%oga_to_og)
79 if (allocated(io%og_to_oga)) deallocate(io%og_to_oga)
80 if (allocated(io%c0b_to_c0)) deallocate(io%c0b_to_c0)
81 if (allocated(io%c0_to_c0b)) deallocate(io%c0_to_c0b)
82 if (allocated(io%c0a_to_c0b)) deallocate(io%c0a_to_c0b)
83 call io%og%dealloc
84 call io%com_AB%dealloc
85 if (allocated(io%mask)) deallocate(io%mask)
86 
87 end subroutine io_dealloc
88 
89 !----------------------------------------------------------------------
90 ! Subroutine: io_fld_read
91 ! Purpose: write field
92 !----------------------------------------------------------------------
93 subroutine io_fld_read(io,mpl,nam,geom,filename,varname,fld)
94 
95 implicit none
96 
97 ! Passed variables
98 class(io_type),intent(in) :: io ! I/O
99 type(mpl_type),intent(inout) :: mpl ! MPI data
100 type(nam_type),intent(in) :: nam ! Namelist
101 type(geom_type),intent(in) :: geom ! Geometry
102 character(len=*),intent(in) :: filename ! File name
103 character(len=*),intent(in) :: varname ! Variable name
104 real(kind_real),intent(out) :: fld(geom%nc0a,geom%nl0) ! Field
105 
106 ! Local variables
107 integer :: ncid,fld_id,dum
108 real(kind_real) :: fld_c0(geom%nc0,geom%nl0)
109 character(len=1024) :: filename_proc
110 character(len=1024) :: subr = 'fld_read'
111 
112 if (nam%field_io) then
113  if (nam%split_io.and.(mpl%nproc>1)) then
114  ! Open file
115  write(filename_proc,'(a,a,a,a,i4.4,a,i4.4,a)') trim(nam%datadir),'/',trim(filename),'_',mpl%nproc,'-',mpl%myproc,'.nc'
116  call mpl%ncerr(subr,nf90_open(trim(nam%datadir)//'/'//trim(filename),nf90_nowrite,ncid))
117 
118  ! Get variable id
119  call mpl%ncerr(subr,nf90_inq_varid(ncid,trim(varname),fld_id))
120 
121  ! Get data
122  call mpl%ncerr(subr,nf90_get_var(ncid,fld_id,fld))
123 
124  ! Close file
125  call mpl%ncerr(subr,nf90_close(ncid))
126  else
127  if (mpl%main) then
128  ! Open file
129  call mpl%ncerr(subr,nf90_open(trim(nam%datadir)//'/'//trim(filename)//'.nc',nf90_nowrite,ncid))
130 
131  ! Get variable id
132  call mpl%ncerr(subr,nf90_inq_varid(ncid,trim(varname),fld_id))
133 
134  ! Get data
135  call mpl%ncerr(subr,nf90_get_var(ncid,fld_id,fld_c0))
136 
137  ! Close file
138  call mpl%ncerr(subr,nf90_close(ncid))
139  end if
140 
141  ! Global to local
142  call mpl%glb_to_loc(geom%nl0,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,fld_c0,geom%nc0a,fld)
143  end if
144 else
145  ! No field I/O
146  call mpl%abort('field/variable not read: '//trim(filename)//'/'//trim(varname))
147 end if
148 
149 ! Dummy call to avoid compilation warnings
150 dum = io%nog
151 
152 end subroutine io_fld_read
153 
154 !----------------------------------------------------------------------
155 ! Subroutine: io_fld_write
156 ! Purpose: write field
157 !----------------------------------------------------------------------
158 subroutine io_fld_write(io,mpl,nam,geom,filename,varname,fld)
160 implicit none
161 
162 ! Passed variables
163 class(io_type),intent(in) :: io ! I/O
164 type(mpl_type),intent(inout) :: mpl ! MPI data
165 type(nam_type),intent(in) :: nam ! Namelist
166 type(geom_type),intent(in) :: geom ! Geometry
167 character(len=*),intent(in) :: filename ! File name
168 character(len=*),intent(in) :: varname ! Variable name
169 real(kind_real),intent(in) :: fld(geom%nc0a,geom%nl0) ! Field
170 
171 ! Local variables
172 integer :: ic0a,ic0,il0,info
173 integer :: ncid,nc0a_id,nc0_id,nl0_id,fld_id,lon_id,lat_id
174 real(kind_real) :: fld_c0a(geom%nc0a,geom%nl0)
175 real(kind_real),allocatable :: fld_c0(:,:),lon(:),lat(:)
176 character(len=1024) :: filename_proc
177 character(len=1024) :: subr = 'io_fld_write'
178 
179 if (nam%field_io) then
180  ! Apply mask
181  do il0=1,geom%nl0
182  do ic0a=1,geom%nc0a
183  ic0 = geom%c0a_to_c0(ic0a)
184  if (geom%mask_c0(ic0,il0)) then
185  fld_c0a(ic0a,il0) = fld(ic0a,il0)
186  else
187  call msr(fld_c0a(ic0a,il0))
188  end if
189  end do
190  end do
191 
192  if (nam%split_io.and.(mpl%nproc>1)) then
193  ! Check if the file exists
194  write(filename_proc,'(a,a,a,a,i4.4,a,i4.4,a)') trim(nam%datadir),'/',trim(filename),'_',mpl%nproc,'-',mpl%myproc,'.nc'
195  info = nf90_create(trim(filename_proc),or(nf90_noclobber,nf90_64bit_offset),ncid)
196  if (info==nf90_noerr) then
197  ! Write namelist parameters
198  call nam%ncwrite(mpl,ncid)
199 
200  ! Define attribute
201  call mpl%ncerr(subr,nf90_put_att(ncid,nf90_global,'_FillValue',msvalr))
202  else
203  ! Open file
204  call mpl%ncerr(subr,nf90_open(trim(filename_proc),nf90_write,ncid))
205 
206  ! Enter definition mode
207  call mpl%ncerr(subr,nf90_redef(ncid))
208  end if
209 
210  ! Define dimensions and variables if necessary
211  info = nf90_inq_dimid(ncid,'nc0a',nc0a_id)
212  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nc0a',geom%nc0a,nc0a_id))
213  info = nf90_inq_dimid(ncid,'nl0',nl0_id)
214  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0',geom%nl0,nl0_id))
215  info = nf90_inq_varid(ncid,'lon',lon_id)
216  if (info/=nf90_noerr) then
217  call mpl%ncerr(subr,nf90_def_var(ncid,'lon',ncfloat,(/nc0a_id/),lon_id))
218  call mpl%ncerr(subr,nf90_put_att(ncid,lon_id,'_FillValue',msvalr))
219  call mpl%ncerr(subr,nf90_put_att(ncid,lon_id,'unit','degrees_north'))
220  end if
221  info = nf90_inq_varid(ncid,'lat',lat_id)
222  if (info/=nf90_noerr) then
223  call mpl%ncerr(subr,nf90_def_var(ncid,'lat',ncfloat,(/nc0a_id/),lat_id))
224  call mpl%ncerr(subr,nf90_put_att(ncid,lat_id,'_FillValue',msvalr))
225  call mpl%ncerr(subr,nf90_put_att(ncid,lat_id,'unit','degrees_east'))
226  end if
227  info = nf90_inq_varid(ncid,trim(varname),fld_id)
228  if (info/=nf90_noerr) then
229  call mpl%ncerr(subr,nf90_def_var(ncid,trim(varname),ncfloat,(/nc0a_id,nl0_id/),fld_id))
230  call mpl%ncerr(subr,nf90_put_att(ncid,fld_id,'_FillValue',msvalr))
231  end if
232 
233  ! End definition mode
234  call mpl%ncerr(subr,nf90_enddef(ncid))
235 
236  ! Allocation
237  allocate(lon(geom%nc0a))
238  allocate(lat(geom%nc0a))
239 
240  ! Convert to degrees
241  lon = geom%lon(geom%c0a_to_c0)*rad2deg
242  lat = geom%lat(geom%c0a_to_c0)*rad2deg
243 
244  ! Write data
245  call mpl%ncerr(subr,nf90_put_var(ncid,lon_id,lon))
246  call mpl%ncerr(subr,nf90_put_var(ncid,lat_id,lat))
247  call mpl%ncerr(subr,nf90_put_var(ncid,fld_id,fld_c0a))
248 
249  ! Close file
250  call mpl%ncerr(subr,nf90_close(ncid))
251  else
252  ! Allocation
253  allocate(fld_c0(geom%nc0,geom%nl0))
254 
255  ! Local to global
256  call mpl%loc_to_glb(geom%nl0,geom%nc0a,fld_c0a,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,.false.,fld_c0)
257 
258  if (mpl%main) then
259  ! Check if the file exists
260  info = nf90_create(trim(nam%datadir)//'/'//trim(filename)//'.nc',or(nf90_noclobber,nf90_64bit_offset),ncid)
261  if (info==nf90_noerr) then
262  ! Write namelist parameters
263  call nam%ncwrite(mpl,ncid)
264 
265  ! Define attribute
266  call mpl%ncerr(subr,nf90_put_att(ncid,nf90_global,'_FillValue',msvalr))
267  else
268  ! Open file
269  call mpl%ncerr(subr,nf90_open(trim(nam%datadir)//'/'//trim(filename)//'.nc',nf90_write,ncid))
270 
271  ! Enter definition mode
272  call mpl%ncerr(subr,nf90_redef(ncid))
273  end if
274 
275  ! Define dimensions and variables if necessary
276  info = nf90_inq_dimid(ncid,'nc0',nc0_id)
277  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nc0',geom%nc0,nc0_id))
278  info = nf90_inq_dimid(ncid,'nl0',nl0_id)
279  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0',geom%nl0,nl0_id))
280  info = nf90_inq_varid(ncid,'lon',lon_id)
281  if (info/=nf90_noerr) then
282  call mpl%ncerr(subr,nf90_def_var(ncid,'lon',ncfloat,(/nc0_id/),lon_id))
283  call mpl%ncerr(subr,nf90_put_att(ncid,lon_id,'_FillValue',msvalr))
284  call mpl%ncerr(subr,nf90_put_att(ncid,lon_id,'unit','degrees_north'))
285  end if
286  info = nf90_inq_varid(ncid,'lat',lat_id)
287  if (info/=nf90_noerr) then
288  call mpl%ncerr(subr,nf90_def_var(ncid,'lat',ncfloat,(/nc0_id/),lat_id))
289  call mpl%ncerr(subr,nf90_put_att(ncid,lat_id,'_FillValue',msvalr))
290  call mpl%ncerr(subr,nf90_put_att(ncid,lat_id,'unit','degrees_east'))
291  end if
292  info = nf90_inq_varid(ncid,trim(varname),fld_id)
293  if (info/=nf90_noerr) then
294  call mpl%ncerr(subr,nf90_def_var(ncid,trim(varname),ncfloat,(/nc0_id,nl0_id/),fld_id))
295  call mpl%ncerr(subr,nf90_put_att(ncid,fld_id,'_FillValue',msvalr))
296  end if
297 
298  ! End definition mode
299  call mpl%ncerr(subr,nf90_enddef(ncid))
300 
301  ! Allocation
302  allocate(lon(geom%nc0))
303  allocate(lat(geom%nc0))
304 
305  ! Convert to degrees
306  lon = geom%lon*rad2deg
307  lat = geom%lat*rad2deg
308 
309  ! Write data
310  call mpl%ncerr(subr,nf90_put_var(ncid,lon_id,lon))
311  call mpl%ncerr(subr,nf90_put_var(ncid,lat_id,lat))
312  call mpl%ncerr(subr,nf90_put_var(ncid,fld_id,fld_c0))
313 
314  ! Close file
315  call mpl%ncerr(subr,nf90_close(ncid))
316  end if
317  end if
318 
319  ! Regridded field output
320  if (nam%grid_output) call io%grid_write(mpl,nam,geom,filename,trim(varname)//'_regridded',fld)
321 else
322  ! No field I/O
323  call mpl%warning('field/variable not written: '//trim(filename)//'/'//trim(varname))
324 end if
325 
326 end subroutine io_fld_write
327 
328 !----------------------------------------------------------------------
329 ! Subroutine: io_grid_init
330 ! Purpose: initialize fields regridding
331 !----------------------------------------------------------------------
332 subroutine io_grid_init(io,mpl,rng,nam,geom)
334 implicit none
335 
336 ! Passed variables
337 class(io_type),intent(inout) :: io ! I/O
338 type(mpl_type),intent(inout) :: mpl ! MPI data
339 type(rng_type),intent(inout) :: rng ! Random number generator
340 type(nam_type),intent(in) :: nam ! Namelist
341 type(geom_type),intent(in) :: geom ! Geometry
342 
343 ! Local variables
344 integer ::ilon,ilat,i_s,i_s_loc,iog,iproc,ic0,ic0a,ic0b,ioga,il0,nn_index(1)
345 integer,allocatable :: order(:),order_inv(:),interpg_lg(:)
346 real(kind_real) :: dlon,dlat,nn_dist(1)
347 real(kind_real),allocatable :: lon_og(:),lat_og(:)
348 logical :: mask_c0(geom%nc0)
349 logical,allocatable :: mask_lonlat(:,:),mask_og(:),lcheck_og(:),lcheck_c0b(:)
350 type(linop_type) :: ogfull
351 
352 ! Grid size
353 io%nlat = nint(pi/nam%grid_resol)
354 io%nlon = 2*io%nlat
355 dlon = 2.0*pi/real(io%nlon,kind_real)
356 dlat = pi/real(io%nlat,kind_real)
357 
358 ! Allocation
359 allocate(io%lon(io%nlon))
360 allocate(io%lat(io%nlat))
361 allocate(mask_lonlat(io%nlon,io%nlat))
362 
363 ! Setup output grid
364 write(mpl%info,'(a7,a)',advance='no') '','Setup output grid: '
365 call mpl%prog_init(io%nlon*io%nlat)
366 do ilat=1,io%nlat
367  do ilon=1,io%nlon
368  ! Define lon/lat
369  io%lon(ilon) = (-pi+dlon/2)+real(ilon-1,kind_real)*dlon
370  io%lat(ilat) = (-pi/2+dlat/2)+real(ilat-1,kind_real)*dlat
371 
372  ! Check that the interpolation point is inside the domain
373  call geom%mesh%inside(io%lon(ilon),io%lat(ilat),mask_lonlat(ilon,ilat))
374 
375  if (mask_lonlat(ilon,ilat).and.(nam%mask_check.or.geom%mask_del)) then
376  ! Find the nearest Sc0 point
377  call geom%kdtree%find_nearest_neighbors(io%lon(ilon),io%lat(ilat),1,nn_index,nn_dist)
378 
379  ! Check arc
380  call geom%check_arc(1,io%lon(ilon),io%lat(ilat),geom%lon(nn_index(1)),geom%lat(nn_index(1)),mask_lonlat(ilon,ilat))
381  end if
382 
383  ! Update
384  call mpl%prog_print((ilat-1)*io%nlon+ilon)
385  end do
386 end do
387 write(mpl%info,'(a)') '100%'
388 call flush(mpl%info)
389 
390 ! Print results
391 write(mpl%info,'(a7,a)') '','Output grid:'
392 write(mpl%info,'(a10,a,f7.2,a,f5.2,a)') '','Effective resolution: ',0.5*(dlon+dlat)*reqkm,' km (', &
393  & 0.5*(dlon+dlat)*rad2deg,' deg.)'
394 write(mpl%info,'(a10,a,i4,a,i4)') '', 'Size (nlon x nlat): ',io%nlon,' x ',io%nlat
395 
396 ! Allocation
397 io%nog = count(mask_lonlat)
398 allocate(io%og_to_lon(io%nog))
399 allocate(io%og_to_lat(io%nog))
400 allocate(lon_og(io%nog))
401 allocate(lat_og(io%nog))
402 allocate(mask_og(io%nog))
403 allocate(io%og_to_proc(io%nog))
404 allocate(order(io%nog))
405 allocate(order_inv(io%nog))
406 allocate(io%proc_to_noga(mpl%nproc))
407 allocate(io%og_to_oga(io%nog))
408 
409 ! Setup packed output grid
410 iog = 0
411 do ilon=1,io%nlon
412  do ilat=1,io%nlat
413  if (mask_lonlat(ilon,ilat)) then
414  iog = iog+1
415  lon_og(iog) = io%lon(ilon)
416  lat_og(iog) = io%lat(ilat)
417  io%og_to_lon(iog) = ilon
418  io%og_to_lat(iog) = ilat
419  end if
420  end do
421 end do
422 mask_og = .true.
423 
424 ! Interpolation setup
425 mask_c0 = .true.
426 call ogfull%interp(mpl,rng,geom%nc0,geom%lon,geom%lat,mask_c0,io%nog,lon_og,lat_og,mask_og,nam%grid_interp)
427 
428 ! Define a processor for each output grid point
429 call msi(io%og_to_proc)
430 do i_s=1,ogfull%n_s
431  ic0 = ogfull%col(i_s)
432  iproc = geom%c0_to_proc(ic0)
433  iog = ogfull%row(i_s)
434  io%og_to_proc(iog) = iproc
435 end do
436 if (isanymsi(io%og_to_proc)) call mpl%abort('some output grid points are not interpolated')
437 do iproc=1,mpl%nproc
438  io%proc_to_noga(iproc) = count(io%og_to_proc==iproc)
439 end do
440 io%noga = io%proc_to_noga(mpl%myproc)
441 
442 ! Reorder points
443 call qsort(io%nog,io%og_to_proc,order)
444 do iog=1,io%nog
445  order_inv(order(iog)) = iog
446 end do
447 io%og_to_lon = io%og_to_lon(order)
448 io%og_to_lat = io%og_to_lat(order)
449 do i_s=1,ogfull%n_s
450  ogfull%row(i_s) = order_inv(ogfull%row(i_s))
451 end do
452 
453 ! Conversions
454 allocate(io%oga_to_og(io%noga))
455 iog=0
456 do iproc=1,mpl%nproc
457  do ioga=1,io%proc_to_noga(iproc)
458  iog = iog+1
459  io%og_to_oga(iog) = ioga
460  if (iproc==mpl%myproc) io%oga_to_og(ioga) = iog
461  end do
462 end do
463 
464 ! Allocation
465 allocate(lcheck_og(ogfull%n_s))
466 allocate(lcheck_c0b(geom%nc0))
467 
468 ! Halo definitions
469 
470 ! Halo B
471 lcheck_og = .false.
472 lcheck_c0b = .false.
473 do ic0a=1,geom%nc0a
474  ic0 = geom%c0a_to_c0(ic0a)
475  lcheck_c0b(ic0) = .true.
476 end do
477 do i_s=1,ogfull%n_s
478  iog = ogfull%row(i_s)
479  iproc = io%og_to_proc(iog)
480  if (iproc==mpl%myproc) then
481  ic0 = ogfull%col(i_s)
482  lcheck_og(i_s) = .true.
483  lcheck_c0b(ic0) = .true.
484  end if
485 end do
486 
487 ! Halo sizes
488 io%nc0b = count(lcheck_c0b)
489 io%og%n_s = count(lcheck_og)
490 
491 ! Halo B
492 allocate(io%c0b_to_c0(io%nc0b))
493 allocate(io%c0_to_c0b(geom%nc0))
494 ic0b = 0
495 do ic0=1,geom%nc0
496  if (lcheck_c0b(ic0)) then
497  ic0b = ic0b+1
498  io%c0b_to_c0(ic0b) = ic0
499  io%c0_to_c0b(ic0) = ic0b
500  end if
501 end do
502 
503 ! Inter-halo conversions
504 allocate(io%c0a_to_c0b(geom%nc0a))
505 do ic0a=1,geom%nc0a
506  ic0 = geom%c0a_to_c0(ic0a)
507  ic0b = io%c0_to_c0b(ic0)
508  io%c0a_to_c0b(ic0a) = ic0b
509 end do
510 
511 ! Global <-> local conversions for data
512 allocate(interpg_lg(io%og%n_s))
513 i_s_loc = 0
514 do i_s=1,ogfull%n_s
515  if (lcheck_og(i_s)) then
516  i_s_loc = i_s_loc+1
517  interpg_lg(i_s_loc) = i_s
518  end if
519 end do
520 
521 ! Local data
522 
523 ! Horizontal interpolation
524 write(io%og%prefix,'(a,i3.3)') 'og'
525 io%og%n_src = io%nc0b
526 io%og%n_dst = io%noga
527 call io%og%alloc
528 do i_s_loc=1,io%og%n_s
529  i_s = interpg_lg(i_s_loc)
530  io%og%row(i_s_loc) = io%og_to_oga(ogfull%row(i_s))
531  io%og%col(i_s_loc) = io%c0_to_c0b(ogfull%col(i_s))
532  io%og%S(i_s_loc) = ogfull%S(i_s)
533 end do
534 call io%og%reorder(mpl)
535 
536 ! Setup communications
537 call io%com_AB%setup(mpl,'com_AB',geom%nc0,geom%nc0a,io%nc0b,io%c0b_to_c0,io%c0a_to_c0b,geom%c0_to_proc,geom%c0_to_c0a)
538 
539 ! Compute output grid mask
540 allocate(io%mask(io%noga,geom%nl0))
541 io%mask = .true.
542 do i_s=1,io%og%n_s
543  ic0b = io%og%col(i_s)
544  ioga = io%og%row(i_s)
545  ic0 = io%c0b_to_c0(ic0b)
546  do il0=1,geom%nl0
547  if (.not.geom%mask_c0(ic0,il0)) io%mask(ioga,il0) = .false.
548  end do
549 end do
550 
551 ! Print results
552 write(mpl%info,'(a7,a,i4)') '','Parameters for processor #',mpl%myproc
553 write(mpl%info,'(a10,a,i8)') '','nc0 = ',geom%nc0
554 write(mpl%info,'(a10,a,i8)') '','nc0a = ',geom%nc0a
555 write(mpl%info,'(a10,a,i8)') '','nc0b = ',io%nc0b
556 write(mpl%info,'(a10,a,i8)') '','nog = ',io%nog
557 write(mpl%info,'(a10,a,i8)') '','noga = ',io%noga
558 write(mpl%info,'(a10,a,i8)') '','og%n_s = ',io%og%n_s
559 call flush(mpl%info)
560 
561 end subroutine io_grid_init
562 
563 !----------------------------------------------------------------------
564 ! Subroutine: io_grid_write
565 ! Purpose: interpolate and write field
566 !----------------------------------------------------------------------
567 subroutine io_grid_write(io,mpl,nam,geom,filename,varname,fld)
569 implicit none
570 
571 ! Passed variables
572 class(io_type),intent(in) :: io ! I/O
573 type(mpl_type),intent(inout) :: mpl ! MPI data
574 type(nam_type),intent(in) :: nam ! Namelist
575 type(geom_type),intent(in) :: geom ! Geometry
576 character(len=*),intent(in) :: filename ! File name
577 character(len=*),intent(in) :: varname ! Variable name
578 real(kind_real),intent(in) :: fld(geom%nc0a,geom%nl0) ! Field
579 
580 ! Local variables
581 integer :: il0,info,ilon,ilat,iog,ioga,i,iproc
582 integer :: ncid,nlon_gridded_id,nlat_gridded_id,nlev_id,fld_id,lon_gridded_id,lat_gridded_id,lev_id
583 integer,allocatable :: oga_to_og(:)
584 real(kind_real) :: fld_c0b(io%nc0b,geom%nl0)
585 real(kind_real) :: fld_oga(io%noga,geom%nl0)
586 real(kind_real),allocatable :: sbuf(:),rbuf(:),fld_grid(:,:,:),lon_gridded(:),lat_gridded(:)
587 character(len=1024) :: subr = 'io_grid_write'
588 type(fckit_mpi_status) :: status
589 
590 ! Halo extension and interpolation
591 call io%com_AB%ext(mpl,geom%nl0,fld,fld_c0b)
592 do il0=1,geom%nl0
593  call io%og%apply(mpl,fld_c0b(:,il0),fld_oga(:,il0),mssrc=.true.)
594 end do
595 
596 ! Apply mask
597 do il0=1,geom%nl0
598  do ioga=1,io%noga
599  if (.not.io%mask(ioga,il0)) call msr(fld_oga(ioga,il0))
600  end do
601 end do
602 
603 ! Allocation
604 allocate(sbuf(io%noga*geom%nl0))
605 
606 ! Prepare buffer
607 i = 1
608 do il0=1,geom%nl0
609  do ioga=1,io%noga
610  sbuf(i) = fld_oga(ioga,il0)
611  i = i+1
612  end do
613 end do
614 
615 if (mpl%main) then
616  ! Allocation
617  allocate(fld_grid(io%nlon,io%nlat,geom%nl0))
618 
619  ! Initialization
620  call msr(fld_grid)
621 
622  do iproc=1,mpl%nproc
623  ! Allocation
624  allocate(oga_to_og(io%proc_to_noga(iproc)))
625  allocate(rbuf(io%proc_to_noga(iproc)*geom%nl0))
626 
627  if (iproc==mpl%ioproc) then
628  ! Copy buffer
629  oga_to_og = io%oga_to_og
630  rbuf = sbuf
631  else
632  ! Receive data on ioproc
633  call mpl%f_comm%receive(oga_to_og,iproc-1,mpl%tag,status)
634  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag+1,status)
635  end if
636 
637  ! Write data
638  i = 1
639  do il0=1,geom%nl0
640  do ioga=1,io%proc_to_noga(iproc)
641  iog = oga_to_og(ioga)
642  ilon = io%og_to_lon(iog)
643  ilat = io%og_to_lat(iog)
644  fld_grid(ilon,ilat,il0) = rbuf(i)
645  i = i+1
646  end do
647  end do
648 
649  ! Release memory
650  deallocate(oga_to_og)
651  deallocate(rbuf)
652  end do
653 else
654  ! Send data to ioproc
655  call mpl%f_comm%send(io%oga_to_og,mpl%ioproc-1,mpl%tag)
656  call mpl%f_comm%send(sbuf,mpl%ioproc-1,mpl%tag+1)
657 end if
658 call mpl%update_tag(2)
659 
660 ! Release memory
661 deallocate(sbuf)
662 
663 if (mpl%main) then
664  ! Check if the file exists
665  info = nf90_create(trim(nam%datadir)//'/'//trim(filename)//'.nc',or(nf90_noclobber,nf90_64bit_offset),ncid)
666  if (info==nf90_noerr) then
667  ! Write namelist parameters
668  call nam%ncwrite(mpl,ncid)
669 
670  ! Define attribute
671  call mpl%ncerr(subr,nf90_put_att(ncid,nf90_global,'_FillValue',msvalr))
672  else
673  ! Open file
674  call mpl%ncerr(subr,nf90_open(trim(nam%datadir)//'/'//trim(filename)//'.nc',nf90_write,ncid))
675 
676  ! Enter definition mode
677  call mpl%ncerr(subr,nf90_redef(ncid))
678  end if
679 
680  ! Define dimensions and variables if necessary
681  info = nf90_inq_dimid(ncid,'nlon_gridded',nlon_gridded_id)
682  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nlon_gridded',io%nlon,nlon_gridded_id))
683  info = nf90_inq_dimid(ncid,'nlat_gridded',nlat_gridded_id)
684  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nlat_gridded',io%nlat,nlat_gridded_id))
685  info = nf90_inq_dimid(ncid,'nlev',nlev_id)
686  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nlev',geom%nl0,nlev_id))
687  info = nf90_inq_varid(ncid,'lon_gridded',lon_gridded_id)
688  if (info/=nf90_noerr) then
689  call mpl%ncerr(subr,nf90_def_var(ncid,'lon_gridded',ncfloat,(/nlon_gridded_id/),lon_gridded_id))
690  call mpl%ncerr(subr,nf90_put_att(ncid,lon_gridded_id,'_FillValue',msvalr))
691  call mpl%ncerr(subr,nf90_put_att(ncid,lon_gridded_id,'unit','degrees_north'))
692  end if
693  info = nf90_inq_varid(ncid,'lat_gridded',lat_gridded_id)
694  if (info/=nf90_noerr) then
695  call mpl%ncerr(subr,nf90_def_var(ncid,'lat_gridded',ncfloat,(/nlat_gridded_id/),lat_gridded_id))
696  call mpl%ncerr(subr,nf90_put_att(ncid,lat_gridded_id,'_FillValue',msvalr))
697  call mpl%ncerr(subr,nf90_put_att(ncid,lat_gridded_id,'unit','degrees_east'))
698  end if
699  info = nf90_inq_varid(ncid,'lev',lev_id)
700  if (info/=nf90_noerr) then
701  call mpl%ncerr(subr,nf90_def_var(ncid,'lev',ncfloat,(/nlev_id/),lev_id))
702  call mpl%ncerr(subr,nf90_put_att(ncid,lev_id,'_FillValue',msvalr))
703  call mpl%ncerr(subr,nf90_put_att(ncid,lev_id,'unit','layer'))
704  end if
705  info = nf90_inq_varid(ncid,trim(varname),fld_id)
706  if (info/=nf90_noerr) then
707  call mpl%ncerr(subr,nf90_def_var(ncid,trim(varname),ncfloat,(/nlon_gridded_id,nlat_gridded_id,nlev_id/),fld_id))
708  call mpl%ncerr(subr,nf90_put_att(ncid,fld_id,'_FillValue',msvalr))
709  end if
710 
711  ! End definition mode
712  call mpl%ncerr(subr,nf90_enddef(ncid))
713 
714  ! Allocation
715  allocate(lon_gridded(io%nlon))
716  allocate(lat_gridded(io%nlat))
717 
718  ! Convert to degrees
719  lon_gridded = io%lon*rad2deg
720  lat_gridded = io%lat*rad2deg
721 
722  ! Write data
723  call mpl%ncerr(subr,nf90_put_var(ncid,lon_gridded_id,lon_gridded))
724  call mpl%ncerr(subr,nf90_put_var(ncid,lat_gridded_id,lat_gridded))
725  do il0=1,geom%nl0
726  call mpl%ncerr(subr,nf90_put_var(ncid,lev_id,real(il0,kind_real),(/il0/)))
727  end do
728  call mpl%ncerr(subr,nf90_put_var(ncid,fld_id,fld_grid))
729 
730  ! Close file
731  call mpl%ncerr(subr,nf90_close(ncid))
732 
733  ! Release memory
734  deallocate(fld_grid)
735 end if
736 
737 end subroutine io_grid_write
738 
739 end module type_io
real(kind_real), parameter, public rad2deg
Definition: tools_const.F90:17
subroutine io_grid_init(io, mpl, rng, nam, geom)
Definition: type_io.F90:333
real(kind_real), parameter, public msvalr
Definition: tools_const.F90:24
subroutine io_dealloc(io)
Definition: type_io.F90:65
subroutine io_grid_write(io, mpl, nam, geom, filename, varname, fld)
Definition: type_io.F90:568
real(kind_real), parameter, public deg2rad
Definition: tools_const.F90:16
subroutine io_fld_write(io, mpl, nam, geom, filename, varname, fld)
Definition: type_io.F90:159
subroutine io_fld_read(io, mpl, nam, geom, filename, varname, fld)
Definition: type_io.F90:94
integer, parameter, public kind_real
integer, parameter, public ncfloat
Definition: tools_nc.F90:27
real(fp), parameter, public pi
real(kind_real), parameter, public reqkm
Definition: tools_const.F90:19