FV3 Bundle
oda_core_ecda.F90
Go to the documentation of this file.
1 ! -*- f90 -*-
2 !***********************************************************************
3 !* GNU Lesser General Public License
4 !*
5 !* This file is part of the GFDL Flexible Modeling System (FMS).
6 !*
7 !* FMS is free software: you can redistribute it and/or modify it under
8 !* the terms of the GNU Lesser General Public License as published by
9 !* the Free Software Foundation, either version 3 of the License, or (at
10 !* your option) any later version.
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 !* for more details.
16 !*
17 !* You should have received a copy of the GNU Lesser General Public
18 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
19 !***********************************************************************
21  ! FMS Shared modules
22  use fms_mod, only : file_exist, read_data
23  use fms_mod, only : open_namelist_file, check_nml_error, close_file
24  use fms_mod, only : error_mesg, fatal, note
25 #ifdef INTERNAL_FILE_NML
26  USE mpp_mod, ONLY: input_nml_file
27 #endif
28  use mpp_mod, only : mpp_sum, stdout, stdlog, mpp_sync_self
29  use mpp_mod, only : mpp_pe, mpp_root_pe
30  use mpp_io_mod, only : mpp_open, mpp_close, mpp_ascii, mpp_rdonly, mpp_multi, mpp_single, mpp_netcdf
31  use mpp_io_mod, only : mpp_get_atts, mpp_get_info, mpp_get_fields, mpp_read, axistype, fieldtype, mpp_get_axes
32  use mpp_io_mod, only : mpp_get_axis_data, mpp_get_field_name
38  use time_manager_mod, only : operator( <= ), operator( - ), operator( > ), operator ( < )
39  use get_cal_time_mod, only : get_cal_time
40  use axis_utils_mod, only : frac_index
43  use constants_mod, only : deg_to_rad
44 
45  ! ODA_tools modules
48  use oda_types_mod, only : unknown, tao
50 
51  implicit none
52 
53  private
54 
58 
59  ! Parameters
60  integer, parameter :: profile_file = 1
61  integer, parameter :: sfc_file = 2
62 
63  ! oda_core_nml variables
64  real :: max_misfit = 5.0 !< used to inflate observation errors where the difference from the first guess is large
65  real :: ass_start_lat = -87.0 !< set obs domain
66  real :: ass_end_lat = 87.0 !< set obs domain
67  integer :: max_profiles = 50000
68  namelist /oda_core_nml/ max_misfit, ass_start_lat, ass_end_lat, max_profiles
69 
70  ! Shared ocean_obs_nml namelist variables
71  real :: eta_obs_start_lat = -80.0 !< set obs domain
72  real :: eta_obs_end_lat = 85.0 !< set obs domain
73  real :: sst_obs_start_lat = -82.0 !< set obs domain
74  real :: sst_obs_end_lat = 89.0 !< set obs domain
75 
76  integer :: max_prflvs = 200 ! for vd test
77 
78  type(ocean_profile_type), target, dimension(:), allocatable :: profiles
79 
80  integer :: num_profiles, no_sst, no_prf, no_temp, no_salt, no_suv, no_eta ! total number of observations
81  integer :: no_woa05
82 
83  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed ! indices for local domain on model grid
84  integer :: isg, ieg, jsg, jeg
87  integer :: nk
88 
89  real, dimension(:,:), allocatable, save :: mask_tao
90 
91  ! sst obs grid information
92  real, allocatable :: woa05_lon(:), woa05_lat(:), woa05_z(:)
93  real, allocatable :: sst_lon(:), sst_lat(:), obs_sst(:,:)
94  real, allocatable, save :: obs_woa05t(:,:,:), obs_woa05s(:,:,:)
95  integer :: nlon, nlat, nlev
96  integer :: nlon_woa, nlat_woa, nlev_woa
97 
98  ! time window for DROP, MOORING and SATELLITE data respectively
99 
100  type(time_type) , dimension(0:100), public :: time_window
101 
102  type(grid_type), pointer :: grd
103 
104  type(horiz_interp_type), save :: interp
105 
106  real, allocatable, dimension(:, :) :: x_grid, y_grid, x_grid_uv, y_grid_uv
107  real :: lon_out(1, 1), lat_out(1, 1)
108 
110 
111  integer :: ssh_td
112 
114  character(len=128) :: filename
115  character(len=16) :: file_type
116  end type obs_entry_type
117 
118 
119 contains
120 
121  subroutine init_observations(time_s, time_e, filt_domain, localize)
122  type(time_type), intent(in) :: time_s, time_e
123  type(domain2d), intent(in) :: filt_domain
124  logical, intent(in), optional :: localize
125 
126  integer, parameter :: SUV_ID = 4, eta_id = 5, woat_id = 11, woas_id = 12
127 
128  ! ocean_obs_nml variables
129  integer :: mooring_window = 5
130  integer :: satellite_window = 10
131  integer :: drop_window = 30
132  integer :: drifter_window = 30
133  integer :: ship_window = 30
134  integer :: unknown_window = 30
135 
136  logical :: prfs_obs, salt_obs, sst_obs, eta_obs, suv_obs
137  logical :: temp_obs_argo, salt_obs_argo, temp_obs_gtspp
138  logical :: temp_obs_woa05, salt_obs_woa05
139  integer :: eta_obs_td = 10
140  integer :: max_files = 30
141  integer :: max_files_argo = 10
142  integer :: max_files_gtspp = 10
143  namelist /ocean_obs_nml/ mooring_window, satellite_window, drop_window,&
144  & drifter_window, ship_window, unknown_window,&
145  & prfs_obs, salt_obs, sst_obs, eta_obs, suv_obs,&
146  & temp_obs_argo, salt_obs_argo, temp_obs_gtspp,&
147  & temp_obs_woa05, salt_obs_woa05, eta_obs_td,&
149  & max_files, max_files_argo, max_files_gtspp
150 
151  integer :: i, j, n, obs_variable
152  integer :: ioun, io_status, ierr
153  integer :: stdout_unit, stdlog_unit
154  integer :: nfiles, nrecs, unit
155  integer :: nfiles_argo, nrecs_argo, unit_argo
156  integer :: nfiles_gtspp, nrecs_gtspp, unit_gtspp
157  integer, dimension(:), allocatable :: filetype
158  integer, dimension(:), allocatable :: filetype_argo
159  integer, dimension(:), allocatable :: filetype_gtspp
160 
161  character(len=128) :: input_files_woa05t, input_files_woa05s
162  character(len=256) :: record
163  character(len=128), dimension(:), allocatable :: input_files
164  character(len=128), dimension(:), allocatable :: input_files_argo
165  character(len=128), dimension(:), allocatable :: input_files_gtspp
166 
167  type(obs_entry_type) :: tbl_entry
168 
169  stdout_unit = stdout()
170  stdlog_unit = stdlog()
171 
172 #ifdef INTERNAL_FILE_NML
173  read (input_nml_file, ocean_obs_nml, iostat=io_status)
174 #else
175  ioun = open_namelist_file()
176  read(unit=ioun, nml=ocean_obs_nml, iostat=io_status)
177  ierr = check_nml_error(io_status,'ocean_obs_nml')
178  call close_file(ioun)
179 #endif
180  write (unit=stdlog_unit, nml=ocean_obs_nml)
181 
182  ! Allocate filetype* and input_files* variables
183  allocate(filetype(max_files), input_files(max_files))
184  allocate(filetype_argo(max_files_argo), input_files_argo(max_files_argo))
185  allocate(filetype_gtspp(max_files_gtspp), input_files_gtspp(max_files_gtspp))
186 
187  filetype = -1
188  filetype_argo = -1
189  filetype_gtspp = -1
190  input_files = ''
191  input_files_argo = ''
192  input_files_gtspp = ''
193 
194  if ( prfs_obs .or. salt_obs .or. temp_obs_argo .or. temp_obs_gtspp .or. salt_obs_argo ) then
195  ocn_obs%use_prf_as_obs = .true.
196  end if
197  ocn_obs%use_sst_as_obs = sst_obs
198  ocn_obs%use_ssh_as_obs = eta_obs
199  ocn_obs%use_suv_as_obs = suv_obs
200  ocn_obs%use_woa05_t = temp_obs_woa05
201  ocn_obs%use_woa05_s = salt_obs_woa05
202  ssh_td = eta_obs_td
203 
204  ! time window for DROP, MOORING and SATELLITE data respectively
205  ! will be available from namelist
206  time_window(:) = set_time(0,unknown_window)
207  time_window(drop_profiler:drop_profiler+9) = set_time(0,drop_window)
208  time_window(mooring:mooring+9) = set_time(0,mooring_window)
209  time_window(satellite:satellite+9) = set_time(0,satellite_window)
210  time_window(drifter:drifter+9) = set_time(0,drifter_window)
211  time_window(ship:ship+9) = set_time(0,ship_window)
212 
213  nfiles = 0
214  nrecs=0
215  call mpp_open(unit, 'ocean_obs_table', action=mpp_rdonly)
216  read_obs: do while ( nfiles <= max_files )
217  read (unit=unit, fmt='(A)', iostat=io_status) record
218  if ( io_status < 0 ) then
219  exit read_obs
220  else if ( io_status > 0 ) then
221  cycle read_obs
222  else
223  nrecs = nrecs + 1
224  if ( record(1:1) == '#' ) cycle read_obs
225  read ( unit=record, fmt=*, iostat=io_status ) tbl_entry
226  if ( io_status < 0 ) then
227  exit read_obs
228  else if ( io_status > 0 ) then
229  cycle read_obs
230  else
231  nfiles = nfiles + 1
232  input_files(nfiles) = tbl_entry%filename
233  select case ( trim(tbl_entry%file_type) )
234  case ('profiles')
235  filetype(nfiles) = profile_file
236  case ('sfc')
237  filetype(nfiles) = sfc_file
238  case default
239  call error_mesg('oda_core_mod::init_observations', 'error in obs_table entry format', fatal)
240  end select
241  end if
242  end if
243  end do read_obs
244  if ( nfiles > max_files ) then
245  call error_mesg('oda_core_mod::init_observations', 'number of obs files exceeds max_files parameter', fatal)
246  end if
247  CALL mpp_close(unit)
248 
249  nfiles_argo = 0
250  nrecs_argo = 0
251  call mpp_open(unit_argo, 'ocean_obs_argo_table', action=mpp_rdonly)
252  read_obs_argo: do while ( nfiles_argo <= max_files_argo )
253  read (unit=unit_argo, fmt='(A)', iostat=io_status) record
254  if ( io_status < 0 ) then
255  exit read_obs_argo
256  else if ( io_status > 0 ) then
257  cycle read_obs_argo
258  else
259  nrecs_argo = nrecs_argo + 1
260  if ( record(1:1) == '#' ) cycle read_obs_argo
261  read (unit=record, fmt=*, iostat=io_status) tbl_entry
262  if ( io_status < 0 ) then
263  exit read_obs_argo
264  else if ( io_status > 0 ) then
265  cycle read_obs_argo
266  else
267  nfiles_argo = nfiles_argo + 1
268  input_files_argo(nfiles_argo) = tbl_entry%filename
269  select case ( trim(tbl_entry%file_type) )
270  case ('profiles')
271  filetype_argo(nfiles_argo) = profile_file
272  case ('sfc')
273  filetype_argo(nfiles_argo) = sfc_file
274  case default
275  call error_mesg('oda_core_mod::init_observations', 'error in obs_table entry format for argo', fatal)
276  end select
277  end if
278  end if
279  end do read_obs_argo
280  if ( nfiles_argo > max_files_argo ) then
281  call error_mesg('oda_core_mod::init_observations', 'number of obs files exceeds max_files_argo parameter', fatal)
282  end if
283  call mpp_close(unit_argo)
284 
285  nfiles_gtspp = 0
286  nrecs_gtspp = 0
287  call mpp_open(unit_gtspp, 'ocean_obs_gtspp_table', action=mpp_rdonly)
288  read_obs_gtspp: do while ( nfiles_gtspp <= max_files_gtspp )
289  read (unit=unit_gtspp, fmt='(A)', iostat=io_status) record
290  if ( io_status < 0 ) then
291  exit read_obs_gtspp
292  else if ( io_status > 0 ) then
293  cycle read_obs_gtspp
294  else
295  nrecs_gtspp = nrecs_gtspp + 1
296  if ( record(1:1) == '#' ) cycle read_obs_gtspp
297  read (unit=record, fmt=*, iostat=io_status) tbl_entry
298  if ( io_status < 0 ) then
299  exit read_obs_gtspp
300  else if ( io_status > 0 ) then
301  cycle read_obs_gtspp
302  else
303  nfiles_gtspp = nfiles_gtspp + 1
304  input_files_gtspp(nfiles_gtspp) = tbl_entry%filename
305  select case ( trim(tbl_entry%file_type) )
306  case ('profiles')
307  filetype_gtspp(nfiles_gtspp) = profile_file
308  case ('sfc')
309  filetype_gtspp(nfiles_gtspp) = sfc_file
310  case default
311  call error_mesg('oda_core_mod::init_observations', 'error in obs_table entry format for gtspp', fatal)
312  end select
313  end if
314  end if
315  end do read_obs_gtspp
316  if ( nfiles_gtspp > max_files_gtspp ) then
317  call error_mesg('oda_core_mod::init_observations', 'number of obs files exceeds max_files_gtspp parameter', fatal)
318  end if
319  CALL mpp_close(unit_gtspp)
320 
321  num_profiles = 0
322  no_prf = 0
323  no_sst = 0
324  no_temp = 0
325  no_salt = 0
326  no_suv = 0
327  no_eta = 0
328  no_woa05 = 0
329 
330  ! get local indices for Model grid
331  allocate(x_grid(isg:ieg,jsg:jeg), x_grid_uv(isg:ieg,jsg:jeg))
332  allocate(y_grid(isg:ieg,jsg:jeg), y_grid_uv(isg:ieg,jsg:jeg))
333 
334  call mpp_global_field(filt_domain, grd%x(:,:), x_grid(:,:))
335  call mpp_global_field(filt_domain, grd%y(:,:), y_grid(:,:))
336 
337  ! Allocate profiles
338  allocate(profiles(max_profiles))
339 
340  do j=jsg, jeg
341  do i=isg, ieg
342  if ( x_grid(i,j) .lt. 80.0 ) x_grid(i,j) = x_grid(i,j) + 360.0
343  end do
344  end do
345 
346  ! uv grid may not be precise, need to be carefully checked
347  x_grid_uv(:,:) = x_grid(:,:) + 0.5
348  do j=jsg, jeg-1
349  do i=isg, ieg
350  y_grid_uv(i,j) = y_grid(i,j) + 0.5*(y_grid(i,j+1)-y_grid(i,j))
351  end do
352  end do
353  do i=isg, ieg
354  y_grid_uv(i,jeg) = 90.0
355  end do
356 
357  if ( prfs_obs ) then
358  obs_variable = temp_id
359  if ( mpp_pe() == mpp_root_pe() ) then
360  write (unit=stdout_unit, fmt='("TEMP_ID = ",I5)') temp_id
361  end if
362  do n=1, nfiles
363  select case ( filetype(n) )
364  case (profile_file)
365  call open_profile_dataset(trim(input_files(n)), time_s, time_e, obs_variable, localize)
366  case default
367  call error_mesg('oda_core_mod::init_observations', 'filetype not currently supported for prfs_obs', fatal)
368  end select
369  end do
370  end if
371 
372  if ( salt_obs ) then
373  obs_variable = salt_id
374  if ( mpp_pe() == mpp_root_pe() ) then
375  write (unit=stdout_unit, fmt='("SALT_ID = ",I5)') salt_id
376  end if
377  do n=1, nfiles
378  select case ( filetype(n) )
379  case (profile_file)
380  call open_profile_dataset(trim(input_files(n)), time_s, time_e, obs_variable, localize)
381  case default
382  call error_mesg('oda_core_mod::init_observations', 'filetype not currently supported for salt_obs', fatal)
383  end select
384  end do
385  end if
386 
387  if ( temp_obs_gtspp ) then
388  obs_variable = temp_id
389  if ( mpp_pe() == mpp_root_pe() ) then
390  write (unit=stdout_unit, fmt='("TEMP_ID = ",I5)') temp_id
391  end if
392  do n=1, nfiles_gtspp
393  if ( mpp_pe() == mpp_root_pe() ) then
394  write (unit=stdout_unit, fmt='("f_typ_gtspp = ",I8)') filetype_gtspp(n)
395  write (unit=stdout_unit, fmt='("i_f_gtspp = ",A)') input_files_gtspp(n)
396  end if
397  select case ( filetype_gtspp(n) )
398  case (profile_file)
400  case default
401  call error_mesg('oda_core_mod::init_observations', 'filetype_gtspp not currently supported', fatal)
402  end select
403  end do
404  end if
405 
406  if ( temp_obs_argo ) then
407  obs_variable = temp_id
408  if ( mpp_pe() == mpp_root_pe() ) then
409  write (unit=stdout_unit, fmt='("TEMP_ID = ",I5)') temp_id
410  end if
411  do n=1, nfiles_argo
412  if ( mpp_pe() == mpp_root_pe() ) then
413  write (unit=stdout_unit, fmt='("f_typ_argo = ",I8)') filetype_argo(n)
414  write (unit=stdout_unit, fmt='("i_f_argo = ",A)') input_files_argo(n)
415  end if
416  select case ( filetype_argo(n) )
417  case (profile_file)
418  call open_profile_dataset_argo(trim(input_files_argo(n)), time_s, time_e, obs_variable, localize)
419  case default
420  call error_mesg('oda_core_mod::init_observations', 'filetype_argo not currently supported', fatal)
421  end select
422  end do
423  end if
424 
425  if ( salt_obs_argo ) then
426  obs_variable = salt_id
427  if ( mpp_pe() == mpp_root_pe() ) then
428  write (unit=stdout_unit, fmt='("SALT_ID = ",I5)') salt_id
429  end if
430  do n=1, nfiles_argo
431  select case ( filetype_argo(n) )
432  case (profile_file)
433  call open_profile_dataset_argo(trim(input_files_argo(n)), time_s, time_e, obs_variable, localize)
434  case default
435  call error_mesg('oda_core_mod::init_observations', 'filetype_argo not currently supported', fatal)
436  end select
437  end do
438  end if
439 
440  if ( temp_obs_woa05 ) then
441  obs_variable = woat_id
442  if ( mpp_pe() == mpp_root_pe() ) then
443  write (unit=stdout_unit, fmt='("WOAT_ID = ",I5)') woat_id
444  end if
445  input_files_woa05t = "INPUT/woa05_temp.nc"
446  call open_profile_dataset_woa05t(trim(input_files_woa05t), obs_variable, localize)
447  end if
448 
449  if ( salt_obs_woa05 ) then
450  obs_variable = woas_id
451  if ( mpp_pe() == mpp_root_pe() ) then
452  write (unit=stdout_unit, fmt='("WOAS_ID = ",I5)') woas_id
453  end if
454  input_files_woa05s = "INPUT/woa05_salt.nc"
455  call open_profile_dataset_woa05s(trim(input_files_woa05s), obs_variable, localize)
456  end if
457 
458  if ( sst_obs ) then
459  obs_variable = temp_id
460  if ( mpp_pe() == mpp_root_pe() ) then
461  write (unit=stdout_unit, fmt='("TEMP_ID for sst = ",I5)') temp_id
462  end if
463  nfiles = 1
464  nrecs = 0
465  input_files(nfiles) = "INPUT/sst_daily.nc"
466  filetype(nfiles) = profile_file
467 !!$ call open_profile_dataset_sst(trim(input_files(nfiles)), obs_variable, localize)
468  end if
469 
470  if ( eta_obs ) then
471  obs_variable = eta_id
472  nfiles = 1
473  nrecs = 0
474  input_files(nfiles) = "INPUT/ocean.19760101-20001231.eta_t.nc"
475  filetype(nfiles) = profile_file
476  call open_profile_dataset_eta(trim(input_files(nfiles)), obs_variable, localize)
477  end if
478 
479  if ( suv_obs ) then
480  obs_variable = suv_id
481  nfiles = 1
482  nrecs = 0
483  input_files(nfiles) = "INPUT/sfc_current.197601-200012.nc"
484  filetype(nfiles) = profile_file
485  call open_profile_dataset_suv(trim(input_files(nfiles)), obs_variable, localize)
486  end if
487 
488  ! Deallocate before exiting routine
489  deallocate(filetype, input_files)
490  deallocate(filetype_argo, input_files_argo)
491  deallocate(filetype_gtspp, input_files_gtspp)
492  end subroutine init_observations
493 
494  subroutine open_profile_dataset(filename, time_start, time_end, obs_variable, localize)
495  character(len=*), intent(in) :: filename
496  type(time_type), intent(in) :: time_start, time_end
497  integer, intent(in) :: obs_variable
498  logical, intent(in), optional :: localize
499 
500  integer, parameter :: max_levels = 1000
501  integer, parameter :: max_lnks = 500
502 
503  real :: lon, lat, time, profile_error, rlink, flag_t, flag_s, fix_depth
504  real :: ri0, rj0
505  real, dimension(MAX_LEVELS) :: depth, data, t_flag, s_flag
506  real, dimension(MAX_LNKS, MAX_LEVELS) :: data_bfr, depth_bfr, t_flag_bfr, s_flag_bfr
507 
508  integer :: unit, ndim, nvar, natt, nstation
509  integer :: stdout_unit
510  integer :: inst_type, var_id
511  integer :: num_levs, k, kk, i, i0, j0, k0, nlevs, a, nn, ii, nlinks
512  integer :: nprof_in_filt_domain
513  integer :: bad_point, bad_point_g, out_bound_point
514 
515  logical :: data_is_local, localize_data, cont
516  logical :: data_in_period
517  logical :: prof_in_filt_domain
518  logical, dimension(MAX_LEVELS) :: flag
519  logical, dimension(MAX_LNKS, MAX_LEVELS) :: flag_bfr
520 
521  character(len=32) :: fldname, axisname, anal_fldname, time_units
522  character(len=138) :: emsg_local
523 
524  type(time_type) :: profile_time
525  type(axistype), pointer :: depth_axis, station_axis
526  type(axistype), allocatable, dimension(:), target :: axes
527  type(fieldtype), allocatable, dimension(:), target :: fields
528  type(fieldtype), pointer :: field_lon, field_lat, field_flag, field_time, field_depth, field_data
529  type(fieldtype), pointer :: field_error, field_link, field_t_flag, field_s_flag, field_fix_depth ! snz drop rate
530 
531  ! NOTE: fields are restricted to be in separate files
532 
533  if ( PRESENT(localize) ) then
534  localize_data = localize
535  else
536  localize_data = .true.
537  end if
538 
539  nprof_in_filt_domain = 0
540  stdout_unit = stdout()
541 
542  anal_fldname = 'none'
543  var_id=-1
544  if ( obs_variable == temp_id ) then
545  anal_fldname = 'temp'
546  var_id = temp_id
547  else if ( obs_variable == salt_id ) then
548  anal_fldname = 'salt'
549  var_id = salt_id
550  end if
551 
552 ! call mpp_print_memuse_stats('open_profile_dataset Start')
553 
554  call mpp_open(unit, filename, form=mpp_netcdf, fileset=mpp_single, threading=mpp_multi, action=mpp_rdonly)
555  call mpp_get_info(unit, ndim, nvar, natt, nstation)
556 
557  if ( mpp_pe() .eq. mpp_root_pe() ) then
558  write (unit=stdout_unit, fmt='("Opened profile dataset: ",A)') trim(filename)
559  end if
560 
561  ! get axis information
562  allocate(axes(ndim))
563  call mpp_get_axes(unit, axes)
564  do i=1, ndim
565  call mpp_get_atts(axes(i), name=axisname)
566  select case ( trim(axisname) )
567  case ('depth_index')
568  depth_axis => axes(i)
569  case ('station_index')
570  station_axis => axes(i)
571  end select
572  end do
573 
574  ! get field information
575  allocate(fields(nvar))
576  call mpp_get_fields(unit, fields)
577  do i=1, nvar
578  call mpp_get_atts(fields(i), name=fldname)
579  if( var_id .eq. temp_id ) then
580  select case (trim(fldname))
581  case ('longitude')
582  field_lon => fields(i)
583  case ('latitude')
584  field_lat => fields(i)
585  case ('profile_flag')
586  field_flag => fields(i)
587  case ('time')
588  field_time => fields(i)
589  case ('temp')
590  field_data => fields(i)
591  case ('depth')
592  field_depth => fields(i)
593  case ('link')
594  field_link => fields(i)
595  case ('temp_error')
596  field_error => fields(i)
597  case ('temp_flag')
598  field_t_flag => fields(i)
599  case ('fix_depth') ! snz drop rate
600  field_fix_depth => fields(i)
601  end select
602  else if( var_id .eq. salt_id ) then
603  select case (trim(fldname))
604  case ('longitude')
605  field_lon => fields(i)
606  case ('latitude')
607  field_lat => fields(i)
608  case ('profile_flag_s')
609  field_flag => fields(i)
610  case ('time')
611  field_time => fields(i)
612  case ('salt')
613  field_data => fields(i)
614  case ('depth')
615  field_depth => fields(i)
616  case ('link')
617  field_link => fields(i)
618  case ('salt_error')
619  field_error => fields(i)
620  case ('salt_flag')
621  field_s_flag => fields(i)
622  case ('fix_depth') ! snz drop rate
623  field_fix_depth => fields(i)
624  end select
625  end if
626  end do
627 
628  call mpp_get_atts(depth_axis, len=nlevs)
629 
630  if ( nlevs > max_levels ) then
631  call error_mesg('oda_core_mod::open_profile_dataset', 'increase parameter MAX_LEVELS', fatal)
632  else if (nlevs < 1) then
633  call error_mesg('oda_core_mod::open_profile_dataset', 'Value of nlevs is less than 1.', fatal)
634  end if
635 
636  if ( .NOT.ASSOCIATED(field_data) ) then
637  call error_mesg('oda_core_mod::open_profile_dataset',&
638  & 'profile dataset not used because data not needed for Analysis', note)
639  return
640  end if
641 
642  write(unit=stdout_unit, fmt='("There are ",I8," records in this dataset.")') nstation
643  write(unit=stdout_unit, fmt='("Searching for profiles . . .")')
644 
645  call mpp_get_atts(field_time, units=time_units)
646 
647  bad_point = 0
648  out_bound_point = 0
649 
650  i = 1
651  cont = .true.
652 
653  do while ( cont )
654  prof_in_filt_domain = .false.
655  depth = missing_value ! snz add
656  data = missing_value ! snz add
657 
658  call mpp_read(unit, field_lon, lon, tindex=i)
659  call mpp_read(unit, field_lat, lat, tindex=i)
660  call mpp_read(unit, field_time, time, tindex=i)
661  call mpp_read(unit, field_depth, depth(1:nlevs), tindex=i)
662  call mpp_read(unit, field_data, data(1:nlevs), tindex=i)
663  call mpp_read(unit, field_error, profile_error, tindex=i)
664  call mpp_read(unit, field_fix_depth, fix_depth, tindex=i) ! snz drop rate
665  if ( var_id == temp_id ) then
666  call mpp_read(unit, field_t_flag, t_flag(1:nlevs), tindex=i)
667  call mpp_read(unit, field_flag, flag_t, tindex=i)
668  else if ( var_id == salt_id ) then
669  call mpp_read(unit, field_s_flag, s_flag(1:nlevs), tindex=i)
670  call mpp_read(unit, field_flag, flag_s, tindex=i)
671  end if
672  call mpp_read(unit, field_link, rlink, tindex=i)
673 
674  inst_type = 20 ! snz change one line
675 !!$ inst_type = DRIFTER + ARGO
676 
677  data_is_local = .false.
678  data_in_period = .false.
679 
680  if ( lon .lt. 0.0 ) lon = lon + 360.0
681  if ( lon .gt. 360.0 ) lon = lon - 360.0
682  if ( lon .lt. 80.0 ) lon = lon + 360.0
683 
684  if ( lat > ass_start_lat .and. lat < ass_end_lat ) data_is_local = .true.
685 
686  profile_time = get_cal_time(time, time_units, 'julian')
687  if ( profile_time > time_start .and. profile_time < time_end ) data_in_period = .true.
688  if ( (data_in_period .and. data_is_local) .and. (.NOT.localize_data) ) then ! localize
689 
690  if (isd_filt < 1 .and. ied_filt > ieg) then
691  ! filter domain is a full x band
692  if (lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
693  lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ieg-1,jsd_flt0)) then
694  prof_in_filt_domain = .true.
695  end if
696  else if (isd_filt >= 1 .and. ied_filt <= ieg) then
697  ! Interior filter domain
698  if (lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
699  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)) then
700  prof_in_filt_domain = .true.
701  end if
702  else if (isd_filt < 1 .and. ied_filt <= ieg) then
703  ! lhs filter domain
704  isd_flt0 = isd_filt + ieg
705  if ((lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
706  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)).or.&
707  & (lon >= x_grid(isd_flt0,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
708  & lat >= y_grid(isd_flt0,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1))) then
709  prof_in_filt_domain = .true.
710  end if
711  else if (isd_filt >= 1 .and. ied_filt > ieg) then
712  ! rhs filter domain
713  ied_flt0 = ied_filt - ieg
714  if ( lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
715  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1) ) then
716  prof_in_filt_domain = .true.
717  end if
718  if (ied_flt0-1 > 1) then
719  if ( lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_flt0-1,jsd_flt0) .and.&
720  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_flt0-1,jed_flt0-1) ) then
721  prof_in_filt_domain = .true.
722  end if
723  end if
724  end if
725 
726  if ( var_id == temp_id .and. flag_t == 0.0 ) then
728  no_temp = no_temp + 1
729  no_prf = no_prf + 1
730  end if
731  if ( var_id == salt_id .and. flag_s == 0.0 ) then
733  no_salt = no_salt + 1
734  no_prf = no_prf + 1
735  end if
736 
737  if ( num_profiles > max_profiles ) then
738  call error_mesg('oda_core_mod::open_profile_dataset',&
739  & 'maximum number of profiles exceeded, increase max_profiles in oda_core_nml', fatal)
740  end if
741 
742  num_levs = 0
743  do k=1, max_levels
744  flag(k) = .true.
745 
746  if ( depth(k) > 2000.0 ) depth(k) = missing_value ! snz add for rdat-hybn
747 
748  if ( var_id == temp_id ) then
749  if ( data(k) .eq. missing_value .or.&
750  & depth(k) .eq. missing_value .or. t_flag(k) .ne. 0.0 ) then
751  flag(k) = .false.
752  else
753  num_levs = num_levs + 1
754  end if
755  else if ( var_id == salt_id ) then
756  if ( data(k) .eq. missing_value .or.&
757  & depth(k) .eq. missing_value .or. s_flag(k) .ne. 0.0 ) then
758  flag(k) = .false.
759  else
760  num_levs = num_levs+1
761  end if
762  end if
763  end do
764 
765  ! large profile are stored externally in separate records
766  ! read linked records and combine profile
767  ii = i + 1
768  nlinks = 0
769  do while ( rlink > 0.0 )
770  nlinks = nlinks + 1
771 
772  if ( nlinks > max_lnks ) then
773  write (emsg_local, '("nlinks (",I6,") > MAX_LNKS (",I6,")")')&
774  & nlinks, max_lnks
775  call error_mesg('oda_core_mod::open_profile_dataset',&
776  & trim(emsg_local)//' in file "'//trim(filename)//&
777  & '". Increase parameter MAX_LNKS', fatal)
778  end if
779 
780  depth_bfr(nlinks,:) = missing_value
781  data_bfr(nlinks,:) = missing_value
782  call mpp_read(unit, field_depth, depth_bfr(nlinks,1:nlevs), tindex=ii)
783  call mpp_read(unit, field_data, data_bfr(nlinks,1:nlevs), tindex=ii)
784  if ( var_id == temp_id ) then
785  call mpp_read(unit, field_t_flag, t_flag_bfr(nlinks,1:nlevs), tindex=ii)
786  else if ( var_id == salt_id ) then
787  call mpp_read(unit, field_s_flag, s_flag_bfr(nlinks,1:nlevs), tindex=ii)
788  end if
789  call mpp_read(unit, field_link, rlink, tindex=ii)
790  ii = ii + 1
791  end do
792  i = ii ! set record counter to start of next profile
793 
794  if ( nlinks > 0 ) then
795  do nn=1, nlinks
796  do k=1, max_levels
797  flag_bfr(nn,k) = .true.
798 
799  if ( depth_bfr(nn,k) > 2000.0 ) depth_bfr(nn,k) = missing_value ! snz add for rdat-hybn
800 
801  if ( var_id == temp_id ) then
802  if ( data_bfr(nn,k) .eq. missing_value .or.&
803  & depth_bfr(nn,k) .eq. missing_value .or.&
804  & t_flag_bfr(nn,k) .ne. 0.0 ) then
805  flag_bfr(nn,k) = .false.
806  else
807  num_levs = num_levs+1
808  end if
809  else if (var_id == salt_id) then
810  if ( data_bfr(nn,k) .eq. missing_value .or.&
811  & depth_bfr(nn,k) .eq. missing_value .or.&
812  & s_flag_bfr(nn,k) .ne. 0.0 ) then
813  flag_bfr(nn,k) = .false.
814  else
815  num_levs = num_levs+1
816  end if
817  end if
818  end do
819  end do
820  end if
821 
822  ! mh2 asks to change from [if (num_levs == 0) cycle]
823  if ( num_levs == 0 ) then
824  if ( i .gt. nstation ) cont = .false.
825  cycle
826  end if
827 
828  if ( num_profiles > 0 .and. prof_in_filt_domain ) then ! snz - 05 Nov 2012
829 
830  allocate(profiles(num_profiles)%depth(num_levs))
831  allocate(profiles(num_profiles)%data(num_levs))
832  allocate(profiles(num_profiles)%flag(num_levs))
833  profiles(num_profiles)%variable = var_id
834  if ( inst_type < 1 ) inst_type = unknown
835  profiles(num_profiles)%inst_type = inst_type
836  profiles(num_profiles)%levels = num_levs
837  profiles(num_profiles)%lat = lat
838  profiles(num_profiles)%lon = lon
839 ! allocate(profiles(num_profiles)%ms(num_levs))
840 ! allocate(profiles(num_profiles)%ms_inv(num_levs))
841 ! profiles(num_profiles)%ms(:) = 0.5
842  kk = 1
843  do k=1, max_levels
844  if ( flag(k) ) then
845  if ( kk > profiles(num_profiles)%levels ) then
846  call error_mesg('oda_core_mod::open_profile_dataset',&
847  & 'Loop value "kk" is greater than profile levels', fatal)
848  end if
849  profiles(num_profiles)%depth(kk) = depth(k)
850  profiles(num_profiles)%data(kk) = data(k)
851 ! profiles(num_profiles)%ms_inv(kk) = 1./profiles(num_profiles)%ms(kk)
852  kk = kk + 1
853  end if
854  end do
855 
856  do nn=1, nlinks
857  do k=1, max_levels
858  if ( flag_bfr(nn,k) ) then
859  if ( kk > profiles(num_profiles)%levels ) then
860  call error_mesg('oda_core_mod::open_profile_dataset',&
861  & 'Loop value "kk" is greater than profile levels (bfr loop)', fatal)
862  end if
863  profiles(num_profiles)%depth(kk) = depth_bfr(nn,k)
864  profiles(num_profiles)%data(kk) = data_bfr(nn,k)
865 ! profiles(num_profiles)%ms_inv(kk) = 1./profiles(num_profiles)%ms(kk)
866  kk = kk + 1
867  end if
868  end do
869  end do
870 
871  profiles(num_profiles)%time = profile_time
872 
873  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
874  if ( lat < 65.0 ) then ! regular grids
875  ri0 = frac_index(lon, x_grid(:,1))
876  rj0 = frac_index(lat, y_grid(90,:))
877  i0 = floor(ri0)
878  j0 = floor(rj0)
879  if ( i0 > ieg .or. j0 > jeg ) then
880  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') mpp_pe(), i0, j0
881  call error_mesg('oda_core_mod::open_profile_dataset',&
882  & 'For regular grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
883  end if
884  if ( isd_filt >= 1 .and. ied_filt <= ieg ) then
885  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
886  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
887  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
888  call error_mesg('oda_core_mod::open_profile_dataset',&
889  & 'i0,j0 out of bounds in prfs01. '//trim(emsg_local), fatal)
890  end if
891  end if
892  if ( isd_filt < 1 .and. i0 > ied_filt-1 .and. i0 < isd_filt + ieg ) then
893  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
894  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
895  call error_mesg('oda_core_mod::open_profile_dataset',&
896  & 'i0,j0 out of bounds in prfs02. '//trim(emsg_local), fatal)
897  end if
898  if ( ied_filt > ieg .and. i0 > ied_filt-ieg-1 .and. ied_filt < isd_filt ) then
899  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
900  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
901  call error_mesg('oda_core_mod::open_profile_dataset',&
902  & 'i0,j0 out of bounds in prfs03. '//trim(emsg_local), fatal)
903  end if
904  profiles(num_profiles)%i_index = ri0
905  profiles(num_profiles)%j_index = rj0
906  else ! tripolar grids
907  lon_out(1,1) = (lon-360.0)*deg_to_rad
908  lat_out(1,1) = lat*deg_to_rad
910  & lon_out, lat_out, new_search=.true., no_crash_when_not_found=.true.)
911 
912  if ( interp%i_lon(1,1,1) == -999. ) bad_point = bad_point + 1
913  if ( interp%wti(1,1,2) < 1.0 ) then
914  i0 = interp%i_lon(1,1,1)
915  else
916  i0 = interp%i_lon(1,1,2)
917  end if
918  if ( interp%wtj(1,1,2) < 1.0 ) then
919  j0 = interp%j_lat(1,1,1)
920  else
921  j0 = interp%j_lat(1,1,2)
922  end if
923  if ( i0 > ieg .or. j0 > jeg ) then
924  write (unit=emsg_local, fmt='("i0 = ",I6,", j0 = ",I6)') mpp_pe(), i0, j0
925  call error_mesg('oda_core_mod::open_profile_dataset',&
926  & 'For tripolar grids, either i0 > ieg or j0 > jeg', fatal)
927  end if
928  if( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
929 !!$ print*,'prfs.pe,i0,j0= ',mpp_pe(), i0, j0,&
930 !!$ & 'isd_filt,ied_filt,jsd_filt,jed_filt= ',isd_filt,ied_filt,jsd_filt,jed_filt
931 !!$ print*,'pe,lon,lat=',mpp_pe(),lon,lat,'x_grid(i0+-1)',x_grid(i0-1:i0+1,j0),&
932 !!$ & 'y_grid(i0,j0+-1)=',y_grid(i0,j0-1:j0+1)
933 !!$ print*,'lono11,lato11=',x_grid(i0,j0),y_grid(i0,j0),'lono21,lato21=',x_grid(i0+1,j0),y_grid(i0+1,j0)
934 !!$ print*,'lono12,lato12=',x_grid(i0,j0+1),y_grid(i0,j0+1),'lono22,lato22=',x_grid(i0+1,j0+1),y_grid(i0+1,j0+1)
935 !!$ print*,'lonm11,latm11=',x_grid(isd_filt,jsd_filt),y_grid(isd_filt,jsd_filt),&
936 !!$ & 'lonm21,latm21=',x_grid(ied_filt,jsd_filt),y_grid(ied_filt,jsd_filt)
937 !!$ print*,'lonm12,latm12=',x_grid(isd_filt,jed_filt),y_grid(isd_filt,jed_filt),&
938 !!$ & 'lonm22,latm22=',x_grid(ied_filt,jed_filt),y_grid(ied_filt,jed_filt)
939 !!$ print*,'wti(1:2)=',Interp%wti(1,1,:),'wtj(1:2)=',Interp%wtj(1,1,:)
940 
941  out_bound_point = out_bound_point + 1
942  end if
943  if ( interp%wti(1,1,2) < 1.0 ) then
944  profiles(num_profiles)%i_index =interp%i_lon(1,1,1) + interp%wti(1,1,2)
945  else
946  profiles(num_profiles)%i_index =interp%i_lon(1,1,2)
947  end if
948  if (interp%wtj(1,1,2) < 1.0) then
949  profiles(num_profiles)%j_index =interp%j_lat(1,1,1) + interp%wtj(1,1,2)
950  else
951  profiles(num_profiles)%j_index =interp%j_lat(1,1,2)
952  end if
953  end if ! grids
954 
955  profiles(num_profiles)%accepted = .true.
956 
957  if ( var_id == temp_id .and. flag_t /= 0.0 ) profiles(num_profiles)%accepted = .false.
958  if ( var_id == salt_id .and. flag_s /= 0.0 ) profiles(num_profiles)%accepted = .false.
959 
960  if (i0 < 1 .or. j0 < 1) then
961  profiles(num_profiles)%accepted = .false.
962  end if
963  if( i0 < isd_filt .or. i0 >= ied_filt .or. j0 < jsd_filt .or. j0 >= jed_filt ) then
964  profiles(num_profiles)%accepted = .false.
965  end if
966 
967  if ( profiles(num_profiles)%accepted ) then ! here
968  if ( i0 /= ieg .and. j0 /= jeg ) then
969  if (grd%mask(i0,j0,1) == 0.0 .or.&
970  & grd%mask(i0+1,j0,1) == 0.0 .or.&
971  & grd%mask(i0,j0+1,1) == 0.0 .or.&
972  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
973  profiles(num_profiles)%accepted = .false.
974  end if
975  else if ( i0 == ieg .and. j0 /= jeg ) then
976  if (grd%mask(i0,j0,1) == 0.0 .or.&
977  & grd%mask(1,j0,1) == 0.0 .or.&
978  & grd%mask(i0,j0+1,1) == 0.0 .or.&
979  & grd%mask(1,j0+1,1) == 0.0 ) then
980  profiles(num_profiles)%accepted = .false.
981  end if
982  else if ( i0 /= ieg .and. j0 == jeg ) then
983  if ( grd%mask(i0,j0,1) == 0.0 .or. grd%mask(i0+1,j0,1) == 0.0 ) then
984  profiles(num_profiles)%accepted = .false.
985  end if
986  else
987  if ( grd%mask(i0,j0,1) == 0.0 ) then
988  profiles(num_profiles)%accepted = .false.
989  end if
990  end if
991  end if ! here
992 
993  if ( profiles(num_profiles)%accepted .and.&
994  & profiles(num_profiles)%inst_type == mooring+tao ) then
995  if ( allocated(mask_tao) ) then
996  if ( mask_tao(i0,j0) < 1.0 ) then
997  profiles(num_profiles)%accepted = .false.
998  write (unit=stdout_unit,&
999  & fmt='("Rejecting tao mooring at (lat,lon) = (",F10.5,",",F10.5,") based on user-specified mask.")')&
1000  & profiles(num_profiles)%lat,&
1001  & profiles(num_profiles)%lon
1002  end if
1003  end if
1004  end if
1005 
1006  if ( profiles(num_profiles)%accepted ) then ! accepted
1007  profiles(num_profiles)%flag(:) = .true.
1008  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
1009  do k=1, profiles(num_profiles)%levels
1010  if (profiles(num_profiles)%depth(k) < grd%z(1)) then
1011  profiles(num_profiles)%k_index(k) = 1.0
1012  else
1013  profiles(num_profiles)%k_index(k) = frac_index(profiles(num_profiles)%depth(k), (/0.,grd%z(:)/))! - 1 snz modify to v3.2 JAN3012
1014  end if
1015  if ( profiles(num_profiles)%k_index(k) < 1.0 ) then
1016  if ( profiles(num_profiles)%depth(k) < 0.0 ) then
1017  profiles(num_profiles)%k_index(k) = 0.0
1018  else if ( profiles(num_profiles)%depth(k) > grd%z(size(grd%z,1)) ) then
1019  profiles(num_profiles)%k_index(k) = real(nk)
1020  end if
1021  else
1022  profiles(num_profiles)%k_index(k) = profiles(num_profiles)%k_index(k) - 1.0
1023  end if
1024  if ( profiles(num_profiles)%k_index(k) > real(nk) ) then
1025  call error_mesg('oda_core_mod::open_profile_dataset', 'Profile k_index is greater than nk', fatal)
1026  else if ( profiles(num_profiles)%k_index(k) < 0.0 ) then
1027  call error_mesg('oda_core_mod::open_profile_dataset', 'Profile k_index is less than 0', fatal)
1028  end if
1029  k0 = floor(profiles(num_profiles)%k_index(k))
1030 
1031  IF ( k0 >= 1 ) THEN ! snz add
1032  if ( profiles(num_profiles)%flag(k) ) then ! flag
1033  if ( i0 /= ieg .and. j0 /= jeg ) then
1034  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1035  & grd%mask(i0+1,j0,k0) == 0.0 .or.&
1036  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
1037  & grd%mask(i0+1,j0+1,k0) == 0.0 ) then
1038  profiles(num_profiles)%flag(k) = .false.
1039  end if
1040  else if ( i0 == ieg .and. j0 /= jeg ) then
1041  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1042  & grd%mask(1,j0,k0) == 0.0 .or.&
1043  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
1044  & grd%mask(1,j0+1,k0) == 0.0) then
1045  profiles(num_profiles)%flag(k) = .false.
1046  end if
1047  else if ( i0 /= ieg .and. j0 == jeg ) then
1048  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1049  & grd%mask(i0+1,j0,k0) == 0.0) then
1050  profiles(num_profiles)%flag(k) = .false.
1051  end if
1052  else
1053  if ( grd%mask(i0,j0,k0) == 0.0 ) then
1054  profiles(num_profiles)%flag(k) = .false.
1055  end if
1056  end if
1057 
1058  if ( i0 /= ieg .and. j0 /= jeg) then
1059  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1060  & grd%mask(i0+1,j0,k0+1) == 0.0 .or.&
1061  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
1062  & grd%mask(i0+1,j0+1,k0+1) == 0.0 ) then
1063  profiles(num_profiles)%flag(k) = .false.
1064  end if
1065  else if ( i0 == ieg .and. j0 /= jeg ) then
1066  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1067  & grd%mask(1,j0,k0+1) == 0.0 .or.&
1068  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
1069  & grd%mask(1,j0+1,k0+1) == 0.0) then
1070  profiles(num_profiles)%flag(k) = .false.
1071  end if
1072  else if ( i0 /= ieg .and. j0 == jeg ) then
1073  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1074  & grd%mask(i0+1,j0,k0+1) == 0.0) then
1075  profiles(num_profiles)%flag(k) = .false.
1076  end if
1077  else
1078  if ( grd%mask(i0,j0,k0+1) == 0.0 ) then
1079  profiles(num_profiles)%flag(k) = .false.
1080  end if
1081  end if
1082 
1083  if ( abs(profiles(num_profiles)%data(k)) > 1.e4 &
1084  & .or. abs(profiles(num_profiles)%depth(k)) > 1.e4 ) then
1085  profiles(num_profiles)%flag(k) = .false.
1086  end if
1087  end if ! flag
1088  end if ! snz add
1089  end do
1090  end if ! accepted
1091  endif ! 05 Nov 2012
1092  else ! localize
1093  i = i+1
1094  end if ! localize
1095 
1096  if ( var_id == temp_id .and. num_profiles > 0 ) call xbt_drop_rate_adjust(profiles(num_profiles))
1097 
1098  if ( i .gt. nstation ) cont = .false.
1099  end do
1100 
1101  a = nprof_in_filt_domain
1102  bad_point_g = bad_point
1103  call mpp_sum(a)
1104  call mpp_sum(bad_point_g)
1105  call mpp_sum(out_bound_point)
1106 
1107  if ( no_prf /= num_profiles ) then
1108  write(unit=stdout_unit, fmt='("PE: ",I6," no_prf = ",I8,", num_profiles = ",I8)') mpp_pe(), no_prf, num_profiles
1109  end if
1110  if ( var_id == temp_id ) then
1111  write(unit=stdout_unit, fmt='("A grand total of ",I8," temp prfs within global domain")') no_temp
1112  write(unit=stdout_unit, fmt='("The total of bad_point temp ",I8," within global domain")') bad_point_g
1113  write(unit=stdout_unit, fmt='("The total out_bound_point temp ",I8)') out_bound_point
1114  else if ( var_id == salt_id ) then
1115  write(unit=stdout_unit, fmt='("A grand total of ",I8," salt prfs within global domain")') no_salt
1116  write(unit=stdout_unit, fmt='("The total of bad_point salt",I8," within global domain")') bad_point_g
1117  write(unit=stdout_unit, fmt='("A grand total of ",I8," prfs within global domain")') no_prf
1118  write(unit=stdout_unit, fmt='("A grand total of ",I8," prfs within current PEs computer domain")') a
1119  write(unit=stdout_unit, fmt='("The total out_bound_point salt ",I8)') out_bound_point
1120  end if
1121 
1122  call mpp_sync_self()
1123  call mpp_close(unit)
1124  deallocate(axes)
1125  deallocate(fields)
1126 
1127 ! call mpp_print_memuse_stats('open_profile_dataset End')
1128 
1129  end subroutine open_profile_dataset
1130 
1131  subroutine open_profile_dataset_gtspp()
1132  return
1133  end subroutine open_profile_dataset_gtspp
1134 
1135  subroutine open_profile_dataset_argo(filename, time_start, time_end, obs_variable, localize)
1136  character(len=*), intent(in) :: filename
1137  type(time_type), intent(in) :: time_start, time_end
1138  integer, intent(in) :: obs_variable
1139  logical, intent(in), optional :: localize
1140 
1141  integer, parameter :: MAX_LEVELS = 1000
1142  integer, parameter :: MAX_LNKS = 500
1143 
1144  real :: lon, lat, time, rlink, prf_type
1145  real :: ri0, rj0
1146  real, dimension(MAX_LEVELS) :: depth, data
1147  real, dimension(MAX_LNKS, MAX_LEVELS) :: data_bfr, depth_bfr
1148 
1149  integer :: unit, ndim, nvar, natt, nstation
1150  integer :: stdout_unit
1151  integer :: inst_type, var_id
1152  integer :: num_levs, k, kk, i, i0, j0, k0, nlevs, a, nn, ii, nlinks
1153  integer :: nprof_in_filt_domain, out_bound_point
1154 
1155  character(len=32) :: fldname, axisname, anal_fldname, time_units
1156  character(len=128) :: emsg_local
1157 
1158  logical :: data_is_local, localize_data, cont
1159  logical :: data_in_period
1160  logical :: prof_in_filt_domain
1161  logical, dimension(MAX_LEVELS) :: flag
1162  logical, dimension(MAX_LNKS, MAX_LEVELS) :: flag_bfr
1163 
1164  type(time_type) :: profile_time
1165  type(axistype), pointer :: depth_axis, station_axis
1166  type(axistype), allocatable, dimension(:), target :: axes
1167  type(fieldtype), allocatable, dimension(:), target :: fields
1168  type(fieldtype), pointer :: field_lon, field_lat, field_flag, field_time
1169  type(fieldtype), pointer :: field_depth, field_data, field_link, field_var_type
1170 
1171  ! NOTE: fields are restricted to be in separate files
1172 
1173  stdout_unit = stdout()
1174 
1175  if ( PRESENT(localize) ) then
1176  localize_data = localize
1177  else
1178  localize_data = .true.
1179  end if
1180 
1181  nprof_in_filt_domain = 0
1182 
1183  anal_fldname = 'none'
1184  var_id=-1
1185  if ( obs_variable == temp_id ) then
1186  anal_fldname = 'temp'
1187  var_id = temp_id
1188  else if ( obs_variable == salt_id ) then
1189  anal_fldname = 'salt'
1190  var_id = salt_id
1191  end if
1192 
1193 ! call mpp_print_memuse_stats('open_profile_dataset_argo Start')
1194 
1195  call mpp_open(unit, filename, form=mpp_netcdf, fileset=mpp_single, threading=mpp_multi, action=mpp_rdonly)
1196  call mpp_get_info(unit, ndim, nvar, natt, nstation)
1197 
1198  write (unit=stdout_unit, fmt='("Opened profile dataset: ",A)') trim(filename)
1199 
1200  ! get axis information
1201 
1202  allocate(axes(ndim))
1203  call mpp_get_axes(unit, axes)
1204  do i=1, ndim
1205  call mpp_get_atts(axes(i), name=axisname)
1206  select case (trim(axisname))
1207  case ('depth_index')
1208  depth_axis => axes(i)
1209  case ('station_index')
1210  station_axis => axes(i)
1211  end select
1212  end do
1213 
1214  ! get field information
1215  allocate(fields(nvar))
1216  call mpp_get_fields(unit, fields)
1217  do i=1, nvar
1218  call mpp_get_atts(fields(i), name=fldname)
1219  if( var_id .eq. temp_id ) then
1220  select case (trim(fldname))
1221  case ('longitude')
1222  field_lon => fields(i)
1223  case ('latitude')
1224  field_lat => fields(i)
1225  case ('dens_flag')
1226  field_flag => fields(i)
1227  case ('time')
1228  field_time => fields(i)
1229  case ('temp')
1230  field_data => fields(i)
1231  case ('depth')
1232  field_depth => fields(i)
1233  case ('link')
1234  field_link => fields(i)
1235  case ('var_type')
1236  field_var_type => fields(i)
1237  end select
1238  else if( var_id .eq. salt_id ) then
1239  select case (trim(fldname))
1240  case ('longitude')
1241  field_lon => fields(i)
1242  case ('latitude')
1243  field_lat => fields(i)
1244  case ('dens_flag')
1245  field_flag => fields(i)
1246  case ('time')
1247  field_time => fields(i)
1248  case ('salt')
1249  field_data => fields(i)
1250  case ('depth')
1251  field_depth => fields(i)
1252  case ('link')
1253  field_link => fields(i)
1254  case ('var_type')
1255  field_var_type => fields(i)
1256  end select
1257  end if
1258  end do
1259 
1260  call mpp_get_atts(depth_axis, len=nlevs)
1261 
1262  if ( nlevs > max_levels ) then
1263  call error_mesg('oda_core_mod::open_profile_dataset_argo', 'increase parameter MAX_LEVELS', fatal)
1264  else if (nlevs < 1) then
1265  call error_mesg('oda_core_mod::open_profile_dataset_argo', 'nlevs less than 1.', fatal)
1266  end if
1267 
1268  if ( .NOT.ASSOCIATED(field_data) ) then
1269  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1270  & 'profile dataset not used because data not needed for Analysis', note)
1271  return
1272  end if
1273 
1274  write (unit=stdout_unit, fmt='("There are ",I8," records in this dataset")') nstation
1275  write (unit=stdout_unit, fmt='("Searching for profiles . . .")')
1276 
1277  call mpp_get_atts(field_time, units=time_units)
1278 
1279  out_bound_point = 0
1280 
1281  i=1
1282  cont=.true.
1283 
1284  do while (cont)
1285  prof_in_filt_domain = .false.
1286  depth = missing_value ! snz add
1287  data = missing_value ! snz add
1288 
1289  call mpp_read(unit, field_lon, lon, tindex=i)
1290  call mpp_read(unit, field_lat, lat, tindex=i)
1291  call mpp_read(unit, field_time, time, tindex=i)
1292  call mpp_read(unit, field_depth, depth(1:nlevs), tindex=i)
1293  call mpp_read(unit, field_data, data(1:nlevs), tindex=i)
1294  call mpp_read(unit, field_var_type, prf_type, tindex=i)
1295  call mpp_read(unit, field_link, rlink, tindex=i)
1296 
1297 !!$ inst_type = DRIFTER + ARGO
1298  inst_type = 20 ! snz change one line
1299  data_is_local = .false.
1300  data_in_period = .false.
1301 
1302  if ( lon .lt. 0.0 ) lon = lon + 360.0
1303  if ( lon .gt. 360.0 ) lon = lon - 360.0
1304  if ( lon .lt. 80.0 ) lon = lon + 360.0
1305 
1306  if ( lat > ass_start_lat .and. lat < ass_end_lat ) data_is_local = .true.
1307 
1308  profile_time = get_cal_time(time, time_units, 'NOLEAP')
1309  if ( profile_time > time_start .and. profile_time < time_end ) data_in_period = .true.
1310  if ( (data_in_period .and. data_is_local) .and. (.NOT.localize_data) ) then
1311 
1312  if (isd_filt < 1 .and. ied_filt > ieg) then
1313  ! filter domain is a full x band
1314  if (lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
1315  lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ieg-1,jsd_flt0)) then
1316  prof_in_filt_domain = .true.
1317  end if
1318  else if (isd_filt >= 1 .and. ied_filt <= ieg) then
1319  ! Interior filter domain
1320  if (lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
1321  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)) then
1322  prof_in_filt_domain = .true.
1323  end if
1324  else if (isd_filt < 1 .and. ied_filt <= ieg) then
1325  ! lhs filter domain
1326  isd_flt0 = isd_filt + ieg
1327  if ((lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
1328  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)).or.&
1329  & (lon >= x_grid(isd_flt0,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
1330  & lat >= y_grid(isd_flt0,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1))) then
1331  prof_in_filt_domain = .true.
1332  end if
1333  else if (isd_filt >= 1 .and. ied_filt > ieg) then
1334  ! rhs filter domain
1335  ied_flt0 = ied_filt - ieg
1336  if ( lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
1337  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1) ) then
1338  prof_in_filt_domain = .true.
1339  end if
1340  if (ied_flt0-1 > 1) then
1341  if ( lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_flt0-1,jsd_flt0) .and.&
1342  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_flt0-1,jed_flt0-1) ) then
1343  prof_in_filt_domain = .true.
1344  end if
1345  end if
1346  end if
1347 
1348  if ( var_id == temp_id ) then
1350  no_temp = no_temp + 1
1351  no_prf = no_prf + 1
1352  else if ( var_id == salt_id .and. prf_type == 2.0 ) then
1354  no_salt = no_salt + 1
1355  no_prf = no_prf + 1
1356  end if
1357 
1358  if ( num_profiles > max_profiles ) then
1359  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1360  & 'maximum number of profiles exceeded, increase max_profiles in oda_core_nml', fatal)
1361  end if
1362 
1363  num_levs = 0
1364  do k=1, max_levels
1365  flag(k) = .true.
1366  if ( depth(k) > 2000.0 ) depth(k) = missing_value ! snz add for rdat-hybn
1367  if ( var_id == temp_id ) then
1368  if ( data(k) .eq. missing_value .or. depth(k) .eq. missing_value ) then
1369  flag(k) = .false.
1370  else
1371  num_levs = num_levs+1
1372  end if
1373  else if ( var_id == salt_id ) then
1374  if ( data(k) .eq. missing_value .or. depth(k) .eq. missing_value ) then
1375  flag(k) = .false.
1376  else
1377  num_levs = num_levs+1
1378  end if
1379  end if
1380  end do
1381 
1382  ! large profile are stored externally in separate records
1383  ! read linked records and combine profile
1384  ii=i+1
1385  nlinks = 0
1386  do while ( rlink > 0.0 )
1387  nlinks = nlinks + 1
1388 
1389  if ( nlinks > max_lnks ) then
1390  write (emsg_local, '("nlinks (",I6,") > MAX_LNKS (",I6,")")')&
1391  & nlinks, max_lnks
1392  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1393  & trim(emsg_local)//' in file "'//trim(filename)//&
1394  & '". Increase parameter MAX_LNKS', fatal)
1395  end if
1396 
1397  depth_bfr(nlinks,:) = missing_value
1398  data_bfr(nlinks,:) = missing_value
1399  call mpp_read(unit,field_depth,depth_bfr(nlinks,1:nlevs),tindex=ii)
1400  call mpp_read(unit,field_data,data_bfr(nlinks,1:nlevs),tindex=ii)
1401  call mpp_read(unit,field_link,rlink,tindex=ii)
1402  ii=ii+1
1403  end do
1404  i=ii ! set record counter to start of next profile
1405 
1406  if ( nlinks > 0 ) then
1407  do nn=1, nlinks
1408  do k=1, max_levels
1409  flag_bfr(nn,k) = .true.
1410 
1411  if ( depth_bfr(nn,k) > 2000.0 ) depth_bfr(nn,k) = missing_value ! snz add for rdat-hybn
1412 
1413  if ( var_id == temp_id ) then
1414  if ( data_bfr(nn,k) .eq. missing_value .or. depth_bfr(nn,k) .eq. missing_value ) then
1415  flag_bfr(nn,k) = .false.
1416  else
1417  num_levs = num_levs+1
1418  end if
1419  else if ( var_id == salt_id ) then
1420  if ( data_bfr(nn,k) .eq. missing_value .or. depth_bfr(nn,k) .eq. missing_value ) then
1421  flag_bfr(nn,k) = .false.
1422  else
1423  num_levs = num_levs+1
1424  end if
1425  end if
1426  end do
1427  end do
1428  end if
1429 
1430  ! mh2 asks to change from [if (num_levs == 0) cycle]
1431  if ( num_levs == 0 ) then
1432  if ( i .gt. nstation ) cont = .false.
1433  cycle
1434  end if
1435 
1436  if (nprof_in_filt_domain > 0 .and. prof_in_filt_domain) then ! snz 05 Nov 2012
1437 
1438  allocate(profiles(num_profiles)%depth(num_levs))
1439  allocate(profiles(num_profiles)%data(num_levs))
1440  allocate(profiles(num_profiles)%flag(num_levs))
1441  profiles(num_profiles)%variable = var_id
1442  if ( inst_type < 1 ) inst_type = unknown
1443  profiles(num_profiles)%inst_type = inst_type
1444  profiles(num_profiles)%levels = num_levs
1445  profiles(num_profiles)%lat = lat
1446  profiles(num_profiles)%lon = lon
1447 ! allocate(profiles(num_profiles)%ms(num_levs))
1448 ! allocate(profiles(num_profiles)%ms_inv(num_levs))
1449 ! profiles(num_profiles)%ms(:) = 0.5
1450 
1451  kk= 1
1452  do k=1, max_levels
1453  if ( flag(k) ) then
1454  if ( kk > profiles(num_profiles)%levels ) then
1455  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1456  & 'Loop variable "kk" is greater than profile levels', fatal)
1457  end if
1458  profiles(num_profiles)%depth(kk) = depth(k)
1459  profiles(num_profiles)%data(kk) = data(k)
1460 ! profiles(num_profiles)%ms_inv(kk) = 1./profiles(num_profiles)%ms(kk)
1461  kk = kk + 1
1462  end if
1463  end do
1464 
1465  do nn=1, nlinks
1466  do k=1, max_levels
1467  if ( flag_bfr(nn,k) ) then
1468  if ( kk > profiles(num_profiles)%levels ) then
1469  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1470  & 'Loop variable "kk" is greater than profile levels (bfr loop)', fatal)
1471  end if
1472  profiles(num_profiles)%depth(kk) = depth_bfr(nn,k)
1473  profiles(num_profiles)%data(kk) = data_bfr(nn,k)
1474 ! profiles(num_profiles)%ms_inv(kk) = 1./profiles(num_profiles)%ms(kk)
1475  kk = kk + 1
1476  end if
1477  end do
1478  end do
1479 
1480  profiles(num_profiles)%time = profile_time
1481 
1482 ! snz uses the following to test excluding the coast area salt profiles
1483 ! if (profiles(num_profiles)%variable == SALT_ID .and. &
1484 ! profiles(num_profiles)%depth(num_levs) < 900.0) profiles(num_profiles)%accepted = .false.
1485 
1486  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
1487  ! note that this only works for lat/lon grids
1488  if ( lat < 65.0 ) then ! regular grids
1489  ri0 = frac_index(lon, x_grid(:,1))
1490  rj0 = frac_index(lat, y_grid(90,:))
1491  i0 = floor(ri0)
1492  j0 = floor(rj0)
1493  if ( i0 > ieg .or. j0 > jeg ) then
1494  write (unit=emsg_local, fmt='("i0 = ",I6,", j0 = ",I6)') mpp_pe(), i0, j0
1495  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1496  & 'For regular grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
1497  end if
1498  if ( isd_filt >= 1 .and. ied_filt <= ieg ) then
1499  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
1500  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1501  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
1502  call error_mesg('oda_core_mod::open_profile_dataset',&
1503  & 'i0,j0 out of bounds in argo01. '//trim(emsg_local), fatal)
1504  end if
1505  end if
1506  if ( isd_filt < 1 .and. i0 > ied_filt-1 .and. i0 < isd_filt + ieg ) then
1507  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1508  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
1509  call error_mesg('oda_core_mod::open_profile_dataset',&
1510  & 'i0,j0 out of bounds in argo02. '//trim(emsg_local), fatal)
1511  end if
1512  if ( ied_filt > ieg .and. i0 > ied_filt-ieg-1 .and. ied_filt < isd_filt ) then
1513  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1514  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
1515  call error_mesg('oda_core_mod::open_profile_dataset',&
1516  & 'i0,j0 out of bounds in argo03. '//trim(emsg_local), fatal)
1517  end if
1518  profiles(num_profiles)%i_index = ri0
1519  profiles(num_profiles)%j_index = rj0
1520  else ! tripolar grids
1521  lon_out(1,1) = lon*deg_to_rad
1522  lat_out(1,1) = lat*deg_to_rad
1524  if(interp%wti(1,1,2) < 1.0) then
1525  i0 = interp%i_lon(1,1,1)
1526  else
1527  i0 = interp%i_lon(1,1,2)
1528  end if
1529  if ( interp%wtj(1,1,2) < 1.0 ) then
1530  j0 = interp%j_lat(1,1,1)
1531  else
1532  j0 = interp%j_lat(1,1,2)
1533  end if
1534  if ( i0 > ieg .or. j0 > jeg ) then
1535  write (unit=emsg_local, fmt='("i0 = ",I6,", j0 = ",I6)') mpp_pe(), i0, j0
1536  call error_mesg('oda_core_mod::open_profile_dataset_argo',&
1537  & 'For tirpolar grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
1538  end if
1539  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
1540 !!$ print*,'argo.pe,i0,j0= ',mpp_pe(), i0, j0,&
1541 !!$ & 'isd_filt,ied_filt,jsd_filt,jed_filt= ',isd_filt,ied_filt,jsd_filt,jed_filt
1542 !!$ print*,'pe,lon,lat=',mpp_pe(),lon,lat,'x_grid(i0+-1)',x_grid(i0-1:i0+1,j0),&
1543 !!$ & 'y_grid(i0,j0+-1)=',y_grid(i0,j0-1:j0+1)
1544 !!$ print*,'lono11,lato11=',x_grid(i0,j0),y_grid(i0,j0),'lono21,lato21=',x_grid(i0+1,j0),y_grid(i0+1,j0)
1545 !!$ print*,'lono12,lato12=',x_grid(i0,j0+1),y_grid(i0,j0+1),'lono22,lato22=',x_grid(i0+1,j0+1),y_grid(i0+1,j0+1)
1546 !!$ print*,'lonm11,latm11=',x_grid(isd_filt,jsd_filt),y_grid(isd_filt,jsd_filt),&
1547 !!$ & 'lonm21,latm21=',x_grid(ied_filt,jsd_filt),y_grid(ied_filt,jsd_filt)
1548 !!$ print*,'lonm12,latm12=',x_grid(isd_filt,jed_filt),y_grid(isd_filt,jed_filt),&
1549 !!$ & 'lonm22,latm22=',x_grid(ied_filt,jed_filt),y_grid(ied_filt,jed_filt)
1550 !!$ print*,'wti(1:2)=',Interp%wti(1,1,:),'wtj(1:2)=',Interp%wtj(1,1,:)
1551 
1552  out_bound_point = out_bound_point + 1
1553  end if
1554  if ( interp%wti(1,1,2) < 1.0 ) then
1555  profiles(num_profiles)%i_index =interp%i_lon(1,1,1) + interp%wti(1,1,2)
1556  else
1557  profiles(num_profiles)%i_index =interp%i_lon(1,1,2)
1558  end if
1559  if ( interp%wtj(1,1,2) < 1.0 ) then
1560  profiles(num_profiles)%j_index =interp%j_lat(1,1,1) + interp%wtj(1,1,2)
1561  else
1562  profiles(num_profiles)%j_index =interp%j_lat(1,1,2)
1563  end if
1564  end if ! grids
1565 
1566  profiles(num_profiles)%accepted = .true.
1567  if ( i0 < 1 .or. j0 < 1 ) then
1568  profiles(num_profiles)%accepted = .false.
1569  end if
1570  if ( i0 < isd_filt .or. i0 >= ied_filt .or. j0 < jsd_filt .or. j0 >= jed_filt ) then
1571  profiles(num_profiles)%accepted = .false.
1572  end if
1573 
1574  if ( profiles(num_profiles)%accepted ) then ! here
1575  if ( i0 /= ieg .and. j0 /= jeg ) then
1576  if ( grd%mask(i0,j0,1) == 0.0 .or.&
1577  & grd%mask(i0+1,j0,1) == 0.0 .or.&
1578  & grd%mask(i0,j0+1,1) == 0.0 .or.&
1579  & grd%mask(i0+1,j0+1,1) == 0.0) then
1580  profiles(num_profiles)%accepted = .false.
1581  end if
1582  else if ( i0 == ieg .and. j0 /= jeg ) then
1583  if (grd%mask(i0,j0,1) == 0.0 .or.&
1584  & grd%mask(1,j0,1) == 0.0 .or.&
1585  & grd%mask(i0,j0+1,1) == 0.0 .or.&
1586  & grd%mask(1,j0+1,1) == 0.0) then
1587  profiles(num_profiles)%accepted = .false.
1588  end if
1589  else if ( i0 /= ieg .and. j0 == jeg ) then
1590  if (grd%mask(i0,j0,1) == 0.0 .or.&
1591  & grd%mask(i0+1,j0,1) == 0.0) then
1592  profiles(num_profiles)%accepted = .false.
1593  end if
1594  else
1595  if ( grd%mask(i0,j0,1) == 0.0 ) then
1596  profiles(num_profiles)%accepted = .false.
1597  end if
1598  end if
1599  end if ! here
1600 
1601  if ( profiles(num_profiles)%accepted .and. profiles(num_profiles)%inst_type == mooring+tao) then
1602  if ( allocated(mask_tao) ) then
1603  if ( mask_tao(i0,j0) < 1.0 ) then
1604  profiles(num_profiles)%accepted = .false.
1605  write (unit=stdout_unit,&
1606  & fmt='("Rejecting tao mooring at (lat,lon) = (",F10.5,",",F10.5,") based on user-specified mask.")')&
1607  & profiles(num_profiles)%lat,&
1608  & profiles(num_profiles)%lon
1609  end if
1610  end if
1611  end if
1612 
1613  if ( profiles(num_profiles)%accepted ) then
1614  profiles(num_profiles)%flag(:) = .true.
1615  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
1616  do k=1, profiles(num_profiles)%levels
1617  if (profiles(num_profiles)%depth(k) < grd%z(1)) then
1618  profiles(num_profiles)%k_index(k) = 1.0
1619  else
1620  profiles(num_profiles)%k_index(k) = frac_index(profiles(num_profiles)%depth(k), (/0.,grd%z(:)/))! - 1 snz modify to v3.2 JAN3012
1621  end if
1622  if ( profiles(num_profiles)%k_index(k) < 1 ) then
1623  if ( profiles(num_profiles)%depth(k) < 0 ) then
1624  profiles(num_profiles)%k_index(k) = 0
1625  else if ( profiles(num_profiles)%depth(k) > grd%z(size(grd%z,1)) ) then
1626  profiles(num_profiles)%k_index(k) = nk
1627  end if
1628  else
1629  profiles(num_profiles)%k_index(k) = profiles(num_profiles)%k_index(k) - 1
1630  end if
1631  if ( profiles(num_profiles)%k_index(k) > nk ) then
1632  call error_mesg('oda_core_mod::open_profile_dataset_argo', 'Profile k_index is greater than nk', fatal)
1633  else if ( profiles(num_profiles)%k_index(k) < 0 ) then
1634  call error_mesg('oda_core_mod::open_profile_dataset_argo', 'Profile k_index is less than 0', fatal)
1635  end if
1636  k0 = floor(profiles(num_profiles)%k_index(k))
1637 
1638  if ( k0 >= 1 ) then ! snz add
1639  if ( profiles(num_profiles)%flag(k) ) then ! flag
1640  if ( i0 /= ieg .and. j0 /= jeg ) then
1641  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1642  & grd%mask(i0+1,j0,k0) == 0.0 .or.&
1643  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
1644  & grd%mask(i0+1,j0+1,k0) == 0.0 ) then
1645  profiles(num_profiles)%flag(k) = .false.
1646  end if
1647  else if ( i0 == ieg .and. j0 /= jeg ) then
1648  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1649  & grd%mask(1,j0,k0) == 0.0 .or.&
1650  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
1651  & grd%mask(1,j0+1,k0) == 0.0 ) then
1652  profiles(num_profiles)%flag(k) = .false.
1653  end if
1654  else if ( i0 /= ieg .and. j0 == jeg ) then
1655  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
1656  & grd%mask(i0+1,j0,k0) == 0.0 ) then
1657  profiles(num_profiles)%flag(k) = .false.
1658  end if
1659  else
1660  if ( grd%mask(i0,j0,k0) == 0.0 ) then
1661  profiles(num_profiles)%flag(k) = .false.
1662  end if
1663  end if
1664 
1665  if ( i0 /= ieg .and. j0 /= jeg ) then
1666  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1667  & grd%mask(i0+1,j0,k0+1) == 0.0 .or.&
1668  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
1669  & grd%mask(i0+1,j0+1,k0+1) == 0.0 ) then
1670  profiles(num_profiles)%flag(k) = .false.
1671  end if
1672  else if ( i0 == ieg .and. j0 /= jeg ) then
1673  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1674  & grd%mask(1,j0,k0+1) == 0.0 .or.&
1675  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
1676  & grd%mask(1,j0+1,k0+1) == 0.0) then
1677  profiles(num_profiles)%flag(k) = .false.
1678  end if
1679  else if ( i0 /= ieg .and. j0 == jeg ) then
1680  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
1681  & grd%mask(i0+1,j0,k0+1) == 0.0 ) then
1682  profiles(num_profiles)%flag(k) = .false.
1683  end if
1684  else
1685  if ( grd%mask(i0,j0,k0+1) == 0.0 ) then
1686  profiles(num_profiles)%flag(k) = .false.
1687  end if
1688  end if
1689 
1690  if ( abs(profiles(num_profiles)%data(k)) > 1.e4 &
1691  & .or. abs(profiles(num_profiles)%depth(k)) > 1.e4 ) then
1692  profiles(num_profiles)%flag(k) = .false.
1693  end if
1694  end if ! flag
1695  end if ! snz add
1696  end do
1697  end if ! accepted
1698 
1699  end if ! 05 Nov 2012
1700 
1701  else ! localize
1702  i = i+1
1703  end if ! localize
1704 
1705  if ( i .gt. nstation ) cont = .false.
1706  end do
1707 
1708  a = nprof_in_filt_domain
1709  call mpp_sum(a)
1710  call mpp_sum(out_bound_point)
1711 
1712  if ( no_prf /= num_profiles ) then
1713  write(unit=stdout_unit, fmt='("PE: ",I6," no_prf = ",I8,", num_profiles = ",I8)') mpp_pe(), no_prf, num_profiles
1714  end if
1715  if ( var_id == temp_id ) then
1716  write(unit=stdout_unit, fmt='("A grand total of ",I8," argo temp prfs within global domain")') no_temp
1717  write(unit=stdout_unit, fmt='("A total out of bound points",I8," argo temp within global domain")') out_bound_point
1718  else if ( var_id == salt_id ) then
1719  write(unit=stdout_unit, fmt='("A grand total of ",I8," argo salt prfs within global domain")') no_salt
1720  write(unit=stdout_unit, fmt='("A grand total of ",I8," argo prfs within global domain")') no_prf
1721  write(unit=stdout_unit, fmt='("A grand total of ",I8," argo prfs within current PEs computer domain")') a
1722  write(unit=stdout_unit, fmt='("A total out of bound points",I8," argo salt within global domain")') out_bound_point
1723  end if
1724 
1725  call mpp_sync_self()
1726  call mpp_close(unit)
1727  deallocate(axes)
1728  deallocate(fields)
1729 
1730 ! call mpp_print_memuse_stats('open_profile_dataset_argo End')
1731 
1732  end subroutine open_profile_dataset_argo
1733 
1734  ! get profiles and sfc
1735  ! obs relevant to current analysis interval
1736  subroutine get_obs(model_time, Prof, nprof)
1737  type(time_type), intent(in) :: model_time
1738  type(ocean_profile_type), dimension(:), intent(inout) :: prof
1739  integer, intent(inout) :: nprof
1740 
1741  integer :: i, k, kk, k_interval
1742  integer :: yr, mon, day, hr, min, sec
1743  integer :: stdout_unit
1744 
1745  type(time_type) :: tdiff
1746 
1747  nprof = 0
1748  stdout_unit = stdout()
1749 
1750  write (unit=stdout_unit, fmt='("Gathering profiles for current analysis time")')
1751  call get_date(model_time, yr, mon, day, hr, min, sec)
1752  write (unit=stdout_unit, fmt='("Current YYYY/MM/DD = ",I4,"/",I2,"/",I2)') yr, mon, day
1753 
1754  do i=1, no_prf
1755  if ( profiles(i)%time <= model_time ) then
1756  tdiff = model_time - profiles(i)%time
1757  else
1758  tdiff = profiles(i)%time - model_time
1759  end if
1760 
1761  ! no tdiff criteria for monthly mean data like
1762  ! but tdiff criteria has to be set for daily data
1763  if ( tdiff <= time_window(profiles(i)%inst_type) .and. profiles(i)%accepted ) then
1764  ! for single profile test
1765 
1766  nprof = nprof + 1
1767  if ( nprof > size(prof,1) ) then
1768  call error_mesg('oda_core_mod::get_obs',&
1769  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call.',&
1770  & fatal)
1771  end if
1772  call copy_obs(profiles(i:i), prof(nprof:nprof))
1773 
1774  prof(nprof)%tdiff = tdiff
1775 
1776  ! snz add the following few lines for increasing deep water data
1777  if ( prof(nprof)%levels > max_prflvs ) then
1778  k_interval = (prof(nprof)%levels-max_prflvs+50)/50 + 1
1779  kk = max_prflvs - 50
1780  do k=max_prflvs-50+1, prof(nprof)%levels, k_interval
1781  kk = kk + 1
1782  prof(nprof)%depth(kk) = prof(nprof)%depth(k)
1783  prof(nprof)%k_index(kk) = prof(nprof)%k_index(k)
1784  prof(nprof)%data(kk) = prof(nprof)%data(k)
1785  prof(nprof)%flag(kk) = prof(nprof)%flag(k)
1786  end do
1787  prof(nprof)%levels = kk
1788  end if
1789  ! snz end the adding lines
1790  end if
1791  end do
1792 
1793  write (unit=stdout_unit,&
1794  & fmt='("A total of ",I8," profiles are being used for the current analysis step.")') nprof
1795 
1796  return
1797  end subroutine get_obs
1798 
1799  subroutine oda_core_init(Domain, Grid, time_s, time_e, filt_domain, localize)
1800  type(domain2d), intent(inout) :: domain
1801  type(grid_type), target, intent(in) :: grid
1802  logical, intent(in), optional :: localize
1803  type(time_type), intent(in) :: time_s, time_e
1804  type(domain2d), intent(in) :: filt_domain
1805 
1806  integer :: ioun, ierr, io_status
1807  integer :: stdlog_unit
1808 
1809  stdlog_unit = stdlog()
1810 
1811  ! Read in the namelist file
1812 #ifdef INTERNAL_FILE_NML
1813  read (input_nml_file, oda_core_nml, iostat=io_status)
1814 #else
1815  ioun = open_namelist_file()
1816  read(ioun, nml=oda_core_nml, iostat=io_status)
1817  ierr = check_nml_error(io_status, 'oda_core_nml')
1818  call close_file(ioun)
1819 #endif
1820 
1821  write(stdlog_unit, nml=oda_core_nml)
1822 
1823  grd => grid
1824 
1825  call mpp_get_compute_domain(domain, isc, iec, jsc, jec)
1826  call mpp_get_data_domain(domain, isd, ied, jsd, jed)
1827  call mpp_get_global_domain(domain, isg, ieg, jsg, jeg)
1828  call mpp_get_data_domain(filt_domain, isd_filt, ied_filt, jsd_filt, jed_filt)
1829 
1830  jsd_flt0 = jsd_filt
1831  jed_flt0 = jed_filt
1832  if (jsd_filt < 1) jsd_flt0 = 1
1833  if (jed_filt > jeg) jed_flt0 = jeg
1834 
1835  nk = size(grid%z)
1836 
1837  call init_observations(time_s, time_e, filt_domain, localize)
1838  end subroutine oda_core_init
1839 
1840  subroutine copy_obs(obs_in, obs_out)
1841  type(ocean_profile_type), dimension(:), intent(in) :: obs_in
1842  type(ocean_profile_type), dimension(:), intent(inout) :: obs_out
1843 
1844  integer :: n
1845 
1846  if ( size(obs_in) .ne. size(obs_out) ) then
1847  call error_mesg('oda_core_mod::copy_obs', 'Size of in and out obs variables are not equal.', fatal)
1848  end if
1849 
1850  do n=1, size(obs_in)
1851  obs_out(n)%variable = obs_in(n)%variable
1852  obs_out(n)%inst_type = obs_in(n)%inst_type
1853  obs_out(n)%levels = obs_in(n)%levels
1854  obs_out(n)%lon = obs_in(n)%lon
1855  obs_out(n)%lat = obs_in(n)%lat
1856  obs_out(n)%accepted = obs_in(n)%accepted
1857  if ( associated(obs_out(n)%depth) ) then
1858  deallocate(obs_out(n)%depth)
1859  nullify(obs_out(n)%depth)
1860  end if
1861  allocate(obs_out(n)%depth(obs_in(n)%levels))
1862  obs_out(n)%depth(:) = obs_in(n)%depth(:)
1863  if ( associated(obs_out(n)%data) ) then
1864  deallocate(obs_out(n)%data)
1865  nullify(obs_out(n)%data)
1866  end if
1867  allocate(obs_out(n)%data(obs_in(n)%levels))
1868  obs_out(n)%data(:) = obs_in(n)%data(:)
1869  if ( associated(obs_out(n)%flag) ) then
1870  deallocate(obs_out(n)%flag)
1871  nullify(obs_out(n)%flag)
1872  end if
1873  allocate(obs_out(n)%flag(obs_in(n)%levels))
1874  obs_out(n)%flag(:) = obs_in(n)%flag(:)
1875  obs_out(n)%time = obs_in(n)%time
1876  obs_out(n)%yyyy = obs_in(n)%yyyy
1877  obs_out(n)%mmdd = obs_in(n)%mmdd
1878  obs_out(n)%i_index = obs_in(n)%i_index
1879  obs_out(n)%j_index = obs_in(n)%j_index
1880  if ( associated(obs_out(n)%k_index) ) then
1881  deallocate(obs_out(n)%k_index)
1882  nullify(obs_out(n)%k_index)
1883  end if
1884  allocate(obs_out(n)%k_index(obs_in(n)%levels))
1885  obs_out(n)%k_index = obs_in(n)%k_index
1886 
1887 ! if ( associated(Obs_out(n)%ms) ) then
1888 ! deallocate(Obs_out(n)%ms)
1889 ! nullify(Obs_out(n)%ms)
1890 ! end if
1891 ! allocate(Obs_out(n)%ms(Obs_in(n)%levels))
1892 ! Obs_out(n)%ms = Obs_in(n)%ms
1893 ! if ( associated(Obs_out(n)%ms_inv) ) then
1894 ! deallocate(Obs_out(n)%ms_inv)
1895 ! nullify(Obs_out(n)%ms_inv)
1896 ! end if
1897 ! allocate(Obs_out(n)%ms_inv(Obs_in(n)%levels))
1898 ! Obs_out(n)%ms_inv = 1./Obs_in(n)%ms
1899 
1900  obs_out(n)%tdiff = obs_in(n)%tdiff
1901  if ( associated(obs_out(n)%Forward_model%wgt) ) then
1902  deallocate(obs_out(n)%Forward_model%wgt)
1903  nullify(obs_out(n)%Forward_model%wgt)
1904  end if
1905  end do
1906  end subroutine copy_obs
1907 
1908  subroutine open_profile_dataset_sst(filename, obs_variable, localize)
1909  character(len=*), intent(in) :: filename
1910  integer, intent(in) :: obs_variable
1911  logical, intent(in), optional :: localize
1912 
1913  integer, parameter :: max_levels = 1
1914 
1915  real :: lon, lat, rms_err
1916  real :: ri0, rj0
1917  real, dimension(MAX_LEVELS) :: depth, data
1918 
1919  integer :: unit, ndim, nvar, natt, ntime
1920  integer :: var_id, inst_type
1921  integer :: num_levs, k, kk, i, j, i0, j0
1922  integer :: stdout_unit
1923 
1924  logical :: data_is_local, localize_data
1925  logical, dimension(MAX_LEVELS) :: flag
1926 
1927  character(len=32) :: axisname, anal_fldname
1928  character(len=128) :: emsg_local
1929 
1930  type(axistype), dimension(:), allocatable, target :: axes
1931  type(axistype), pointer :: lon_axis, lat_axis
1932 
1933  if ( PRESENT(localize) ) then
1934  localize_data = localize
1935  else
1936  localize_data = .true.
1937  end if
1938 
1939  stdout_unit = stdout()
1940 
1941  anal_fldname = 'temp'
1942  var_id = obs_variable
1943 
1944  call mpp_open(unit, trim(filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
1945  call mpp_get_info(unit, ndim, nvar, natt, ntime)
1946  allocate(axes(ndim))
1947  call mpp_get_axes(unit, axes)
1948 
1949  do i=1, ndim
1950  call mpp_get_atts(axes(i),name=axisname)
1951  select case (trim(axisname))
1952 !!$ case ('GRIDLON_T') ! cm2 grids
1953 !!$ case ('gridlon_t') ! cm2 grids
1954  case ('XT_OCEAN') ! cm2.5 grids
1955 !!$ case ('lon') ! after 2008
1956  lon_axis => axes(i)
1957 !!$ case ('GRIDLAT_T') ! cm2 grids
1958 !!$ case ('gridlat_t') ! cm2 grids
1959  case ('YT_OCEAN') ! cm2 grids
1960 !!$ case ('lat') ! for after 2008
1961  lat_axis => axes(i)
1962  end select
1963  end do
1964 
1965  call mpp_get_atts(lon_axis,len=nlon)
1966  call mpp_get_atts(lat_axis,len=nlat)
1967  if ( nlon /= 1440 .or. nlat /= 1070 ) then ! after 2008
1968  write (unit=emsg_local, fmt='("sst obs dim is not same as in file. nlon = ",I5,", nlat = ",I5)') nlon, nlat
1969  call error_mesg('oda_core_mod::open_profile_dataset_sst', trim(emsg_local), fatal)
1970  end if
1971 
1972  ! idealized
1973  do j=1, nlat
1974  do i=1, nlon
1975  lon = x_grid(i,j)
1976  lat = y_grid(i,j)
1977  rms_err = 0.5
1978  inst_type = 20
1979  data_is_local = .true.
1980 
1981  if ( lon .lt. 0.0 ) lon = lon + 360.0
1982  if ( lon .gt. 360.0 ) lon = lon - 360.0
1983  if ( lon .lt. 80.0 ) lon = lon + 360.0
1984 
1985  if ( lat < sst_obs_start_lat .or. lat > sst_obs_end_lat ) data_is_local = .false. ! at the final test
1986 
1987  if ( grd%mask(i,j,1) == 0 ) data_is_local = .false.
1988 
1989  if ( abs(lat) < 40.0 ) then
1990  if ( i/4*4 /= i .or. j/4*4 /= j ) data_is_local = .false.
1991  else if ( abs(lat) < 60.0 ) then
1992  if ( i/8*8 /= i .or. j/6*6 /= j ) data_is_local = .false.
1993  else
1994  if ( i/16*16 /= i .or. j/8*8 /= j ) data_is_local = .false.
1995  end if
1996 
1997  if ( data_is_local .and. (.NOT.localize_data) ) then
1998  if ( lat < 60.0 ) then ! regular grids
1999  ri0 = frac_index(lon, x_grid(:,nlat/2))
2000  rj0 = frac_index(lat, y_grid(nlon/4,:))
2001  i0 = floor(ri0)
2002  j0 = floor(rj0)
2003  else ! tripolar grids
2004  lon_out(1,1) = lon*deg_to_rad
2005  lat_out(1,1) = lat*deg_to_rad
2007  if ( interp%wti(1,1,2) < 1.0 ) then
2008  i0 = interp%i_lon(1,1,1)
2009  else
2010  i0 = interp%i_lon(1,1,2)
2011  end if
2012  if ( interp%wtj(1,1,2) < 1.0 ) then
2013  j0 = interp%j_lat(1,1,1)
2014  else
2015  j0 = interp%j_lat(1,1,2)
2016  end if
2017 
2018  if ( i0 > ieg .or. j0 > jeg ) then
2019  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') i0, j0
2020  call error_mesg('oda_core_mod::open_profile_dataset_sst',&
2021  & 'For tripolar grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
2022  end if
2023  end if
2024 
2025  if ( i0 /= ieg .and. j0 /= jeg ) then ! exclude SSTs at ieg and jeg
2026  if ( grd%mask(i0,j0,1) /= 0.0 .and. grd%mask(i0+1,j0,1) /= 0.0 .and.&
2027  & grd%mask(i0,j0+1,1) /= 0.0 .and. grd%mask(i0+1,j0+1,1) /= 0.0 ) then
2028  no_sst = no_sst+1
2030 
2031  if ( num_profiles > max_profiles ) then
2032  call error_mesg('oda_core_mod::open_profile_dataset_sst',&
2033  & 'Maximum number of profiles exceeded, increase max_profiles in oda_core_nml', fatal)
2034  end if
2035 
2036  num_levs = 0
2037  flag = .false.
2038  do k=1, 1
2039  flag(k) = .true.
2040  data(k) = 0.0
2041  depth(k) = 0.0
2042  num_levs = num_levs + 1
2043  end do
2044  if ( num_levs == 0 ) cycle
2045  allocate(profiles(num_profiles)%depth(num_levs))
2046  allocate(profiles(num_profiles)%data(num_levs))
2047  allocate(profiles(num_profiles)%flag(num_levs))
2048  allocate(profiles(num_profiles)%ms(num_levs))
2049  allocate(profiles(num_profiles)%ms_inv(num_levs))
2050  profiles(num_profiles)%variable = var_id
2051  profiles(num_profiles)%inst_type = inst_type
2052  profiles(num_profiles)%levels = num_levs
2053  profiles(num_profiles)%lat = lat
2054  profiles(num_profiles)%lon = lon
2055 
2056  kk = 1
2057  do k=1, 1
2058  if ( flag(k) ) then
2059  profiles(num_profiles)%depth(kk) = depth(k)
2060  profiles(num_profiles)%data(kk) = data(k)
2061  profiles(num_profiles)%ms(kk) = 1.0
2062  profiles(num_profiles)%ms_inv(kk) = 1.0
2063  kk=kk+1
2064  end if
2065  end do
2066 
2067  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
2068  if ( lat < 60.0 ) then ! for regular grids
2069  profiles(num_profiles)%i_index = ri0
2070  profiles(num_profiles)%j_index = rj0
2071  else ! for tripolar grids
2072  lon_out(1,1) = lon*deg_to_rad
2073  lat_out(1,1) = lat*deg_to_rad
2075  if ( interp%wti(1,1,2) < 1.0 ) then
2076  profiles(num_profiles)%i_index =interp%i_lon(1,1,1) + interp%wti(1,1,2)
2077  else
2078  profiles(num_profiles)%i_index =interp%i_lon(1,1,2)
2079  end if
2080  if ( interp%wtj(1,1,2) < 1.0 ) then
2081  profiles(num_profiles)%j_index =interp%j_lat(1,1,1) + interp%wtj(1,1,2)
2082  else
2083  profiles(num_profiles)%j_index =interp%j_lat(1,1,2)
2084  end if
2085  end if
2086 
2087  profiles(num_profiles)%accepted = .true.
2088  if ( i0 < 1 .or. j0 < 1 ) then
2089  profiles(num_profiles)%accepted = .false.
2090  end if
2091  if ( profiles(num_profiles)%accepted ) then
2092  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2093  & grd%mask(i0+1,j0,1) == 0.0 .or.&
2094  & grd%mask(i0,j0+1,1) == 0.0 .or.&
2095  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
2096  profiles(num_profiles)%accepted = .false.
2097  end if
2098  end if
2099  if ( profiles(num_profiles)%accepted ) then
2100  profiles(num_profiles)%flag(:) = .true.
2101  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
2102  do k=1, profiles(num_profiles)%levels
2103  profiles(num_profiles)%k_index(k) = frac_index(depth(k), (/0.,grd%z(:)/)) - 1
2104  !::sdu:: Do we need the same out-of-range check here?
2105  end do
2106  end if
2107  end if ! exclude SSTs at ieg and jeg
2108  end if
2109  end if
2110  end do
2111  end do
2112 
2113  call mpp_close(unit)
2114  deallocate(axes)
2115  write (unit=stdout_unit, fmt='("A grand total of ",I8," sst points within global domain")') no_sst
2116  write (unit=stdout_unit, fmt='("A final total @sst of ",I8," prfs within global domain")') num_profiles
2117  end subroutine open_profile_dataset_sst
2118 
2119  subroutine open_profile_dataset_woa05t(filename, obs_variable, localize)
2120  character(len=*), intent(in) :: filename
2121  integer, intent(in) :: obs_variable
2122  logical, intent(in), optional :: localize
2123 
2124  integer, parameter :: MAX_LEVELS = 24
2125 
2126  real :: lon, lat, rms_err
2127  real :: ri0, rj0
2128  real, dimension(MAX_LEVELS) :: depth, data
2129 
2130  integer :: unit, ndim, nvar, natt, ntime
2131  integer :: var_id, inst_type
2132  integer :: num_levs, k, kk, i, j, i0, j0, k0
2133  integer :: stdout_unit, istat
2134  integer :: out_bound_point
2135 
2136  logical :: data_is_local, localize_data
2137  logical :: prof_in_filt_domain
2138  logical, dimension(MAX_LEVELS) :: flag
2139 
2140  character(len=32) :: axisname, anal_fldname
2141  character(len=128) :: emsg_local
2142 
2143  type(axistype), dimension(:), allocatable, target :: axes
2144  type(axistype), pointer :: lon_axis, lat_axis, z_axis, t_axis
2145 
2146  if ( PRESENT(localize) ) then
2147  localize_data = localize
2148  else
2149  localize_data = .true.
2150  end if
2151 
2152  stdout_unit = stdout()
2153  anal_fldname = 'temp'
2154  var_id = obs_variable
2155 
2156 ! call mpp_print_memuse_stats('open_profile_dataset_woa05t Start')
2157 
2158  call mpp_open(unit, trim(filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2159 
2160  write (unit=stdout_unit, fmt='("Opened profile woa05t dataset: ",A)') trim(filename)
2161 
2162  call mpp_get_info(unit, ndim, nvar, natt, ntime)
2163  allocate(axes(ndim))
2164  call mpp_get_axes(unit,axes)
2165  do i=1, ndim
2166  call mpp_get_atts(axes(i), name=axisname)
2167  select case (trim(axisname))
2168  case ('lon')
2169  lon_axis => axes(i)
2170  case ('lat')
2171  lat_axis => axes(i)
2172  case ('depth')
2173  z_axis => axes(i)
2174  end select
2175  end do
2176 
2177  call mpp_get_atts(lon_axis, len=nlon_woa)
2178  call mpp_get_atts(lat_axis, len=nlat_woa)
2179  call mpp_get_atts(z_axis, len=nlev_woa)
2180 
2181  if ( nlon_woa /= 360 .or. nlat_woa /= 180 ) then
2182  write (unit=emsg_local, fmt='("woa05 obs dim is not same as in file. nlon_woa = ",I8,", nlat_woa = ",I8)') nlon_woa, nlat_woa
2183  call error_mesg('oda_core_mod::open_profile_dataset_woa05t', trim(emsg_local), fatal)
2184  end if
2185 
2187 
2188  call mpp_get_axis_data(lon_axis, woa05_lon)
2189  call mpp_get_axis_data(lat_axis, woa05_lat)
2190  call mpp_get_axis_data(z_axis, woa05_z)
2191 
2192  out_bound_point = 0
2193  ! idealized
2194  do j=1, nlat_woa
2195  do i=1, nlon_woa
2196  lon = woa05_lon(i)
2197  lat = woa05_lat(j)
2198  rms_err = 5
2199  inst_type = 20
2200  data_is_local = .true.
2201  prof_in_filt_domain = .false.
2202 
2203  if ( lon .lt. 0.0 ) lon = lon + 360.0
2204  if ( lon .gt. 360.0 ) lon = lon - 360.0
2205  if ( lon .lt. 80.0 ) lon = lon + 360.0
2206 
2207  if ( lat < -80.0 .or. lat > 80.0 ) data_is_local = .false.
2208  if ( abs(lat) < 20.0 .and. (mod(i,2) /= 0 .or. mod(j,2) /= 0) ) data_is_local = .false.
2209  if ( abs(lat) >= 20.0 .and. (mod(i,4) /= 0 .or. mod(j,4) /= 0) ) data_is_local = .false.
2210  if ( abs(lat) >= 60.0 .and. (mod(i,6) /= 0 .or. mod(j,6) /= 0) ) data_is_local = .false.
2211 
2212  if (isd_filt < 1 .and. ied_filt > ieg) then
2213  ! filter domain is a full x band
2214  if (lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2215  lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ieg-1,jsd_flt0)) then
2216  prof_in_filt_domain = .true.
2217  end if
2218  else if (isd_filt >= 1 .and. ied_filt <= ieg) then
2219  ! Interior filter domain
2220  if (lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
2221  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)) then
2222  prof_in_filt_domain = .true.
2223  end if
2224  else if (isd_filt < 1 .and. ied_filt <= ieg) then
2225  ! lhs filter domain
2226  isd_flt0 = isd_filt + ieg
2227  if ((lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
2228  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)).or.&
2229  & (lon >= x_grid(isd_flt0,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2230  & lat >= y_grid(isd_flt0,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1))) then
2231  prof_in_filt_domain = .true.
2232  end if
2233  else if (isd_filt >= 1 .and. ied_filt > ieg) then
2234  ! rhs filter domain
2235  ied_flt0 = ied_filt - ieg
2236  if ( lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2237  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1) ) then
2238  prof_in_filt_domain = .true.
2239  end if
2240  if (ied_flt0-1 > 1) then
2241  if ( lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_flt0-1,jsd_flt0) .and.&
2242  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_flt0-1,jed_flt0-1) ) then
2243  prof_in_filt_domain = .true.
2244  end if
2245  end if
2246  end if
2247 
2248  if ( data_is_local .and. (.NOT.localize_data) ) then ! global index
2249 
2250  no_woa05 = no_woa05 + 1
2252  if ( num_profiles > max_profiles ) then
2253  call error_mesg('oda_core_mod::open_profile_dataset_woa05t',&
2254  & 'Maximum number of profiles exceeded, increase max_profiles in oda_core_nml', fatal)
2255  end if
2256 
2257  num_levs = 0
2258  flag = .false.
2259  do k=1, nlev
2260  flag(k) = .true.
2261  data(k) = 0.0
2262  depth(k) = woa05_z(k)
2263  num_levs = num_levs+1
2264  end do
2265  if ( num_levs == 0 ) cycle
2266 
2267  if ( prof_in_filt_domain ) then ! localize
2268 
2269  allocate(profiles(num_profiles)%depth(num_levs))
2270  allocate(profiles(num_profiles)%data(num_levs))
2271  allocate(profiles(num_profiles)%flag(num_levs))
2272 ! allocate(profiles(num_profiles)%ms(num_levs))
2273 ! allocate(profiles(num_profiles)%ms_inv(num_levs))
2274  profiles(num_profiles)%variable = var_id
2275  profiles(num_profiles)%inst_type = inst_type
2276  profiles(num_profiles)%levels = num_levs
2277  profiles(num_profiles)%lat = lat
2278  profiles(num_profiles)%lon = lon
2279 
2280  kk = 1
2281  do k=1, nlev
2282  if ( flag(k) ) then
2283  profiles(num_profiles)%depth(kk) = depth(k)
2284  profiles(num_profiles)%data(kk) = data(k)
2285 ! profiles(num_profiles)%ms(kk) = 1.0
2286 ! profiles(num_profiles)%ms_inv(kk) = 1.0
2287  kk = kk + 1
2288  end if
2289  end do
2290 
2291  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
2292  if ( lat < 65.0 ) then ! regular grids
2293  ri0 = frac_index(lon, x_grid(:,1))
2294  rj0 = frac_index(lat, y_grid(90,:))
2295  i0 = floor(ri0)
2296  j0 = floor(rj0)
2297  if ( i0 > ieg .or. j0 > jeg ) then
2298  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') i0, j0
2299  call error_mesg('oda_core_mod::open_profile_dataset_woa05t',&
2300  & 'For regular grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
2301  end if
2302  if ( isd_filt >= 1 .and. ied_filt <= ieg ) then
2303  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
2304  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2305  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2306  call error_mesg('oda_core_mod::open_profile_dataset',&
2307  & 'i0,j0 out of bounds in woat01. '//trim(emsg_local), fatal)
2308  end if
2309  end if
2310  if ( isd_filt < 1 .and. i0 > ied_filt-1 .and. i0 < isd_filt + ieg ) then
2311  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2312  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2313  call error_mesg('oda_core_mod::open_profile_dataset',&
2314  & 'i0,j0 out of bounds in woat02. '//trim(emsg_local), fatal)
2315  end if
2316  if ( ied_filt > ieg .and. i0 > ied_filt-ieg-1 .and. ied_filt < isd_filt ) then
2317  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2318  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2319  call error_mesg('oda_core_mod::open_profile_dataset',&
2320  & 'i0,j0 out of bounds in woat03. '//trim(emsg_local), fatal)
2321  end if
2322  profiles(num_profiles)%i_index = ri0
2323  profiles(num_profiles)%j_index = rj0
2324  else ! tripolar grids
2325  lon_out(1,1) = lon*deg_to_rad
2326  lat_out(1,1) = lat*deg_to_rad
2328  if ( interp%wti(1,1,2) < 1.0 ) then
2329  i0 = interp%i_lon(1,1,1)
2330  else
2331  i0 = interp%i_lon(1,1,2)
2332  end if
2333  if ( interp%wtj(1,1,2) < 1.0 ) then
2334  j0 = interp%j_lat(1,1,1)
2335  else
2336  j0 = interp%j_lat(1,1,2)
2337  end if
2338  if ( i0 > ieg .or. j0 > jeg ) then
2339  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') i0, j0
2340  call error_mesg('oda_core_mod::open_profile_dataset_woa05t',&
2341  & 'For tripolar grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
2342  end if
2343  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
2344  write (unit=stdout_unit, fmt='("woat.pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2345  & mpp_pe(),i0, j0,isd_filt,ied_filt,jsd_filt,jed_filt
2346  out_bound_point = out_bound_point + 1
2347  end if
2348  if ( interp%wti(1,1,2) < 1.0 ) then
2349  profiles(num_profiles)%i_index =interp%i_lon(1,1,1) + interp%wti(1,1,2)
2350  else
2351  profiles(num_profiles)%i_index =interp%i_lon(1,1,2)
2352  end if
2353  if ( interp%wtj(1,1,2) < 1.0 ) then
2354  profiles(num_profiles)%j_index =interp%j_lat(1,1,1) + interp%wtj(1,1,2)
2355  else
2356  profiles(num_profiles)%j_index =interp%j_lat(1,1,2)
2357  end if
2358  end if ! grids
2359 
2360  profiles(num_profiles)%accepted = .true.
2361  if ( i0 < 1 .or. j0 < 1 ) then
2362  profiles(num_profiles)%accepted = .false.
2363  end if
2364  if ( i0 < isd_filt .or. i0 >= ied_filt .or. j0 < jsd_filt .or. j0 >= jed_filt ) then
2365  profiles(num_profiles)%accepted = .false.
2366  end if
2367 
2368  if ( profiles(num_profiles)%accepted ) then ! here
2369  if ( i0 /= ieg .and. j0 /= jeg ) then
2370  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2371  & grd%mask(i0+1,j0,1) == 0.0 .or.&
2372  & grd%mask(i0,j0+1,1) == 0.0 .or.&
2373  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
2374  profiles(num_profiles)%accepted = .false.
2375  end if
2376  else if ( i0 == ieg .and. j0 /= jeg ) then
2377  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2378  & grd%mask(1,j0,1) == 0.0 .or.&
2379  & grd%mask(i0,j0+1,1) == 0.0 .or.&
2380  & grd%mask(1,j0+1,1) == 0.0 ) then
2381  profiles(num_profiles)%accepted = .false.
2382  end if
2383  else if ( i0 /= ieg .and. j0 == jeg ) then
2384  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2385  & grd%mask(i0+1,j0,1) == 0.0 ) then
2386  profiles(num_profiles)%accepted = .false.
2387  end if
2388  else
2389  if ( grd%mask(i0,j0,1) == 0.0 ) then
2390  profiles(num_profiles)%accepted = .false.
2391  end if
2392  end if
2393  end if ! here
2394 
2395  if ( profiles(num_profiles)%accepted ) then ! accepted
2396  profiles(num_profiles)%flag(:) = .true.
2397  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
2398  do k=1, profiles(num_profiles)%levels
2399  if (depth(k) < grd%z(1)) then
2400  profiles(num_profiles)%k_index(k) = 0.0
2401  else
2402  profiles(num_profiles)%k_index(k) = frac_index(depth(k), (/0.,grd%z(:)/)) - 1.0 ! snz modify to v3.2 JAN3012
2403  end if
2404  if ( profiles(num_profiles)%k_index(k) > nk ) then
2405  call error_mesg('oda_core_mod::open_profile_dataset_woa05t',&
2406  & 'Profile k_index is greater than nk', fatal)
2407  end if
2408  k0 = floor(profiles(num_profiles)%k_index(k))
2409 
2410  if ( k0 >= 1 ) then ! snz add
2411  if ( profiles(num_profiles)%flag(k) ) then ! flag
2412  if ( i0 /= ieg .and. j0 /= jeg ) then
2413  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2414  & grd%mask(i0+1,j0,k0) == 0.0 .or.&
2415  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
2416  & grd%mask(i0+1,j0+1,k0) == 0.0 ) then
2417  profiles(num_profiles)%flag(k) = .false.
2418  end if
2419  else if ( i0 == ieg .and. j0 /= jeg ) then
2420  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2421  & grd%mask(1,j0,k0) == 0.0 .or.&
2422  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
2423  & grd%mask(1,j0+1,k0) == 0.0 ) then
2424  profiles(num_profiles)%flag(k) = .false.
2425  end if
2426  else if ( i0 /= ieg .and. j0 == jeg ) then
2427  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2428  & grd%mask(i0+1,j0,k0) == 0.0 ) then
2429  profiles(num_profiles)%flag(k) = .false.
2430  end if
2431  else
2432  if ( grd%mask(i0,j0,k0) == 0.0 ) then
2433  profiles(num_profiles)%flag(k) = .false.
2434  end if
2435  end if
2436 
2437  if ( i0 /= ieg .and. j0 /= jeg ) then
2438  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2439  & grd%mask(i0+1,j0,k0+1) == 0.0 .or.&
2440  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
2441  & grd%mask(i0+1,j0+1,k0+1) == 0.0 ) then
2442  profiles(num_profiles)%flag(k) = .false.
2443  end if
2444  else if ( i0 == ieg .and. j0 /= jeg ) then
2445  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2446  & grd%mask(1,j0,k0+1) == 0.0 .or.&
2447  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
2448  & grd%mask(1,j0+1,k0+1) == 0.0 ) then
2449  profiles(num_profiles)%flag(k) = .false.
2450  end if
2451  else if ( i0 /= ieg .and. j0 == jeg ) then
2452  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2453  & grd%mask(i0+1,j0,k0+1) == 0.0) then
2454  profiles(num_profiles)%flag(k) = .false.
2455  end if
2456  else
2457  if ( grd%mask(i0,j0,k0+1) == 0.0 ) then
2458  profiles(num_profiles)%flag(k) = .false.
2459  end if
2460  end if
2461 
2462  if ( abs(profiles(num_profiles)%data(k)) > 1.e4 &
2463  & .or. abs(profiles(num_profiles)%depth(k)) > 1.e4 ) then
2464  profiles(num_profiles)%flag(k) = .false.
2465  end if
2466  end if ! flag
2467  end if ! snz add
2468  end do
2469  end if ! accepted
2470  end if ! localize
2471  end if ! global index
2472  end do
2473  end do
2474 
2475  call mpp_close(unit)
2476  deallocate(axes)
2477  write (unit=stdout_unit, fmt='("A grand total of ",I8," woa05t points within global domain")') no_woa05
2478  write (unit=stdout_unit, fmt='("A final total @woa05t of ",I8," prfs within global domain")') num_profiles
2479 
2480 ! call mpp_print_memuse_stats('open_profile_dataset_woa05t End')
2481 
2482  end subroutine open_profile_dataset_woa05t
2483 
2484  subroutine open_profile_dataset_woa05s(filename, obs_variable, localize)
2485  character(len=*), intent(in) :: filename
2486  integer, intent(in) :: obs_variable
2487  logical, intent(in), optional :: localize
2488 
2489  integer, parameter :: MAX_LEVELS = 24
2490 
2491  real :: lon, lat, rms_err
2492  real :: ri0, rj0
2493  real, dimension(MAX_LEVELS) :: depth, data
2494 
2495  integer :: unit, ndim, nvar, natt, ntime
2496  integer :: var_id, inst_type
2497  integer :: num_levs, k, kk, i, j, i0, j0, k0
2498  integer :: stdout_unit
2499  integer :: out_bound_point
2500 
2501  logical :: data_is_local, localize_data
2502  logical :: prof_in_filt_domain
2503  logical, dimension(MAX_LEVELS) :: flag
2504 
2505  character(len=32) :: axisname, anal_fldname
2506  character(len=128) :: emsg_local
2507 
2508  type(axistype), dimension(:), allocatable, target :: axes
2509  type(axistype), pointer :: lon_axis, lat_axis, z_axis
2510 
2511  if ( present(localize) ) then
2512  localize_data = localize
2513  else
2514  localize_data = .true.
2515  end if
2516 
2517  stdout_unit = stdout()
2518 
2519  anal_fldname = 'salt'
2520  var_id = obs_variable
2521 
2522 ! call mpp_print_memuse_stats('open_profile_dataset_woa05s Start')
2523 
2524  call mpp_open(unit, trim(filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2525 
2526  write (unit=stdout_unit, fmt='("Opened profile woa05s dataset: ",A)') trim(filename)
2527 
2528  call mpp_get_info(unit, ndim, nvar, natt, ntime)
2529  allocate(axes(ndim))
2530  call mpp_get_axes(unit, axes)
2531  do i=1, ndim
2532  call mpp_get_atts(axes(i), name=axisname)
2533  select case ( trim(axisname) )
2534  case ('lon')
2535  lon_axis => axes(i)
2536  case ('lat')
2537  lat_axis => axes(i)
2538  case ('depth')
2539  z_axis => axes(i)
2540  end select
2541  end do
2542  call mpp_get_atts(lon_axis, len=nlon_woa)
2543  call mpp_get_atts(lat_axis, len=nlat_woa)
2544  call mpp_get_atts(z_axis, len=nlev_woa)
2545  if ( nlon_woa /= 360 .or. nlat_woa /= 180 ) then
2546  write (unit=emsg_local, fmt='("woa05 obs dim is not same as in file nlon_woa = ",I8,", nlat_woa = ",I8)') nlon_woa, nlat_woa
2547  call error_mesg('oda_core_mod::open_profile_dataset_woa05s', trim(emsg_local), fatal)
2548  end if
2549 
2550  out_bound_point = 0
2551  ! idealized
2552  do j=1, nlat_woa
2553  do i=1, nlon_woa
2554  lon = woa05_lon(i)
2555  lat = woa05_lat(j)
2556  rms_err = 5
2557  inst_type = 20
2558  data_is_local = .true.
2559  prof_in_filt_domain = .false.
2560 
2561  if ( lon .lt. 0.0 ) lon = lon + 360.0
2562  if ( lon .gt. 360.0 ) lon = lon - 360.0
2563  if ( lon .lt. 80.0 ) lon = lon + 360.0
2564 
2565  if ( lat < -80.0 .or. lat > 80.0 ) data_is_local = .false.
2566  if ( abs(lat) < 20.0 .and. (mod(i,2) /= 0 .or. mod(j,2) /= 0) ) data_is_local = .false.
2567  if ( abs(lat) >= 20.0 .and. (mod(i,4) /= 0 .or. mod(j,4) /= 0) ) data_is_local = .false.
2568  if ( abs(lat) >= 60.0 .and. (mod(i,6) /= 0 .or. mod(j,6) /= 0) ) data_is_local = .false.
2569 
2570  if (isd_filt < 1 .and. ied_filt > ieg) then
2571  ! filter domain is a full x band
2572  if (lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2573  lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ieg-1,jsd_flt0)) then
2574  prof_in_filt_domain = .true.
2575  end if
2576  else if (isd_filt >= 1 .and. ied_filt <= ieg) then
2577  ! Interior filter domain
2578  if (lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
2579  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)) then
2580  prof_in_filt_domain = .true.
2581  end if
2582  else if (isd_filt < 1 .and. ied_filt <= ieg) then
2583  ! lhs filter domain
2584  isd_flt0 = isd_filt + ieg
2585  if ((lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_filt-1,jsd_flt0) .and.&
2586  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_filt-1,jed_flt0-1)).or.&
2587  & (lon >= x_grid(isd_flt0,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2588  & lat >= y_grid(isd_flt0,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1))) then
2589  prof_in_filt_domain = .true.
2590  end if
2591  else if (isd_filt >= 1 .and. ied_filt > ieg) then
2592  ! rhs filter domain
2593  ied_flt0 = ied_filt - ieg
2594  if ( lon >= x_grid(isd_filt,jsd_flt0) .and. lon <= x_grid(ieg-1,jsd_flt0) .and.&
2595  & lat >= y_grid(isd_filt,jsd_flt0) .and. lat <= y_grid(ieg-1,jed_flt0-1) ) then
2596  prof_in_filt_domain = .true.
2597  end if
2598  if (ied_flt0-1 > 1) then
2599  if ( lon >= x_grid(1,jsd_flt0) .and. lon <= x_grid(ied_flt0-1,jsd_flt0) .and.&
2600  & lat >= y_grid(1,jsd_flt0) .and. lat <= y_grid(ied_flt0-1,jed_flt0-1) ) then
2601  prof_in_filt_domain = .true.
2602  end if
2603  end if
2604  end if
2605 
2606  if ( data_is_local .and. (.NOT.localize_data) ) then ! global index
2607 
2608  no_woa05 = no_woa05 + 1
2610  if ( num_profiles > max_profiles ) then
2611  call error_mesg('oda_core_mod::open_profile_dataset_woa05s',&
2612  & 'Maximum number of profiles exceeded, increase max_profiles in oda_core_nml.', fatal)
2613  end if
2614 
2615  num_levs = 0
2616  flag = .false.
2617  do k=1, nlev_woa
2618  flag(k) = .true.
2619  data(k) = 0.0
2620  depth(k) = woa05_z(k)
2621  num_levs = num_levs + 1
2622  end do
2623  if ( num_levs == 0 ) cycle
2624 
2625  if ( prof_in_filt_domain ) then ! localize
2626 
2627  allocate(profiles(num_profiles)%depth(num_levs))
2628  allocate(profiles(num_profiles)%data(num_levs))
2629  allocate(profiles(num_profiles)%flag(num_levs))
2630 ! allocate(profiles(num_profiles)%ms(num_levs))
2631 ! allocate(profiles(num_profiles)%ms_inv(num_levs))
2632  profiles(num_profiles)%variable = var_id
2633  profiles(num_profiles)%inst_type = inst_type
2634  profiles(num_profiles)%levels = num_levs
2635  profiles(num_profiles)%lat = lat
2636  profiles(num_profiles)%lon = lon
2637 
2638  kk = 1
2639  do k=1, nlev_woa
2640  if ( flag(k) ) then
2641  profiles(num_profiles)%depth(kk) = depth(k)
2642  profiles(num_profiles)%data(kk) = data(k)
2643 ! profiles(num_profiles)%ms(kk) = 1.0
2644 ! profiles(num_profiles)%ms_inv(kk) = 1.0
2645  kk = kk + 1
2646  end if
2647  end do
2648 
2649  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
2650  if ( lat < 65.0 ) then ! regular grids
2651  ri0 = frac_index(lon, x_grid(:,1))
2652  rj0 = frac_index(lat, y_grid(90,:))
2653  i0 = floor(ri0)
2654  j0 = floor(rj0)
2655  if ( i0 > ieg .or. j0 > jeg ) then
2656  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') i0, j0
2657  call error_mesg('oda_core_mod::open_profile_dataset_woa05s',&
2658  & 'For regular grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
2659  end if
2660  if ( isd_filt >= 1 .and. ied_filt <= ieg ) then
2661  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
2662  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2663  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2664  call error_mesg('oda_core_mod::open_profile_dataset',&
2665  & 'i0,j0 out of bounds in woas01. '//trim(emsg_local), fatal)
2666  end if
2667  end if
2668  if ( isd_filt < 1 .and. i0 > ied_filt-1 .and. i0 < isd_filt + ieg ) then
2669  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2670  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2671  call error_mesg('oda_core_mod::open_profile_dataset',&
2672  & 'i0,j0 out of bounds in woas02. '//trim(emsg_local), fatal)
2673  end if
2674  if ( ied_filt > ieg .and. i0 > ied_filt-ieg-1 .and. ied_filt < isd_filt ) then
2675  write (unit=emsg_local, fmt='("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2676  & mpp_pe(), i0, j0, isd_filt,ied_filt,jsd_filt,jed_filt
2677  call error_mesg('oda_core_mod::open_profile_dataset',&
2678  & 'i0,j0 out of bounds in woas03. '//trim(emsg_local), fatal)
2679  end if
2680  profiles(num_profiles)%i_index = ri0
2681  profiles(num_profiles)%j_index = rj0
2682  else ! tripolar grids
2683  lon_out(1,1) = lon*deg_to_rad
2684  lat_out(1,1) = lat*deg_to_rad
2686  if ( interp%wti(1,1,2) < 1.0 ) then
2687  i0 = interp%i_lon(1,1,1)
2688  else
2689  i0 = interp%i_lon(1,1,2)
2690  end if
2691  if ( interp%wtj(1,1,2) < 1.0 ) then
2692  j0 = interp%j_lat(1,1,1)
2693  else
2694  j0 = interp%j_lat(1,1,2)
2695  end if
2696  if ( i0 > ieg .or. j0 > jeg ) then
2697  write (unit=emsg_local, fmt='("i0 = ",I8,", j0 = ",I8)') i0, j0
2698  call error_mesg('oda_core_mod::open_profile_dataset_woa05s',&
2699  & 'For tripolar grids, either i0 > ieg or j0 > jeg. '//trim(emsg_local), fatal)
2700  end if
2701  if ( i0 < isd_filt .or. i0 > ied_filt .or. j0 < jsd_filt .or. j0 > jed_filt ) then
2702  write (unit=stdout_unit, fmt='("woas.pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2703  & mpp_pe(),i0, j0,isd_filt,ied_filt,jsd_filt,jed_filt
2704  out_bound_point = out_bound_point + 1
2705  end if
2706  if ( interp%wti(1,1,2) < 1.0 ) then
2707  profiles(num_profiles)%i_index =interp%i_lon(1,1,1) + interp%wti(1,1,2)
2708  else
2709  profiles(num_profiles)%i_index =interp%i_lon(1,1,2)
2710  end if
2711  if ( interp%wtj(1,1,2) < 1.0 ) then
2712  profiles(num_profiles)%j_index =interp%j_lat(1,1,1) + interp%wtj(1,1,2)
2713  else
2714  profiles(num_profiles)%j_index =interp%j_lat(1,1,2)
2715  end if
2716  end if ! grids
2717 
2718  profiles(num_profiles)%accepted = .true.
2719  if ( i0 < 1 .or. j0 < 1 ) then
2720  profiles(num_profiles)%accepted = .false.
2721  end if
2722  if ( i0 < isd_filt .or. i0 >= ied_filt .or. j0 < jsd_filt .or. j0 >= jed_filt ) then
2723  profiles(num_profiles)%accepted = .false.
2724  end if
2725 
2726  if ( profiles(num_profiles)%accepted ) then ! here
2727  if ( i0 /= ieg .and. j0 /= jeg ) then
2728  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2729  & grd%mask(i0+1,j0,1) == 0.0 .or.&
2730  & grd%mask(i0,j0+1,1) == 0.0 .or.&
2731  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
2732  profiles(num_profiles)%accepted = .false.
2733  end if
2734  else if ( i0 == ieg .and. j0 /= jeg ) then
2735  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2736  & grd%mask(1,j0,1) == 0.0 .or.&
2737  & grd%mask(i0,j0+1,1) == 0.0 .or.&
2738  & grd%mask(1,j0+1,1) == 0.0 ) then
2739  profiles(num_profiles)%accepted = .false.
2740  end if
2741  else if ( i0 /= ieg .and. j0 == jeg ) then
2742  if ( grd%mask(i0,j0,1) == 0.0 .or.&
2743  & grd%mask(i0+1,j0,1) == 0.0 ) then
2744  profiles(num_profiles)%accepted = .false.
2745  end if
2746  else
2747  if ( grd%mask(i0,j0,1) == 0.0 ) then
2748  profiles(num_profiles)%accepted = .false.
2749  end if
2750  end if
2751  end if ! here
2752 
2753  if ( profiles(num_profiles)%accepted ) then ! accepted
2754  profiles(num_profiles)%flag(:) = .true.
2755  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
2756  do k=1, profiles(num_profiles)%levels
2757  if (depth(k) < grd%z(1)) then
2758  profiles(num_profiles)%k_index(k) = 0.0
2759  else
2760  profiles(num_profiles)%k_index(k) = frac_index(depth(k), (/0.,grd%z(:)/)) - 1.0 ! snz modify to v3.2 JAN3012
2761  end if
2762  if ( profiles(num_profiles)%k_index(k) > nk ) then
2763  call error_mesg('oda_core_mod::open_profile_dataset_woa05s',&
2764  & 'Profile k_index is greater than nk', fatal)
2765  end if
2766  k0 = floor(profiles(num_profiles)%k_index(k))
2767 
2768  if ( k0 >= 1 ) then ! snz add
2769  if ( profiles(num_profiles)%flag(k) ) then ! flag
2770  if ( i0 /= ieg .and. j0 /= jeg ) then
2771  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2772  & grd%mask(i0+1,j0,k0) == 0.0 .or.&
2773  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
2774  & grd%mask(i0+1,j0+1,k0) == 0.0 ) then
2775  profiles(num_profiles)%flag(k) = .false.
2776  end if
2777  else if ( i0 == ieg .and. j0 /= jeg ) then
2778  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2779  & grd%mask(1,j0,k0) == 0.0 .or.&
2780  & grd%mask(i0,j0+1,k0) == 0.0 .or.&
2781  & grd%mask(1,j0+1,k0) == 0.0 ) then
2782  profiles(num_profiles)%flag(k) = .false.
2783  end if
2784  else if ( i0 /= ieg .and. j0 == jeg ) then
2785  if ( grd%mask(i0,j0,k0) == 0.0 .or.&
2786  & grd%mask(i0+1,j0,k0) == 0.0 ) then
2787  profiles(num_profiles)%flag(k) = .false.
2788  end if
2789  else
2790  if ( grd%mask(i0,j0,k0) == 0.0 ) then
2791  profiles(num_profiles)%flag(k) = .false.
2792  end if
2793  end if
2794 
2795  if ( i0 /= ieg .and. j0 /= jeg ) then
2796  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2797  & grd%mask(i0+1,j0,k0+1) == 0.0 .or.&
2798  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
2799  & grd%mask(i0+1,j0+1,k0+1) == 0.0 ) then
2800  profiles(num_profiles)%flag(k) = .false.
2801  end if
2802  elseif ( i0 == ieg .and. j0 /= jeg ) then
2803  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2804  & grd%mask(1,j0,k0+1) == 0.0 .or.&
2805  & grd%mask(i0,j0+1,k0+1) == 0.0 .or.&
2806  & grd%mask(1,j0+1,k0+1) == 0.0 ) then
2807  profiles(num_profiles)%flag(k) = .false.
2808  end if
2809  else if ( i0 /= ieg .and. j0 == jeg ) then
2810  if ( grd%mask(i0,j0,k0+1) == 0.0 .or.&
2811  & grd%mask(i0+1,j0,k0+1) == 0.0 ) then
2812  profiles(num_profiles)%flag(k) = .false.
2813  end if
2814  else
2815  if ( grd%mask(i0,j0,k0+1) == 0.0 ) then
2816  profiles(num_profiles)%flag(k) = .false.
2817  end if
2818  end if
2819 
2820  if ( abs(profiles(num_profiles)%data(k)) > 1.e4 &
2821  & .or. abs(profiles(num_profiles)%depth(k)) > 1.e4 ) then
2822  profiles(num_profiles)%flag(k) = .false.
2823  end if
2824  end if ! flag
2825  end if ! snz add
2826  end do
2827  end if ! accepted
2828  end if ! localize
2829  end if ! global index
2830  end do
2831  end do
2832 
2833  call mpp_close(unit)
2834  deallocate(axes)
2835  write (unit=stdout_unit, fmt='("A grand total of ",I8," woa05s points within global domain")') no_woa05
2836  write (unit=stdout_unit, fmt='("A final total @woa05s of ",I8," prfs within global domain")') num_profiles
2837 
2838 ! call mpp_print_memuse_stats('open_profile_dataset_woa05s Ens')
2839 
2840  end subroutine open_profile_dataset_woa05s
2841 
2842  subroutine get_obs_sst(model_time, Prof, nprof, no_prf0, sst_climo, Filter_domain)
2843  type(time_type), intent(in) :: model_time
2844  type(ocean_profile_type), dimension(:), intent(inout) :: prof
2845  integer, intent(inout) :: nprof
2846  integer, intent(in) :: no_prf0
2847  type(obs_clim_type), intent(inout) :: sst_climo
2848  type(domain2d), intent(in) :: filter_domain
2849 
2850  integer :: i0, j0, i, days, seconds, days1, seconds1
2851  integer :: unit, ndim, nvar, natt, ntime, time_idx
2852  integer :: iy0, in0, id0, ih0, im0, is0, i_m
2853  integer :: stdout_unit, istat
2854  integer, dimension(12) :: n_days
2855  integer, save :: year_on_first_read = 0 !< Year on first read of file during
2856  !! module run
2857  character(len=128) :: sst_filename, emsg_local
2858 
2859  type(fieldtype), dimension(:), allocatable :: fields
2860  type(time_type) :: tdiff, sst_time0, time1
2861 
2862  n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
2863 
2864  nprof = 0
2865 
2866  stdout_unit = stdout()
2867 
2868  call get_time(model_time, seconds, days)
2869  call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
2870  if ( year_on_first_read == 0 ) then
2871  year_on_first_read = iy0
2872  end if
2873  time1=set_date(year_on_first_read, 1, 1, 0, 0, 0)
2874  call get_time(time1, seconds1, days1)
2875  time_idx = days-days1+1
2876 
2877  ! daily data
2878 
2879  if ( mpp_pe() == mpp_root_pe() ) then
2880  write (unit=stdout_unit, fmt='("time_idx = ",I8)') time_idx
2881  end if
2882 
2883  sst_filename = "INPUT/sst_daily.nc"
2884 
2885  call mpp_open(unit, trim(sst_filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2886  call mpp_get_info(unit, ndim, nvar, natt, ntime)
2887 
2888  allocate(fields(nvar), stat=istat)
2889  if ( istat .ne. 0 ) then
2890  call error_mesg('oda_core_mod::get_obs_sst', 'Unable to allocate fields', fatal)
2891  end if
2892 
2893  call mpp_get_fields(unit, fields)
2894  do i=1, nvar
2895  select case ( mpp_get_field_name(fields(i)) )
2896  case ('SST1') ! for AVHRR daily SST
2897  call mpp_read(unit, fields(i), filter_domain, sst_climo%sst_obs, tindex=time_idx)
2898  end select
2899  end do
2900 
2901  ! get profiles and sst
2902  ! obs relevant to current analysis interval
2903  sst_time0 = set_date(iy0, in0, id0, ih0, im0, is0)
2904 
2905  if ( no_sst > 1 ) then
2906 
2908  profiles(i)%time = sst_time0
2909 
2910  tdiff = model_time - profiles(i)%time
2911 
2912  i0 = floor(profiles(i)%i_index)
2913  if ( i0 < 1 .or. i0 > 1440 ) then
2914  write (unit=emsg_local, fmt='("Profiles(",I8,")%lon = ",I4,", i0 = ",I8)') i, profiles(i)%lon, i0
2915  call error_mesg('oda_core_mod::get_obs_sst',&
2916  & 'Profile longitude index outside range [1,1440]. '//trim(emsg_local), fatal)
2917  end if
2918 
2919  j0 = floor(profiles(i)%j_index)
2920  if ( j0 < 1 .or. j0 > 1070 ) then
2921  write (unit=emsg_local, fmt='("Profiles(",I8,")%lat = ",I4,", j0 = ",I8)') i, profiles(i)%lon, j0
2922  call error_mesg('oda_core_mod::get_obs_sst',&
2923  & 'Profile latitude index outside range [1,1070]. '//trim(emsg_local), fatal)
2924  end if
2925 
2926  if ( profiles(i)%accepted ) then
2927  nprof = nprof + 1
2928  if ( nprof > size(prof,1) ) then
2929  call error_mesg('oda_core_mod::get_obs_sst',&
2930  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call.',&
2931  & fatal)
2932  end if
2933 
2934  call copy_obs(profiles(i:i), prof(no_prf0+nprof:no_prf0+nprof))
2935 
2936  prof(nprof+no_prf0)%tdiff = tdiff
2937  end if
2938  end do
2939 
2940  end if ! for no_sst > 1
2941 
2942  if ( mpp_pe() == mpp_root_pe() ) then
2943  write (unit=stdout_unit, fmt='("no of sst records: ",I8)') nprof
2944  end if
2945 
2946  deallocate(fields)
2947  call mpp_close(unit)
2948  end subroutine get_obs_sst
2949 
2950  subroutine get_obs_woa05t(model_time, Prof, nprof, no_prf0)
2951  type(time_type), intent(in) :: model_time
2952  type(ocean_profile_type), dimension(:), intent(inout) :: prof
2953  integer, intent(inout) :: nprof
2954  integer, intent(in) :: no_prf0
2955 
2956  real :: ri0, rj0, lon_woa05
2957 
2958  integer :: i0, j0
2959  integer :: i, k, unit, time_idx
2960  integer :: iy0, in0, id0, ih0, im0, is0
2961  integer :: ndim, nvar, natt, ntime
2962  integer :: stdout_unit, istat
2963 
2964  character(len=32) :: axisname
2965  character(len=128) :: woa05t_filename
2966 
2967  type(fieldtype), dimension(:), allocatable :: fields
2968  type(time_type) :: tdiff, woa05_time0
2969 
2970  nprof = 0
2971  stdout_unit = stdout()
2972 
2973  call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
2974 
2975  time_idx = in0
2976 
2977  ! daily data
2978  woa05t_filename = "INPUT/woa05_temp.nc"
2979 
2980  call mpp_open(unit, trim(woa05t_filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2981  call mpp_get_info(unit, ndim, nvar, natt, ntime)
2982 
2983  allocate(fields(nvar), stat=istat)
2984  if ( istat .ne. 0 ) then
2985  call error_mesg('oda_core_mod::get_obs_woa05t', 'Unable to allocate fields', fatal)
2986  end if
2987 
2988  call mpp_get_fields(unit, fields)
2989 
2991 
2992  do i=1, nvar
2993  select case ( mpp_get_field_name(fields(i)) )
2994  case ('t0112an1')
2995  call mpp_read(unit, fields(i), obs_woa05t, tindex=time_idx)
2996  end select
2997  end do
2998 
2999  woa05_time0 = set_date(iy0, in0, id0, ih0, im0, is0)
3000 
3001  do i=no_prf+1, no_prf+no_woa05/2
3002  profiles(i)%time = woa05_time0
3003 
3004  tdiff = model_time - profiles(i)%time
3005 
3006  lon_woa05 = profiles(i)%lon
3007  if ( lon_woa05 < 0.0 ) lon_woa05 = lon_woa05 + 360.0
3008  if ( lon_woa05 > 360.0 ) lon_woa05 = lon_woa05 - 360.0
3009  ri0 = frac_index(lon_woa05, woa05_lon)
3010  i0 = floor(ri0)
3011  if ( i0 < 1 ) i0 = 1
3012  if ( i0 > nlon_woa ) i0 = nlon_woa
3013 
3014  rj0 = frac_index(profiles(i)%lat, woa05_lat)
3015  j0 = floor(rj0)
3016  if(j0 < 1 ) j0 = 1
3017  if(j0 > nlat_woa) j0 = nlat_woa
3018 
3019  if ( profiles(i)%accepted ) then
3020  nprof = nprof + 1
3021  if ( nprof > size(prof,1) ) then
3022  call error_mesg('oda_core_mod::get_obs_woa05t',&
3023  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call.',&
3024  & fatal)
3025  end if
3026  profiles(i)%data(1:nlev_woa) = obs_woa05t(i0,j0,1:nlev_woa)
3027  do k=1, nlev_woa
3028  if ( abs(profiles(i)%data(k)) > 1.e3 .or.&
3029  & abs(profiles(i)%depth(k)) > 1.e5 ) then
3030  profiles(i)%flag(k) = .false.
3031  end if
3032  end do
3033  call copy_obs(profiles(i:i), prof(no_prf0+nprof:no_prf0+nprof))
3034  prof(no_prf0+nprof)%tdiff = tdiff
3035  end if
3036  end do
3037 
3038  if ( mpp_pe() == mpp_root_pe() ) then
3039  write (unit=stdout_unit, fmt='("no of woa05t records: ",I8)') nprof
3040  end if
3041 
3042  deallocate(fields, obs_woa05t)
3043  call mpp_close(unit)
3044  end subroutine get_obs_woa05t
3045 
3046  subroutine get_obs_woa05s(model_time, Prof, nprof, no_prf0)
3047  type(time_type), intent(in) :: model_time
3048  type(ocean_profile_type), dimension(:), intent(inout) :: prof
3049  integer, intent(inout) :: nprof
3050  integer, intent(in) :: no_prf0
3051 
3052  real :: ri0, rj0, lon_woa05
3053 
3054  integer :: i0, j0
3055  integer :: i, k, unit, time_idx
3056  integer :: iy0, in0, id0, ih0, im0, is0
3057  integer :: ndim, nvar, natt, ntime
3058  integer :: stdout_unit, istat
3059 
3060  character(len=128) :: woa05s_filename
3061 
3062  type(fieldtype), dimension(:), allocatable :: fields
3063  type(time_type) :: tdiff, woa05_time0
3064 
3065  nprof = 0
3066  stdout_unit = stdout()
3067 
3068  call get_date(model_time, iy0,in0,id0,ih0,im0,is0)
3069 
3070  time_idx = in0
3071 
3072  ! climatological data
3073  woa05s_filename = "INPUT/woa05_salt.nc"
3074 
3075  call mpp_open(unit, trim(woa05s_filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
3076  call mpp_get_info(unit, ndim, nvar, natt, ntime)
3077 
3078  allocate(fields(nvar), stat=istat)
3079  if ( istat .ne. 0 ) then
3080  call error_mesg('oda_core_mod::get_obs_woa05s', 'Unable to allocate fields', fatal)
3081  end if
3082 
3083  call mpp_get_fields(unit, fields)
3084 
3086 
3087  do i=1, nvar
3088  select case ( mpp_get_field_name(fields(i)) )
3089  case ('s0112an1')
3090  call mpp_read(unit, fields(i), obs_woa05s, tindex=time_idx)
3091  end select
3092  end do
3093 
3094  woa05_time0 = set_date(iy0, in0, id0, ih0, im0, is0)
3095 
3096  do i=no_prf+no_woa05/2+1, no_prf+no_woa05
3097  profiles(i)%time = woa05_time0
3098 
3099  tdiff = model_time - profiles(i)%time
3100 
3101  lon_woa05 = profiles(i)%lon
3102  if ( lon_woa05 < 0.0 ) lon_woa05 = lon_woa05 + 360.0
3103  if ( lon_woa05 > 360.0 ) lon_woa05 = lon_woa05 - 360.0
3104  ri0 = frac_index(lon_woa05, woa05_lon)
3105  i0 = floor(ri0)
3106  if ( i0 < 1 ) i0 = 1
3107  if ( i0 > nlon_woa ) i0 = nlon_woa
3108 
3109  rj0 = frac_index(profiles(i)%lat, woa05_lat)
3110  j0 = floor(rj0)
3111  if ( j0 < 1 ) j0 = 1
3112  if ( j0 > nlat_woa ) j0 = nlat_woa
3113 
3114  if ( profiles(i)%accepted ) then
3115  nprof = nprof + 1
3116  if ( nprof > size(prof,1) ) then
3117  call error_mesg('oda_core_mod::get_obs_woa05s',&
3118  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call',&
3119  & fatal)
3120  end if
3121  profiles(i)%data(1:nlev_woa) = obs_woa05s(i0,j0,1:nlev_woa)
3122  do k=1, nlev_woa
3123  if ( abs(profiles(i)%data(k)) > 1.e3 .or.&
3124  & abs(profiles(i)%depth(k)) > 1.e5 ) then
3125  profiles(i)%flag(k) = .false.
3126  end if
3127  end do
3128  call copy_obs(profiles(i:i),prof(no_prf0+nprof:no_prf0+nprof))
3129  prof(no_prf0+nprof)%tdiff = tdiff
3130  end if
3131  end do
3132 
3133  if ( mpp_pe() == mpp_root_pe() ) then
3134  write (unit=stdout_unit, fmt='("no of woa05t records: ",I8)') nprof
3135  end if
3136 
3137  deallocate(fields, obs_woa05s)
3138  call mpp_close(unit)
3139  end subroutine get_obs_woa05s
3140 
3141  subroutine open_profile_dataset_eta(filename, obs_variable, localize)
3142  character(len=*), intent(in) :: filename
3143  integer, intent(in) :: obs_variable
3144  logical, intent(in), optional :: localize
3145 
3146  integer, parameter :: MAX_LEVELS = 1000
3147 
3148  real :: lon, lat, rms_err
3149  real :: ri0, rj0
3150  real, dimension(MAX_LEVELS) :: depth, data
3151 
3152  integer :: inst_type, var_id
3153  integer :: num_levs, k, kk, i, j, i0, j0
3154  integer :: stdout_unit
3155 
3156  logical :: data_is_local, localize_data
3157  logical, dimension(MAX_LEVELS) :: flag
3158 
3159  character(len=32) :: anal_fldname
3160 
3161  if ( PRESENT(localize) ) then
3162  localize_data = localize
3163  else
3164  localize_data = .true.
3165  end if
3166 
3167  stdout_unit = stdout()
3168 
3169  anal_fldname = 'eta'
3170  var_id = obs_variable
3171 
3172  !snz idealized
3173  do j=1, size(x_grid, dim=1)
3174  do i=1, size(x_grid, dim=2)
3175  lon = x_grid(i,j)
3176  lat = y_grid(i,j)
3177  rms_err = 0.5
3178 
3179  inst_type = 20
3180  data_is_local = .true.
3181 
3182  if ( lon .lt. 0.0 ) lon = lon + 360.0
3183  if ( lon .gt. 360.0 ) lon = lon - 360.0
3184  if ( lon .lt. 80.0 ) lon = lon + 360.0
3185 
3186  if ( lat < eta_obs_start_lat .or. lat > eta_obs_end_lat ) data_is_local = .false.
3187  if ( abs(lat) < 20.0 .and.&
3188  & (mod(floor(lon),2) /= 0 .or. mod(floor(lat),2) /= 0) ) data_is_local = .false.
3189  if ( (abs(lat) >= 20.0 .and. abs(lat) < 40.0) .and.&
3190  & (mod(floor(lon),4) /= 0 .or. mod(floor(lat),4) /= 0) ) data_is_local = .false.
3191  if ( (abs(lat) >= 40.0) .and.&
3192  & (mod(floor(lon),6) /= 0 .or. mod(floor(lat),6) /= 0) ) data_is_local = .false.
3193 
3194  if ( data_is_local .and. (.NOT.localize_data) ) then
3195  ri0 = frac_index(lon, x_grid(:,1))
3196  rj0 = frac_index(lat, y_grid(90,:))
3197  i0 = floor(ri0)
3198  j0 = floor(rj0)
3199  if ( grd%mask(i0,j0,1) /= 0.0 .and. grd%mask(i0+1,j0,1) /= 0.0 .and.&
3200  & grd%mask(i0,j0+1,1) /= 0.0 .and. grd%mask(i0+1,j0+1,1) /= 0.0 ) then
3201  no_eta = no_eta+1
3203  if ( num_profiles > max_profiles ) then
3204  call error_mesg('oda_core_mod::open_profile_dataset_eta',&
3205  & 'Maximum number of profiles exceeded, increase max_profiles in oda_core_nml.', fatal)
3206  end if
3207 
3208 
3209  num_levs = 0
3210  flag = .false.
3211  do k=1, 1
3212  flag(k) = .true.
3213  data(k) = 0.0
3214  depth(k) = 0.0
3215  num_levs = num_levs+1
3216  end do
3217  if ( num_levs == 0 ) cycle
3218  allocate(profiles(num_profiles)%depth(num_levs))
3219  allocate(profiles(num_profiles)%data(num_levs))
3220  allocate(profiles(num_profiles)%flag(num_levs))
3221  allocate(profiles(num_profiles)%ms(num_levs))
3222  allocate(profiles(num_profiles)%ms_inv(num_levs))
3223  profiles(num_profiles)%variable = var_id
3224  profiles(num_profiles)%inst_type = inst_type
3225  profiles(num_profiles)%levels = num_levs
3226  profiles(num_profiles)%lat = lat
3227  profiles(num_profiles)%lon = lon
3228  kk = 1
3229  do k=1, 1
3230  if ( flag(k) ) then
3231  profiles(num_profiles)%depth(kk) = depth(k)
3232  profiles(num_profiles)%data(kk) = data(k)
3233  profiles(num_profiles)%ms(kk) = 1.0
3234  profiles(num_profiles)%ms_inv(kk) = 1.0
3235  kk = kk + 1
3236  end if
3237  end do
3238 
3239  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
3240  profiles(num_profiles)%i_index = ri0
3241  profiles(num_profiles)%j_index = rj0
3242  profiles(num_profiles)%accepted = .true.
3243  if ( i0 < 1 .or. j0 < 1 ) then
3244  profiles(num_profiles)%accepted = .false.
3245  end if
3246  if ( profiles(num_profiles)%accepted ) then
3247  if ( grd%mask(i0,j0,1) == 0.0 .or.&
3248  & grd%mask(i0+1,j0,1) == 0.0 .or.&
3249  & grd%mask(i0,j0+1,1) == 0.0 .or.&
3250  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
3251  profiles(num_profiles)%accepted = .false.
3252  end if
3253  end if
3254  if ( profiles(num_profiles)%accepted ) then
3255  profiles(num_profiles)%flag(:) = .true.
3256  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
3257  do k=1, profiles(num_profiles)%levels
3258  if (depth(k) < grd%z(1)) then
3259  profiles(num_profiles)%k_index(k) = 0.0
3260  else
3261  profiles(num_profiles)%k_index(k) = frac_index(depth(k), (/0.,grd%z(:)/)) - 1
3262  end if
3263  if ( profiles(num_profiles)%k_index(k) < 1.0 ) profiles(num_profiles)%flag(k) = .false.
3264  end do
3265  end if
3266  end if
3267  end if
3268  end do
3269  end do
3270 
3271  write (unit=stdout_unit, fmt='("A grand total of ",I8," eta points within global domain")') no_eta
3272  write (unit=stdout_unit, fmt='("A final total @eta of ",I8," prfs within global domain")') num_profiles
3273  end subroutine open_profile_dataset_eta
3274 
3275  subroutine open_profile_dataset_suv(filename, obs_variable, localize)
3276  character(len=*), intent(in) :: filename
3277  integer, intent(in) :: obs_variable
3278  logical, intent(in), optional :: localize
3279 
3280  integer, parameter :: MAX_LEVELS = 1000
3281 
3282  real :: ri0, rj0
3283  real :: lon, lat, rms_err
3284  real, dimension(MAX_LEVELS) :: depth, data
3285 
3286  integer :: inst_type, var_id
3287  integer :: num_levs, k, kk, i, j, i0, j0
3288  integer :: stdout_unit
3289 
3290  logical :: data_is_local, localize_data
3291  logical, dimension(MAX_LEVELS) :: flag
3292 
3293  character(len=32) :: anal_fldname
3294 
3295  if ( PRESENT(localize) ) then
3296  localize_data = localize
3297  else
3298  localize_data = .true.
3299  end if
3300 
3301  stdout_unit = stdout()
3302 
3303  anal_fldname = 'suv'
3304  var_id = obs_variable
3305 
3306  !snz idealized
3307  do j=1, size(x_grid_uv,dim=1)
3308  do i=1, size(x_grid_uv,dim=2)
3309  lon = x_grid_uv(i,j)
3310  lat = y_grid_uv(i,j)
3311  rms_err = 0.5
3312 
3313  inst_type = 20
3314  data_is_local = .true.
3315 
3316  if ( lon .lt. 0.0 ) lon = lon + 360.0
3317  if ( lon .gt. 360.0 ) lon = lon - 360.0
3318  if ( lon .lt. 80.0 ) lon = lon + 360.0
3319 
3320  if ( lat < -40.0 .or. lat > 40.0 ) data_is_local = .false.
3321  if ( abs(lat) < 20.0 .and.&
3322  & (mod(floor(lon),2) /= 0 .or. mod(floor(lat),2) /= 0) ) data_is_local = .false.
3323  if ( (abs(lat) >= 20.0 .and. abs(lat) < 40.0) .and.&
3324  & (mod(floor(lon),4) /= 0 .or. mod(floor(lat),4) /= 0) ) data_is_local = .false.
3325  if ( (abs(lat) >= 40.0) .and.&
3326  & (mod(floor(lon),6) /= 0 .or. mod(floor(lat),6) /= 0) ) data_is_local = .false.
3327 
3328  if ( data_is_local .and. (.NOT.localize_data) ) then
3329  ri0 = frac_index(lon, x_grid_uv(:,1))
3330  rj0 = frac_index(lat, y_grid_uv(90,:))
3331  i0 = floor(ri0)
3332  j0 = floor(rj0)
3333  if ( grd%mask(i0,j0,1) /= 0.0 .and. grd%mask(i0+1,j0,1) /= 0.0 .and.&
3334  & grd%mask(i0,j0+1,1) /= 0.0 .and. grd%mask(i0+1,j0+1,1) /= 0.0 ) then
3335  no_suv = no_suv+1
3337  if ( num_profiles > max_profiles ) then
3338  call error_mesg('oda_core_mod::open_profile_dataset_suv',&
3339  & 'Maximum number of profiles exceeded, increase max_profiles in oda_core_nml.', fatal)
3340  end if
3341 
3342 
3343  num_levs = 0
3344  flag = .false.
3345  do k=1, 2
3346  flag(k) = .true.
3347  data(k) = 0.0
3348  depth(k) = 0.0
3349  num_levs = num_levs + 1
3350  end do
3351  if ( num_levs == 0 ) cycle
3352  allocate(profiles(num_profiles)%depth(num_levs))
3353  allocate(profiles(num_profiles)%data(num_levs))
3354  allocate(profiles(num_profiles)%flag(num_levs))
3355  allocate(profiles(num_profiles)%ms(num_levs))
3356  allocate(profiles(num_profiles)%ms_inv(num_levs))
3357  profiles(num_profiles)%variable = var_id
3358  profiles(num_profiles)%inst_type = inst_type
3359  profiles(num_profiles)%levels = num_levs
3360  profiles(num_profiles)%lat = lat
3361  profiles(num_profiles)%lon = lon
3362  kk = 1
3363  do k=1, 2
3364  if ( flag(k) ) then
3365  profiles(num_profiles)%depth(kk) = depth(k)
3366  profiles(num_profiles)%data(kk) = data(k)
3367  profiles(num_profiles)%ms(kk) = 1.0
3368  profiles(num_profiles)%ms_inv(kk) = 1.0
3369  kk = kk + 1
3370  end if
3371  end do
3372 
3373  ! calculate interpolation coefficients (make sure to account for grid offsets here!)
3374  profiles(num_profiles)%i_index = ri0
3375  profiles(num_profiles)%j_index = rj0
3376  profiles(num_profiles)%accepted = .true.
3377  if ( i0 < 1 .or. j0 < 1 ) then
3378  profiles(num_profiles)%accepted = .false.
3379  end if
3380  if ( profiles(num_profiles)%accepted ) then
3381  if ( grd%mask(i0,j0,1) == 0.0 .or.&
3382  & grd%mask(i0+1,j0,1) == 0.0 .or.&
3383  & grd%mask(i0,j0+1,1) == 0.0 .or.&
3384  & grd%mask(i0+1,j0+1,1) == 0.0 ) then
3385  profiles(num_profiles)%accepted = .false.
3386  end if
3387  end if
3388  if ( profiles(num_profiles)%accepted ) then
3389  profiles(num_profiles)%flag(:) = .true.
3390  allocate(profiles(num_profiles)%k_index(profiles(num_profiles)%levels))
3391  do k=1, profiles(num_profiles)%levels
3392  if (depth(k) < grd%z(1)) then
3393  profiles(num_profiles)%k_index(k) = 0.0
3394  else
3395  profiles(num_profiles)%k_index(k) = frac_index(depth(k), (/0.,grd%z(:)/)) - 1.0 ! snz modify to v3.2 JAN3012
3396  end if
3397  if ( profiles(num_profiles)%k_index(k) < 1.0 ) profiles(num_profiles)%flag(k) = .false.
3398  end do
3399  end if
3400  end if
3401  end if
3402  end do
3403  end do
3404 
3405  write (unit=stdout_unit, fmt='("A grand total of ",I8," suv points within global domain")') no_suv
3406  write (unit=stdout_unit, fmt='("A final total @suv of ",I8," prfs within global domain")') num_profiles
3407  end subroutine open_profile_dataset_suv
3408 
3409  subroutine get_obs_suv(model_time, Prof, nprof, no_prf0)
3410  type(time_type), intent(in) :: model_time
3411  type(ocean_profile_type), dimension(:), intent(inout) :: prof
3412  integer, intent(inout) :: nprof
3413  integer, intent(in) :: no_prf0
3414 
3415  ! get sst data and put into profiles
3416  ! only current day
3417 
3418  real :: sfc_lon, sfc_lat, ri0, rj0
3419  real, dimension(1440,1070,1) :: sfc_u, sfc_v
3420 
3421  integer :: i, k, i_m, i0, j0
3422  integer :: unit, time_idx, ndim, nvar, natt, ntime
3423  integer :: iy0, in0, id0, ih0, im0, is0
3424  integer :: stdout_unit, istat
3425  integer, dimension(12) :: n_days
3426 
3427  character(len=80) :: sfc_filename
3428  character(len=256) :: emsg_local
3429 
3430  type(fieldtype), dimension(:), allocatable :: fields
3431  type(time_type) :: tdiff, sfc_time0
3432 
3433  n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
3434  nprof = 0
3435  stdout_unit = stdout()
3436 
3437  call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
3438 
3439  !monthly
3440 !!$ time_idx = (iy0-1984)*12+in0
3441  ! daily
3442  if ( in0 == 1 ) then
3443  time_idx = (iy0-1984)*365 + id0
3444  else
3445  time_idx = 0
3446  do i_m=1, in0-1
3447  time_idx = time_idx + (iy0-1984)*365 + n_days(i_m)
3448  end do
3449  time_idx = time_idx + id0
3450  end if
3451 
3452  if ( mpp_pe() == mpp_root_pe() ) then
3453  write (unit=stdout_unit, fmt='("time_idx = ",I8)') time_idx
3454  end if
3455 
3456  sfc_time0 = set_date(iy0, in0, id0, ih0, im0, is0)
3457 
3458  sfc_filename = "INPUT/sfc_current.198401-198412.nc"
3459 
3460  call mpp_open(unit, trim(sfc_filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
3461  call mpp_get_info(unit, ndim, nvar, natt, ntime)
3462 
3463  allocate(fields(nvar), stat=istat)
3464  if ( istat .ne. 0 ) then
3465  call error_mesg('oda_core_mod::get_obs_sst', 'Unable to allocate fields', fatal)
3466  end if
3467 
3468  call mpp_get_fields(unit, fields)
3469  do i=1, nvar
3470  select case ( mpp_get_field_name(fields(i)) )
3471  case ('U_SFC')
3472  call mpp_read(unit, fields(i), sfc_u, tindex=time_idx)
3473  case ('V_SFC')
3474  call mpp_read(unit, fields(i), sfc_v, tindex=time_idx)
3475  end select
3476  end do
3477 
3479  profiles(i)%time = sfc_time0
3480 
3481  tdiff = model_time - profiles(i)%time
3482 
3483  sfc_lon = profiles(i)%lon
3484  ri0 = frac_index(sfc_lon, x_grid_uv(:,1))
3485  i0 = floor(ri0)
3486  if ( i0 < 1 .or. i0 > 1440 ) then
3487  write (unit=emsg_local, fmt='("Profiles(",I8,")%lon = ",I4,", i0 = ",I8)') i, profiles(i)%lon, i0
3488  call error_mesg('oda_core_mod::get_obs_suv',&
3489  & 'Profile longitude index outside range [1,1440]. '//trim(emsg_local), fatal)
3490  end if
3491 
3492  sfc_lat = profiles(i)%lat
3493  rj0 = frac_index(sfc_lat, y_grid_uv(90,:))
3494  j0 = floor(rj0)
3495  if ( j0 < 1 .or. j0 > 1070 ) then
3496  write (unit=emsg_local, fmt='("Profiles(",I8,")%lat = ",I4,", j0 = ",I8)') i, profiles(i)%lon, j0
3497  call error_mesg('oda_core_mod::get_obs_suv',&
3498  & 'Profile latitude index outside range [1,1070]. '//trim(emsg_local), fatal)
3499  end if
3500 
3501  if ( profiles(i)%accepted ) then
3502  nprof = nprof + 1
3503  if ( nprof > size(prof,1) ) then
3504  call error_mesg('oda_core_mod::get_obs_suv',&
3505  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call',&
3506  & fatal)
3507  end if
3508  profiles(i)%data(1) = sfc_u(i0,j0,1)
3509  profiles(i)%data(2) = sfc_v(i0,j0,1)
3510 
3511  call copy_obs(profiles(i:i),prof(nprof+no_prf0:nprof+no_prf0))
3512 
3513  prof(nprof+no_prf0)%tdiff = tdiff
3514  end if
3515  end do
3516 
3517  deallocate(fields)
3518  call mpp_close(unit)
3519  end subroutine get_obs_suv
3520 
3521  subroutine get_obs_eta(model_time, Prof, nprof, no_prf0)
3522  type(time_type), intent(in) :: model_time
3523  type(ocean_profile_type), dimension(:), intent(inout) :: prof
3524  integer, intent(inout) :: nprof
3525  integer, intent(in) :: no_prf0
3526 
3527  ! get sst data and put into profiles
3528  ! only current day
3529 
3530  real :: eta_lon, eta_lat, ri0, rj0
3531  real, dimension(1440,1070) :: eta_t
3532 
3533  integer :: i, i0, j0, i_m
3534  integer :: iy0, in0, id0, ih0, im0, is0
3535  integer :: unit, time_idx, ndim, nvar, natt, ntime
3536  integer :: stdout_unit, istat
3537  integer, dimension(12) :: n_days
3538 
3539  character(len=80) :: eta_filename
3540  character(len=256) :: emsg_local
3541 
3542  type(fieldtype), dimension(:), allocatable :: fields
3543  type(time_type) :: tdiff, sfc_time0
3544 
3545  n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
3546  nprof = 0
3547  stdout_unit = stdout()
3548 
3549  call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
3550 
3551  !monthly
3552 !!$ time_idx = (iy0-1984)*12+in0
3553  ! daily
3554  if ( in0 == 1 ) then
3555  time_idx = (iy0-1976)*365 + id0 - 1
3556  else
3557  time_idx = 0
3558  do i_m=1, in0-1
3559  time_idx = time_idx + n_days(i_m)
3560  end do
3561  time_idx = (iy0-1976)*365 + time_idx + id0 - 1
3562  end if
3563 
3564  if ( mpp_pe() == mpp_root_pe() ) then
3565  write (unit=stdout_unit, fmt='("time_idx = ",I8)') time_idx
3566  end if
3567 
3568  sfc_time0 = set_date(iy0, in0, id0, ih0, im0, is0)
3569 
3570  eta_filename='INPUT/ocean.19760101-20001231.eta_t.nc'
3571 
3572  call mpp_open(unit, trim(eta_filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
3573  call mpp_get_info(unit, ndim, nvar, natt, ntime)
3574 
3575  allocate(fields(nvar), stat=istat)
3576  if ( istat .ne. 0 ) then
3577  call error_mesg('oda_core_mod::get_obs_sst', 'Unable to allocate fields', fatal)
3578  end if
3579 
3580  call mpp_get_fields(unit, fields)
3581  do i=1, nvar
3582  select case ( mpp_get_field_name(fields(i)) )
3583  case ('eta_t')
3584  call mpp_read(unit, fields(i), eta_t, tindex=time_idx)
3585  end select
3586  end do
3587 
3588  do i=no_prf+no_sst+1, no_prf+no_sst+no_eta
3589  profiles(i)%time = sfc_time0
3590 
3591  tdiff = model_time - profiles(i)%time
3592 
3593  eta_lon = profiles(i)%lon
3594  ri0 = frac_index(eta_lon, x_grid(:,1))
3595  i0 = floor(ri0)
3596  if ( i0 < 1 .or. i0 > 1440 ) then
3597  write (unit=emsg_local, fmt='("Profiles(",I8,")%lon = ",I4,", i0 = ",I8)') i, profiles(i)%lon, i0
3598  call error_mesg('oda_core_mod::get_obs_eta',&
3599  & 'Profile longitude index outside range [1,1440]. '//trim(emsg_local), fatal)
3600  end if
3601 
3602  eta_lat = profiles(i)%lat
3603  rj0 = frac_index(eta_lat, y_grid(90,:))
3604  j0 = floor(rj0)
3605  if ( j0 < 1 .or. j0 > 1070 ) then
3606  write (unit=emsg_local, fmt='("Profiles(",I8,")%lat = ",I4,", j0 = ",I8)') i, profiles(i)%lon, j0
3607  call error_mesg('oda_core_mod::get_obs_suv',&
3608  & 'Profile latitude index outside range [1,1070]. '//trim(emsg_local), fatal)
3609  end if
3610 
3611  if ( profiles(i)%accepted ) then
3612  if ( eta_t(i0,j0) > -9.9 ) then !!! excluding missing values
3613  nprof = nprof + 1
3614  if ( nprof > size(prof,1) ) then
3615  call error_mesg('oda_core_mod::get_obs_eta',&
3616  & 'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call.',&
3617  & fatal)
3618  end if
3619  profiles(i)%data(1) = eta_t(i0,j0)
3620 
3621  call copy_obs(profiles(i:i),prof(nprof+no_prf0:nprof+no_prf0))
3622 
3623  prof(nprof+no_prf0)%tdiff = tdiff
3624  end if
3625  end if
3626  end do
3627 
3628  deallocate(fields)
3629  call mpp_close(unit)
3630  end subroutine get_obs_eta
3631 end module oda_core_ecda_mod
Definition: fms.F90:20
subroutine, public get_obs_sst(model_time, Prof, nprof, no_prf0, sst_climo, Filter_domain)
real, dimension(:, :), allocatable y_grid_uv
integer, parameter, public satellite
Definition: oda_types.F90:50
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
real max_misfit
used to inflate observation errors where the difference from the first guess is large ...
subroutine open_profile_dataset_suv(filename, obs_variable, localize)
integer, parameter, public drifter
Definition: oda_types.F90:51
type(horiz_interp_type), save interp
subroutine, public open_profile_dataset(filename, time_start, time_end, obs_variable, localize)
real, dimension(:, :), allocatable x_grid
real, dimension(:,:,:), allocatable, save obs_woa05s
subroutine, public get_obs_eta(model_time, Prof, nprof, no_prf0)
real, dimension(1, 1) lon_out
type(time_type) function, public get_cal_time(time_increment, units, calendar, permit_calendar_conversion)
real ass_end_lat
set obs domain
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
type(ocean_profile_type), dimension(:), allocatable, target profiles
real, dimension(:, :), allocatable x_grid_uv
integer, save, public salt_id
Definition: oda_types.F90:65
type(time_type), dimension(0:100), public time_window
real, dimension(:), allocatable woa05_lat
real eta_obs_start_lat
set obs domain
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
real, dimension(:), allocatable sst_lon
real, dimension(:), allocatable sst_lat
real, dimension(1, 1) lat_out
subroutine open_profile_dataset_woa05s(filename, obs_variable, localize)
subroutine open_profile_dataset_argo(filename, time_start, time_end, obs_variable, localize)
integer, parameter sfc_file
integer, save, public temp_id
Definition: oda_types.F90:64
subroutine, public get_obs_suv(model_time, Prof, nprof, no_prf0)
subroutine init_observations(time_s, time_e, filt_domain, localize)
subroutine, public oda_core_init(Domain, Grid, time_s, time_e, filt_domain, localize)
integer, public max_profiles
real ass_start_lat
set obs domain
integer, parameter, public ship
Definition: oda_types.F90:52
subroutine open_profile_dataset_eta(filename, obs_variable, localize)
subroutine, public mpp_print_memuse_stats(text, unit)
real sst_obs_start_lat
set obs domain
subroutine xbt_drop_rate_adjust(station)
real sst_obs_end_lat
set obs domain
subroutine, public get_obs_woa05t(model_time, Prof, nprof, no_prf0)
subroutine, public get_obs(model_time, Prof, nprof)
real, dimension(:,:,:), allocatable, save obs_woa05t
subroutine open_profile_dataset_gtspp()
integer, parameter, public mooring
Definition: oda_types.F90:49
integer, parameter, public unknown
Definition: oda_types.F90:53
subroutine, public open_profile_dataset_sst(filename, obs_variable, localize)
subroutine, public get_obs_woa05s(model_time, Prof, nprof, no_prf0)
real, dimension(:, :), allocatable y_grid
real, parameter, public missing_value
Definition: oda_types.F90:69
real, dimension(:), allocatable woa05_lon
integer, parameter, public drop_profiler
Definition: oda_types.F90:48
real eta_obs_end_lat
set obs domain
integer, parameter, public tao
moorings
Definition: oda_types.F90:54
integer, public ssh_td
real function, public frac_index(value, array)
Definition: axis_utils.F90:368
real, parameter, public deg_to_rad
Radians per degree [rad/deg].
Definition: constants.F90:120
real, dimension(:), allocatable woa05_z
integer, parameter profile_file
subroutine, public copy_obs(obs_in, obs_out)
subroutine open_profile_dataset_woa05t(filename, obs_variable, localize)
#define min(a, b)
Definition: mosaic_util.h:32
type(ocn_obs_flag_type), public ocn_obs
subroutine, public get_time(Time, seconds, days, ticks, err_msg)
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
real, dimension(:,:), allocatable, save mask_tao
Derived type containing the data.
type(grid_type), pointer grd
real, dimension(:,:), allocatable obs_sst