14 use fckit_log_module, 
only : fckit_log
    42   integer, 
allocatable :: dist_indx(:)
    44   character(len=max_string) :: obstype
    46   character(len=max_string) :: filename
    48   character(len=max_string) :: fileout
    52   real(kind=c_double), 
allocatable :: odb_data(:,:)
    60 subroutine ioda_obsdb_setup(self, fvlen, nobs, dist_indx, nlocs, nvars, filename, fileout, obstype)
    70 integer, 
intent(in) :: fvlen
    71 integer, 
intent(in) :: nobs
    72 integer, 
intent(in) :: dist_indx(:)
    73 integer, 
intent(in) :: nlocs
    74 integer, 
intent(in) :: nvars
    75 character(len=*), 
intent(in) :: filename
    76 character(len=*), 
intent(in) :: fileout
    77 character(len=*), 
intent(in) :: obstype
    79 integer :: input_file_type
    81 character(len=:), 
allocatable :: var_list(:)
    82 logical, 
allocatable :: var_select(:)
    84 integer :: var_list_item_len
    86 integer(selected_int_kind(8)), 
allocatable :: dim_sizes(:)
    91 allocate(self%dist_indx(nobs))
    92 self%dist_indx = dist_indx
    95 self%filename  = filename
    96 self%fileout   = fileout
    97 self%obstype   = obstype
    98 call self%obsvars%setup()
   101 select case (input_file_type)
   108   call nc_diag_read_init(self%filename, iunit)
   111   allocate(
character(var_list_item_len)::var_list(file_nvars))
   114   allocate(var_select(file_nvars))
   118     var_select(i) = (
size(dim_sizes) .eq. 1) .and. (dim_sizes(1) .eq. fvlen)
   119     deallocate(dim_sizes)
   127   var_list_item_len = 80
   128   allocate(
character(var_list_item_len)::var_list(file_nvars))
   129   allocate(var_select(file_nvars))
   131   var_list(1) = 
"latitude"   132   var_list(2) = 
"longitude"   135   var_select(1) = .true.
   136   var_select(2) = .true.
   137   var_select(2) = .true.
   145   if (var_select(i)) 
then   151 deallocate(var_select)
   165 if (
allocated(self%dist_indx)) 
deallocate(self%dist_indx)
   171 call self%obsvars%delete()
   184 type(datetime),   
intent(in)    :: t1, t2
   186 character(len=*),
parameter:: myname = 
"ioda_obsdb_getlocs"   187 character(len=255) :: record
   192 integer, 
dimension(:), 
allocatable :: indx
   193 real(kind_real), 
dimension(:), 
allocatable :: time, lon, lat
   194 type(duration), 
dimension(:), 
allocatable :: dt
   195 type(datetime), 
dimension(:), 
allocatable :: t
   196 type(datetime) :: reftime
   198 character(21) :: tstr, tstr2
   203 istep = self%nobs / self%nlocs
   206 allocate(time(self%nlocs), lon(self%nlocs), lat(self%nlocs))
   207 allocate(indx(self%nlocs))
   219 allocate(dt(self%nlocs), t(self%nlocs))
   224 call datetime_create(
"2018-04-15T00:00:00Z", reftime)
   226 call datetime_to_string(reftime, tstr)
   229   dt(i) = int(3600*time(i))
   231   call datetime_update(t(i), dt(i))
   234 call datetime_to_string(t1,tstr)
   235 call datetime_to_string(t2,tstr2)
   240   if (t(i) > t1 .and. t(i) <= t2) 
then   243     call datetime_to_string(t(i),tstr)
   252   locs%lon(i)  = lon(indx(i))
   253   locs%lat(i)  = lat(indx(i))
   254   locs%time(i) = time(indx(i))
   256 locs%indx = indx(1:ilocs)
   258 deallocate(time, lon, lat)
   261 write(record,*) myname,
': allocated/assinged obs-data'   262 call fckit_log%info(record)
   273 use mpi, 
only: mpi_comm_rank, mpi_comm_size, mpi_comm_world, mpi_init, mpi_finalize
   277 use netcdf, 
only: nf90_float, nf90_double, nf90_int
   288 type(ioda_obsdb), 
intent(in) :: self
   289 character(len=*), 
intent(in)   :: vname
   290 type(ioda_obs_var), 
pointer :: vptr
   293 character(len=max_string) :: err_msg
   298 integer, 
allocatable :: dimsizes(:)
   299 real, 
allocatable :: field1d_sngl(:)
   300 real, 
allocatable :: field2d_sngl(:,:)
   301 integer, 
allocatable :: field1d_int(:)
   302 integer, 
allocatable :: field2d_int(:,:)
   303 real(kind_real), 
allocatable :: field1d_dbl(:)
   304 real(kind_real), 
allocatable :: field2d_dbl(:,:)
   305 integer :: input_file_type
   312 call self%obsvars%get_node(vname, vptr)
   313 if (.not.
associated(vptr)) 
then   314   call self%obsvars%add_node(vname, vptr)
   317   select case (input_file_type)
   321       call nc_diag_read_init(self%filename, iunit)
   324       if (.not.nc_diag_read_check_var(iunit, vname)) 
then   325         write(err_msg,*) 
'ioda_obsdb_getvar: var ', trim(vname), 
' does not exist'   326         call abor1_ftn(trim(err_msg))
   331       call nc_diag_read_get_var_dims(iunit, vname, ndims, dimsizes)
   334       vartype = nc_diag_read_get_var_type(iunit, vname)
   336       if (ndims .gt. 1) 
then   337         write(err_msg,*) 
'ioda_obsdb_getvar: var ', trim(vname), 
' must have rank = 1'   338         call abor1_ftn(trim(err_msg))
   341       if (dimsizes(1) .ne. self%fvlen) 
then   342         write(err_msg,*) 
'ioda_obsdb_getvar: var ', trim(vname), 
' size (', dimsizes(1), 
') must equal fvlen (', self%fvlen, 
')'   343         call abor1_ftn(trim(err_msg))
   347       vptr%nobs = self%nobs
   348       allocate(vptr%vals(vptr%nobs))
   350       if (vartype == nf90_double) 
then   351         allocate(field1d_dbl(dimsizes(1)))
   352         call nc_diag_read_get_var(iunit, vname, field1d_dbl)
   353         vptr%vals = field1d_dbl(self%dist_indx)
   354         deallocate(field1d_dbl)
   355       elseif (vartype == nf90_float) 
then   356         allocate(field1d_sngl(dimsizes(1)))
   357         call nc_diag_read_get_var(iunit, vname, field1d_sngl)
   358         vptr%vals = field1d_sngl(self%dist_indx)
   359         deallocate(field1d_sngl)
   360       elseif (vartype == nf90_int) 
then   361         allocate(field1d_int(dimsizes(1)))
   362         call nc_diag_read_get_var(iunit, vname, field1d_int)
   363         vptr%vals = field1d_int(self%dist_indx)
   364         deallocate(field1d_int)
   376           call get_vars (self % filename, [
"lat"], 
"entryno = 1", field2d_dbl)
   378           call get_vars (self % filename, [
"lon"], 
"entryno = 1", field2d_dbl)
   380          call get_vars (self % filename, [
"time"], 
"entryno = 1", field2d_dbl)
   382       vptr%nobs = 
size(field2d_dbl,dim=2)
   383       allocate(vptr%vals(vptr%nobs))
   384       vptr % vals(:) = field2d_dbl(1,:)
   404 character(len=*), 
intent(in) :: vname
   405 real(kind_real), 
intent(out) :: vdata(:)
   407 character(len=*),
parameter:: myname = 
"ioda_obsdb_get_vec"   408 character(len=255) :: record
   424 character(len=*), 
intent(in) :: vname
   425 real(kind_real), 
intent(in)  :: vdata(:)
   428 character(len=*),
parameter  :: myname = 
"ioda_obsdb_put_vec"   429 character(len=255)          :: record
   431 call self%obsvars%get_node(vname, vptr)
   432 if (.not.
associated(vptr)) 
then   433   call self%obsvars%add_node(vname, vptr)
   434   vptr%nobs = self%nobs
   435   allocate(vptr%vals(vptr%nobs))
   438   write(record,*) myname,
' var= ', trim(vname), 
':this column already exists'   439   call abor1_ftn(record)
   446 subroutine ioda_obsdb_generate(self, fvlen, nobs, dist_indx, nlocs, nvars, obstype, lat, lon1, lon2)
   449 integer, 
intent(in) :: fvlen
   450 integer, 
intent(in) :: nobs
   451 integer, 
intent(in) :: dist_indx(:)
   452 integer, 
intent(in) :: nlocs
   453 integer, 
intent(in) :: nvars
   454 character(len=*) :: obstype
   455 real, 
intent(in) :: lat, lon1, lon2
   457 character(len=*),
parameter :: myname = 
"ioda_obsdb_generate"   460 character(len=max_string) :: vname
   463 call ioda_obsdb_setup(self, fvlen, nobs, dist_indx, nlocs, nvars, 
"", 
"", obstype)
   467 call self%obsvars%get_node(vname, vptr)
   468 if (.not.
associated(vptr)) 
then   469   call self%obsvars%add_node(vname, vptr)
   471 vptr%nobs = self%nobs
   475 call self%obsvars%get_node(vname, vptr)
   476 if (.not.
associated(vptr)) 
then   477   call self%obsvars%add_node(vname, vptr)
   479 vptr%nobs = self%nobs
   481   vptr%vals(i) = lon1 + (i-1)*(lon2-lon1)/(nobs-1)
   492 real(kind=kind_real), 
intent(inout) :: ovec(:)
   493 character(len=*), 
intent(in) :: vname
   495 character(len=*),
parameter:: myname = 
"ioda_obsdb_var_to_ovec"   496 character(len=255) :: record
   501 ovec(:) = vptr%vals(:)
   511 type(ioda_obsdb), 
intent(in) :: self
   513 type(ioda_obs_var), 
pointer  :: vptr
   514 character(len=*),
parameter   :: myname = 
"ioda_obsdb_write"   515 character(len=255)           :: record
   516 integer                      :: i,ncid,dimid_1d(1),dimid_nobs
   517 integer, 
allocatable         :: ncid_var(:)
   521 if (self%fileout(len_trim(self%fileout)-3:len_trim(self%fileout)) == 
".nc4" .or. &
   522     self%fileout(len_trim(self%fileout)-3:len_trim(self%fileout)) == 
".nc") 
then   524    write(record,*) myname, 
':write diag in netcdf, filename=', trim(self%fileout)
   525    call fckit_log%info(record)
   527    call check(
'nf90_create', nf90_create(trim(self%fileout),nf90_hdf5,ncid))
   528    call check(
'nf90_def_dim', nf90_def_dim(ncid,trim(self%obstype)//
'_nobs',self%nobs, dimid_nobs))
   529    dimid_1d = (/ dimid_nobs /)
   532    allocate(ncid_var(self%obsvars%n_nodes))
   533    vptr => self%obsvars%head
   534    do while (
associated(vptr))
   536       call check(
'nf90_def_var', nf90_def_var(ncid,trim(vptr%vname)//
'_'//trim(self%obstype),nf90_double,dimid_1d,ncid_var(i)))
   540    call check(
'nf90_enddef', nf90_enddef(ncid))
   543    vptr => self%obsvars%head
   544    do while (
associated(vptr))
   546       call check(
'nf90_put_var', nf90_put_var(ncid,ncid_var(i),vptr%vals))
   550    call check(
'nf90_close', nf90_close(ncid))
   553 else if (self%fileout(len_trim(self%fileout)-3:len_trim(self%fileout)) == 
".odb") 
then   555    write(record,*) myname, 
':write diag in odb2, filename=', trim(self%fileout)
   556    call fckit_log%info(record)
   560    write(record,*) myname, 
':no output'   561    call fckit_log%info(record)
   572   type(ioda_obsdb), 
intent(in) :: self
   574   type(ioda_obs_var), 
pointer :: vptr
   576   print*, 
"DEBUG: ioda_obsdb_dump: fvlen: ", self%fvlen
   577   print*, 
"DEBUG: ioda_obsdb_dump: nobs: ", self%nobs
   578   print*, 
"DEBUG: ioda_obsdb_dump: nlocs: ", self%nlocs
   579   print*, 
"DEBUG: ioda_obsdb_dump: nvars: ", self%nvars
   580   print*, 
"DEBUG: ioda_obsdb_dump: obstype: ", trim(self%obstype)
   581   print*, 
"DEBUG: ioda_obsdb_dump: filename: ", trim(self%filename)
   583   print*, 
"DEBUG: ioda_obsdb_dump: count: ", self%obsvars%n_nodes
   585   vptr => self%obsvars%head
   586   do while (
associated(vptr))
   587     print*, 
"DEBUG: ioda_obsdb_dump: vname: ", trim(vptr%vname)
   588     print*, 
"DEBUG: ioda_obsdb_dump: shape, size: ", shape(vptr%vals), 
size(vptr%vals)
   589     print*, 
"DEBUG: ioda_obsdb_dump: vals (first 5): ", vptr%vals(1:5)
   590     print*, 
"DEBUG: ioda_obsdb_dump: vals (last 5): ", vptr%vals(vptr%nobs-4:vptr%nobs)
   595   print*, 
"DEBUG: ioda_obsdb_dump:"   600 subroutine check(action, status)
   602 use netcdf, 
only: nf90_noerr, nf90_strerror
   606 integer, 
intent (in) :: status
   607 character (len=*), 
intent (in) :: action
   609 if(status /= nf90_noerr) 
then   610    print *, 
"During action: ", trim(action), 
", received error: ", trim(nf90_strerror(status))
   620   character(len=*), 
intent(in) :: fname
   627   if (fname(len_trim(fname)-3:len_trim(fname)) == 
".nc4" .or. &
   628       fname(len_trim(fname)-2:len_trim(fname)) == 
".nc") 
then   630   elseif (fname(len_trim(fname)-3:len_trim(fname)) == 
".odb") 
then subroutine count_query_results(filename, query, num_results)
 
subroutine ioda_obsdb_dump(self)
 
Fortran derived type to hold a set of observation variables. 
 
subroutine, public ioda_obsdb_setup(self, fvlen, nobs, dist_indx, nlocs, nvars, filename, fileout, obstype)
 
subroutine ioda_obsdb_getvar(self, vname, vptr)
 
subroutine check(action, status)
 
Fortran derived type to hold observation locations. 
 
Fortran module handling radiosonde observation space. 
 
subroutine, public ioda_obsdb_get_vec(self, vname, vdata)
 
integer function, public ioda_obsdb_get_ftype(fname)
 
subroutine, public ioda_obsdb_delete(self)
 
Fortran module with ODB API utility routines. 
 
subroutine get_vars(filename, columns, filter, data)
 
subroutine, public ioda_obsdb_getlocs(self, locs, t1, t2)
 
subroutine, public ioda_obsdb_put_vec(self, vname, vdata)
 
subroutine nc_diag_read_close(filename, file_ncdr_id, from_pop)
 
subroutine, public ioda_obsdb_var_to_ovec(self, ovec, vname)
 
Fortran module handling observation locations. 
 
subroutine ioda_obsdb_write(self)
 
integer, parameter max_string
 
subroutine, public ioda_obsdb_generate(self, fvlen, nobs, dist_indx, nlocs, nvars, obstype, lat, lon1, lon2)
 
subroutine, public ioda_locs_setup(self, nlocs)
 
subroutine nc_diag_read_init(filename, file_ncdr_id, from_push)