25 #ifdef INTERNAL_FILE_NML 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
32 use mpp_io_mod,
only : mpp_get_axis_data, mpp_get_field_name
38 use time_manager_mod,
only :
operator( <= ),
operator( - ),
operator( > ),
operator ( < )
89 real,
dimension(:,:),
allocatable,
save ::
mask_tao 114 character(len=128) :: filename
115 character(len=16) :: file_type
122 type(time_type),
intent(in) :: time_s, time_e
123 type(domain2d),
intent(in) :: filt_domain
124 logical,
intent(in),
optional :: localize
126 integer,
parameter :: SUV_ID = 4, eta_id = 5, woat_id = 11, woas_id = 12
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
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
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
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
167 type(obs_entry_type) :: tbl_entry
169 stdout_unit = stdout()
170 stdlog_unit = stdlog()
172 #ifdef INTERNAL_FILE_NML 173 read (input_nml_file, ocean_obs_nml, iostat=io_status)
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)
180 write (unit=stdlog_unit, nml=ocean_obs_nml)
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))
191 input_files_argo =
'' 192 input_files_gtspp =
'' 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.
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
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 220 else if ( io_status > 0 )
then 224 if ( record(1:1) ==
'#' ) cycle read_obs
225 read ( unit=record, fmt=*, iostat=io_status ) tbl_entry
226 if ( io_status < 0 )
then 228 else if ( io_status > 0 )
then 232 input_files(nfiles) = tbl_entry%filename
233 select case ( trim(tbl_entry%file_type) )
239 call error_mesg(
'oda_core_mod::init_observations',
'error in obs_table entry format', fatal)
244 if ( nfiles > max_files )
then 245 call error_mesg(
'oda_core_mod::init_observations',
'number of obs files exceeds max_files parameter', fatal)
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 256 else if ( io_status > 0 )
then 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 264 else if ( io_status > 0 )
then 267 nfiles_argo = nfiles_argo + 1
268 input_files_argo(nfiles_argo) = tbl_entry%filename
269 select case ( trim(tbl_entry%file_type) )
273 filetype_argo(nfiles_argo) =
sfc_file 275 call error_mesg(
'oda_core_mod::init_observations',
'error in obs_table entry format for argo', fatal)
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)
283 call mpp_close(unit_argo)
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 292 else if ( io_status > 0 )
then 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 300 else if ( io_status > 0 )
then 303 nfiles_gtspp = nfiles_gtspp + 1
304 input_files_gtspp(nfiles_gtspp) = tbl_entry%filename
305 select case ( trim(tbl_entry%file_type) )
309 filetype_gtspp(nfiles_gtspp) =
sfc_file 311 call error_mesg(
'oda_core_mod::init_observations',
'error in obs_table entry format for gtspp', fatal)
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)
319 CALL mpp_close(unit_gtspp)
358 obs_variable = temp_id
359 if ( mpp_pe() == mpp_root_pe() )
then 360 write (unit=stdout_unit, fmt=
'("TEMP_ID = ",I5)') temp_id
367 call error_mesg(
'oda_core_mod::init_observations',
'filetype not currently supported for prfs_obs', fatal)
373 obs_variable = salt_id
374 if ( mpp_pe() == mpp_root_pe() )
then 375 write (unit=stdout_unit, fmt=
'("SALT_ID = ",I5)') salt_id
382 call error_mesg(
'oda_core_mod::init_observations',
'filetype not currently supported for salt_obs', fatal)
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
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)
397 select case ( filetype_gtspp(n) )
401 call error_mesg(
'oda_core_mod::init_observations',
'filetype_gtspp not currently supported', fatal)
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
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)
416 select case ( filetype_argo(n) )
420 call error_mesg(
'oda_core_mod::init_observations',
'filetype_argo not currently supported', fatal)
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
431 select case ( filetype_argo(n) )
435 call error_mesg(
'oda_core_mod::init_observations',
'filetype_argo not currently supported', fatal)
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
445 input_files_woa05t =
"INPUT/woa05_temp.nc" 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
454 input_files_woa05s =
"INPUT/woa05_salt.nc" 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
465 input_files(nfiles) =
"INPUT/sst_daily.nc" 471 obs_variable = eta_id
474 input_files(nfiles) =
"INPUT/ocean.19760101-20001231.eta_t.nc" 480 obs_variable = suv_id
483 input_files(nfiles) =
"INPUT/sfc_current.197601-200012.nc" 490 deallocate(filetype_argo, input_files_argo)
491 deallocate(filetype_gtspp, input_files_gtspp)
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
500 integer,
parameter :: max_levels = 1000
501 integer,
parameter :: max_lnks = 500
503 real :: lon, lat, time, profile_error, rlink, flag_t, flag_s, fix_depth
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
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
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
521 character(len=32) :: fldname, axisname, anal_fldname, time_units
522 character(len=138) :: emsg_local
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
533 if (
PRESENT(localize) )
then 534 localize_data = localize
536 localize_data = .true.
539 nprof_in_filt_domain = 0
540 stdout_unit = stdout()
542 anal_fldname =
'none' 544 if ( obs_variable == temp_id )
then 545 anal_fldname =
'temp' 547 else if ( obs_variable == salt_id )
then 548 anal_fldname =
'salt' 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)
557 if ( mpp_pe() .eq. mpp_root_pe() )
then 558 write (unit=stdout_unit, fmt=
'("Opened profile dataset: ",A)') trim(filename)
563 call mpp_get_axes(unit, axes)
566 select case ( trim(axisname) )
568 depth_axis => axes(i)
569 case (
'station_index')
570 station_axis => axes(i)
575 allocate(fields(nvar))
576 call mpp_get_fields(unit, fields)
579 if( var_id .eq. temp_id )
then 580 select case (trim(fldname))
582 field_lon => fields(i)
584 field_lat => fields(i)
585 case (
'profile_flag')
586 field_flag => fields(i)
588 field_time => fields(i)
590 field_data => fields(i)
592 field_depth => fields(i)
594 field_link => fields(i)
596 field_error => fields(i)
598 field_t_flag => fields(i)
600 field_fix_depth => fields(i)
602 else if( var_id .eq. salt_id )
then 603 select case (trim(fldname))
605 field_lon => fields(i)
607 field_lat => fields(i)
608 case (
'profile_flag_s')
609 field_flag => fields(i)
611 field_time => fields(i)
613 field_data => fields(i)
615 field_depth => fields(i)
617 field_link => fields(i)
619 field_error => fields(i)
621 field_s_flag => fields(i)
623 field_fix_depth => fields(i)
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)
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)
642 write(unit=stdout_unit, fmt=
'("There are ",I8," records in this dataset.")') nstation
643 write(unit=stdout_unit, fmt=
'("Searching for profiles . . .")')
654 prof_in_filt_domain = .false.
655 depth = missing_value
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)
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)
672 call mpp_read(unit, field_link, rlink, tindex=i)
677 data_is_local = .false.
678 data_in_period = .false.
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
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 694 prof_in_filt_domain = .true.
700 prof_in_filt_domain = .true.
709 prof_in_filt_domain = .true.
716 prof_in_filt_domain = .true.
721 prof_in_filt_domain = .true.
726 if ( var_id == temp_id .and. flag_t == 0.0 )
then 731 if ( var_id == salt_id .and. flag_s == 0.0 )
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)
746 if ( depth(k) > 2000.0 ) depth(k) = missing_value
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 753 num_levs = num_levs + 1
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 760 num_levs = num_levs+1
769 do while ( rlink > 0.0 )
772 if ( nlinks > max_lnks )
then 773 write (emsg_local,
'("nlinks (",I6,") > MAX_LNKS (",I6,")")')&
775 call error_mesg(
'oda_core_mod::open_profile_dataset',&
776 & trim(emsg_local)//
' in file "'//trim(filename)//&
777 &
'". Increase parameter MAX_LNKS', fatal)
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)
789 call mpp_read(unit, field_link, rlink, tindex=ii)
794 if ( nlinks > 0 )
then 797 flag_bfr(nn,k) = .true.
799 if ( depth_bfr(nn,k) > 2000.0 ) depth_bfr(nn,k) = missing_value
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.
807 num_levs = num_levs+1
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.
815 num_levs = num_levs+1
823 if ( num_levs == 0 )
then 824 if ( i .gt. nstation ) cont = .false.
834 if ( inst_type < 1 ) inst_type =
unknown 846 call error_mesg(
'oda_core_mod::open_profile_dataset',&
847 &
'Loop value "kk" is greater than profile levels', fatal)
858 if ( flag_bfr(nn,k) )
then 860 call error_mesg(
'oda_core_mod::open_profile_dataset',&
861 &
'Loop value "kk" is greater than profile levels (bfr loop)', fatal)
874 if ( lat < 65.0 )
then 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)
886 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
888 call error_mesg(
'oda_core_mod::open_profile_dataset',&
889 &
'i0,j0 out of bounds in prfs01. '//trim(emsg_local), fatal)
893 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
895 call error_mesg(
'oda_core_mod::open_profile_dataset',&
896 &
'i0,j0 out of bounds in prfs02. '//trim(emsg_local), fatal)
899 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
901 call error_mesg(
'oda_core_mod::open_profile_dataset',&
902 &
'i0,j0 out of bounds in prfs03. '//trim(emsg_local), fatal)
910 &
lon_out,
lat_out, new_search=.true., no_crash_when_not_found=.true.)
912 if (
interp%i_lon(1,1,1) == -999. ) bad_point = bad_point + 1
913 if (
interp%wti(1,1,2) < 1.0 )
then 918 if (
interp%wtj(1,1,2) < 1.0 )
then 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)
941 out_bound_point = out_bound_point + 1
943 if (
interp%wti(1,1,2) < 1.0 )
then 948 if (
interp%wtj(1,1,2) < 1.0)
then 960 if (i0 < 1 .or. j0 < 1)
then 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 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 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 987 if (
grd%mask(i0,j0,1) == 0.0 )
then 998 write (unit=stdout_unit,&
999 & fmt=
'("Rejecting tao mooring at (lat,lon) = (",F10.5,",",F10.5,") based on user-specified mask.")')&
1025 call error_mesg(
'oda_core_mod::open_profile_dataset',
'Profile k_index is greater than nk', fatal)
1027 call error_mesg(
'oda_core_mod::open_profile_dataset',
'Profile k_index is less than 0', fatal)
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 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 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 1053 if (
grd%mask(i0,j0,k0) == 0.0 )
then 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 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 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 1078 if (
grd%mask(i0,j0,k0+1) == 0.0 )
then 1098 if ( i .gt. nstation ) cont = .false.
1101 a = nprof_in_filt_domain
1102 bad_point_g = bad_point
1108 write(unit=stdout_unit, fmt=
'("PE: ",I6," no_prf = ",I8,", num_profiles = ",I8)') mpp_pe(),
no_prf,
num_profiles 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
1122 call mpp_sync_self()
1123 call mpp_close(unit)
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
1141 integer,
parameter :: MAX_LEVELS = 1000
1142 integer,
parameter :: MAX_LNKS = 500
1144 real :: lon, lat, time, rlink, prf_type
1146 real,
dimension(MAX_LEVELS) :: depth, data
1147 real,
dimension(MAX_LNKS, MAX_LEVELS) :: data_bfr, depth_bfr
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
1155 character(len=32) :: fldname, axisname, anal_fldname, time_units
1156 character(len=128) :: emsg_local
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
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
1173 stdout_unit = stdout()
1175 if (
PRESENT(localize) )
then 1176 localize_data = localize
1178 localize_data = .true.
1181 nprof_in_filt_domain = 0
1183 anal_fldname =
'none' 1185 if ( obs_variable == temp_id )
then 1186 anal_fldname =
'temp' 1188 else if ( obs_variable == salt_id )
then 1189 anal_fldname =
'salt' 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)
1198 write (unit=stdout_unit, fmt=
'("Opened profile dataset: ",A)') trim(filename)
1202 allocate(axes(ndim))
1203 call mpp_get_axes(unit, axes)
1206 select case (trim(axisname))
1207 case (
'depth_index')
1208 depth_axis => axes(i)
1209 case (
'station_index')
1210 station_axis => axes(i)
1215 allocate(fields(nvar))
1216 call mpp_get_fields(unit, fields)
1219 if( var_id .eq. temp_id )
then 1220 select case (trim(fldname))
1222 field_lon => fields(i)
1224 field_lat => fields(i)
1226 field_flag => fields(i)
1228 field_time => fields(i)
1230 field_data => fields(i)
1232 field_depth => fields(i)
1234 field_link => fields(i)
1236 field_var_type => fields(i)
1238 else if( var_id .eq. salt_id )
then 1239 select case (trim(fldname))
1241 field_lon => fields(i)
1243 field_lat => fields(i)
1245 field_flag => fields(i)
1247 field_time => fields(i)
1249 field_data => fields(i)
1251 field_depth => fields(i)
1253 field_link => fields(i)
1255 field_var_type => fields(i)
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)
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)
1274 write (unit=stdout_unit, fmt=
'("There are ",I8," records in this dataset")') nstation
1275 write (unit=stdout_unit, fmt=
'("Searching for profiles . . .")')
1285 prof_in_filt_domain = .false.
1286 depth = missing_value
1287 data = missing_value
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)
1299 data_is_local = .false.
1300 data_in_period = .false.
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
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 1316 prof_in_filt_domain = .true.
1322 prof_in_filt_domain = .true.
1331 prof_in_filt_domain = .true.
1338 prof_in_filt_domain = .true.
1343 prof_in_filt_domain = .true.
1348 if ( var_id == temp_id )
then 1352 else if ( var_id == salt_id .and. prf_type == 2.0 )
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)
1366 if ( depth(k) > 2000.0 ) depth(k) = missing_value
1367 if ( var_id == temp_id )
then 1368 if (
data(k) .eq. missing_value .or. depth(k) .eq. missing_value )
then 1371 num_levs = num_levs+1
1373 else if ( var_id == salt_id )
then 1374 if (
data(k) .eq. missing_value .or. depth(k) .eq. missing_value )
then 1377 num_levs = num_levs+1
1386 do while ( rlink > 0.0 )
1389 if ( nlinks > max_lnks )
then 1390 write (emsg_local,
'("nlinks (",I6,") > MAX_LNKS (",I6,")")')&
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)
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)
1406 if ( nlinks > 0 )
then 1409 flag_bfr(nn,k) = .true.
1411 if ( depth_bfr(nn,k) > 2000.0 ) depth_bfr(nn,k) = missing_value
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.
1417 num_levs = num_levs+1
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.
1423 num_levs = num_levs+1
1431 if ( num_levs == 0 )
then 1432 if ( i .gt. nstation ) cont = .false.
1436 if (nprof_in_filt_domain > 0 .and. prof_in_filt_domain)
then 1442 if ( inst_type < 1 ) inst_type =
unknown 1455 call error_mesg(
'oda_core_mod::open_profile_dataset_argo',&
1456 &
'Loop variable "kk" is greater than profile levels', fatal)
1467 if ( flag_bfr(nn,k) )
then 1469 call error_mesg(
'oda_core_mod::open_profile_dataset_argo',&
1470 &
'Loop variable "kk" is greater than profile levels (bfr loop)', fatal)
1488 if ( lat < 65.0 )
then 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)
1500 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1502 call error_mesg(
'oda_core_mod::open_profile_dataset',&
1503 &
'i0,j0 out of bounds in argo01. '//trim(emsg_local), fatal)
1507 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1509 call error_mesg(
'oda_core_mod::open_profile_dataset',&
1510 &
'i0,j0 out of bounds in argo02. '//trim(emsg_local), fatal)
1513 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
1515 call error_mesg(
'oda_core_mod::open_profile_dataset',&
1516 &
'i0,j0 out of bounds in argo03. '//trim(emsg_local), fatal)
1524 if(
interp%wti(1,1,2) < 1.0)
then 1529 if (
interp%wtj(1,1,2) < 1.0 )
then 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)
1552 out_bound_point = out_bound_point + 1
1554 if (
interp%wti(1,1,2) < 1.0 )
then 1559 if (
interp%wtj(1,1,2) < 1.0 )
then 1567 if ( i0 < 1 .or. j0 < 1 )
then 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 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 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 1595 if (
grd%mask(i0,j0,1) == 0.0 )
then 1605 write (unit=stdout_unit,&
1606 & fmt=
'("Rejecting tao mooring at (lat,lon) = (",F10.5,",",F10.5,") based on user-specified mask.")')&
1632 call error_mesg(
'oda_core_mod::open_profile_dataset_argo',
'Profile k_index is greater than nk', fatal)
1634 call error_mesg(
'oda_core_mod::open_profile_dataset_argo',
'Profile k_index is less than 0', fatal)
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 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 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 1660 if (
grd%mask(i0,j0,k0) == 0.0 )
then 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 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 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 1685 if (
grd%mask(i0,j0,k0+1) == 0.0 )
then 1705 if ( i .gt. nstation ) cont = .false.
1708 a = nprof_in_filt_domain
1713 write(unit=stdout_unit, fmt=
'("PE: ",I6," no_prf = ",I8,", num_profiles = ",I8)') mpp_pe(),
no_prf,
num_profiles 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
1725 call mpp_sync_self()
1726 call mpp_close(unit)
1736 subroutine get_obs(model_time, Prof, nprof)
1739 integer,
intent(inout) :: nprof
1741 integer :: i, k, kk, k_interval
1742 integer :: yr, mon, day, hr,
min, sec
1743 integer :: stdout_unit
1748 stdout_unit = stdout()
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
1755 if (
profiles(i)%time <= model_time )
then 1756 tdiff = model_time -
profiles(i)%time
1758 tdiff =
profiles(i)%time - model_time
1767 if ( nprof >
size(prof,1) )
then 1769 &
'Passed in array "Prof" is smaller than number of profiles, increase size of Prof before call.',&
1774 prof(nprof)%tdiff = tdiff
1778 k_interval = (prof(nprof)%levels-
max_prflvs+50)/50 + 1
1780 do k=
max_prflvs-50+1, prof(nprof)%levels, k_interval
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)
1787 prof(nprof)%levels = kk
1793 write (unit=stdout_unit,&
1794 & fmt=
'("A total of ",I8," profiles are being used for the current analysis step.")') nprof
1799 subroutine oda_core_init(Domain, Grid, time_s, time_e, filt_domain, localize)
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
1806 integer :: ioun, ierr, io_status
1807 integer :: stdlog_unit
1809 stdlog_unit = stdlog()
1812 #ifdef INTERNAL_FILE_NML 1813 read (input_nml_file, oda_core_nml, iostat=io_status)
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)
1821 write(stdlog_unit, nml=oda_core_nml)
1840 subroutine copy_obs(obs_in, obs_out)
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)
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)
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)
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)
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)
1884 allocate(obs_out(n)%k_index(obs_in(n)%levels))
1885 obs_out(n)%k_index = obs_in(n)%k_index
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)
1909 character(len=*),
intent(in) :: filename
1910 integer,
intent(in) :: obs_variable
1911 logical,
intent(in),
optional :: localize
1913 integer,
parameter :: max_levels = 1
1915 real :: lon, lat, rms_err
1917 real,
dimension(MAX_LEVELS) :: depth, data
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
1924 logical :: data_is_local, localize_data
1925 logical,
dimension(MAX_LEVELS) :: flag
1927 character(len=32) :: axisname, anal_fldname
1928 character(len=128) :: emsg_local
1930 type(
axistype),
dimension(:),
allocatable,
target :: axes
1931 type(
axistype),
pointer :: lon_axis, lat_axis
1933 if (
PRESENT(localize) )
then 1934 localize_data = localize
1936 localize_data = .true.
1939 stdout_unit = stdout()
1941 anal_fldname =
'temp' 1942 var_id = obs_variable
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)
1951 select case (trim(axisname))
1967 if (
nlon /= 1440 .or.
nlat /= 1070 )
then 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)
1979 data_is_local = .true.
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
1987 if (
grd%mask(i,j,1) == 0 ) data_is_local = .false.
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.
1994 if ( i/16*16 /= i .or. j/8*8 /= j ) data_is_local = .false.
1997 if ( data_is_local .and. (.NOT.localize_data) )
then 1998 if ( lat < 60.0 )
then 2007 if (
interp%wti(1,1,2) < 1.0 )
then 2012 if (
interp%wtj(1,1,2) < 1.0 )
then 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)
2025 if ( i0 /=
ieg .and. j0 /=
jeg )
then 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 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)
2042 num_levs = num_levs + 1
2044 if ( num_levs == 0 ) cycle
2068 if ( lat < 60.0 )
then 2075 if (
interp%wti(1,1,2) < 1.0 )
then 2080 if (
interp%wtj(1,1,2) < 1.0 )
then 2088 if ( i0 < 1 .or. j0 < 1 )
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 2113 call mpp_close(unit)
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 2120 character(len=*),
intent(in) :: filename
2121 integer,
intent(in) :: obs_variable
2122 logical,
intent(in),
optional :: localize
2124 integer,
parameter :: MAX_LEVELS = 24
2126 real :: lon, lat, rms_err
2128 real,
dimension(MAX_LEVELS) :: depth, data
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
2136 logical :: data_is_local, localize_data
2137 logical :: prof_in_filt_domain
2138 logical,
dimension(MAX_LEVELS) :: flag
2140 character(len=32) :: axisname, anal_fldname
2141 character(len=128) :: emsg_local
2143 type(axistype),
dimension(:),
allocatable,
target :: axes
2144 type(axistype),
pointer :: lon_axis, lat_axis, z_axis, t_axis
2146 if (
PRESENT(localize) )
then 2147 localize_data = localize
2149 localize_data = .true.
2152 stdout_unit = stdout()
2153 anal_fldname =
'temp' 2154 var_id = obs_variable
2158 call mpp_open(unit, trim(filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2160 write (unit=stdout_unit, fmt=
'("Opened profile woa05t dataset: ",A)') trim(filename)
2162 call mpp_get_info(unit, ndim, nvar, natt, ntime)
2163 allocate(axes(ndim))
2164 call mpp_get_axes(unit,axes)
2167 select case (trim(axisname))
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)
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)
2200 data_is_local = .true.
2201 prof_in_filt_domain = .false.
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
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.
2216 prof_in_filt_domain = .true.
2222 prof_in_filt_domain = .true.
2231 prof_in_filt_domain = .true.
2238 prof_in_filt_domain = .true.
2243 prof_in_filt_domain = .true.
2248 if ( data_is_local .and. (.NOT.localize_data) )
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)
2263 num_levs = num_levs+1
2265 if ( num_levs == 0 ) cycle
2267 if ( prof_in_filt_domain )
then 2292 if ( lat < 65.0 )
then 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)
2304 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2306 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2307 &
'i0,j0 out of bounds in woat01. '//trim(emsg_local), fatal)
2311 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2313 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2314 &
'i0,j0 out of bounds in woat02. '//trim(emsg_local), fatal)
2317 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2319 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2320 &
'i0,j0 out of bounds in woat03. '//trim(emsg_local), fatal)
2328 if (
interp%wti(1,1,2) < 1.0 )
then 2333 if (
interp%wtj(1,1,2) < 1.0 )
then 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)
2344 write (unit=stdout_unit, fmt=
'("woat.pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2346 out_bound_point = out_bound_point + 1
2348 if (
interp%wti(1,1,2) < 1.0 )
then 2353 if (
interp%wtj(1,1,2) < 1.0 )
then 2361 if ( i0 < 1 .or. j0 < 1 )
then 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 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 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 2389 if (
grd%mask(i0,j0,1) == 0.0 )
then 2399 if (depth(k) <
grd%z(1))
then 2405 call error_mesg(
'oda_core_mod::open_profile_dataset_woa05t',&
2406 &
'Profile k_index is greater than nk', fatal)
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 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 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 2432 if (
grd%mask(i0,j0,k0) == 0.0 )
then 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 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 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 2457 if (
grd%mask(i0,j0,k0+1) == 0.0 )
then 2475 call mpp_close(unit)
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 2485 character(len=*),
intent(in) :: filename
2486 integer,
intent(in) :: obs_variable
2487 logical,
intent(in),
optional :: localize
2489 integer,
parameter :: MAX_LEVELS = 24
2491 real :: lon, lat, rms_err
2493 real,
dimension(MAX_LEVELS) :: depth, data
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
2501 logical :: data_is_local, localize_data
2502 logical :: prof_in_filt_domain
2503 logical,
dimension(MAX_LEVELS) :: flag
2505 character(len=32) :: axisname, anal_fldname
2506 character(len=128) :: emsg_local
2508 type(axistype),
dimension(:),
allocatable,
target :: axes
2509 type(axistype),
pointer :: lon_axis, lat_axis, z_axis
2511 if (
present(localize) )
then 2512 localize_data = localize
2514 localize_data = .true.
2517 stdout_unit = stdout()
2519 anal_fldname =
'salt' 2520 var_id = obs_variable
2524 call mpp_open(unit, trim(filename), mpp_rdonly, mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
2526 write (unit=stdout_unit, fmt=
'("Opened profile woa05s dataset: ",A)') trim(filename)
2528 call mpp_get_info(unit, ndim, nvar, natt, ntime)
2529 allocate(axes(ndim))
2530 call mpp_get_axes(unit, axes)
2533 select case ( trim(axisname) )
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)
2558 data_is_local = .true.
2559 prof_in_filt_domain = .false.
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
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.
2574 prof_in_filt_domain = .true.
2580 prof_in_filt_domain = .true.
2589 prof_in_filt_domain = .true.
2596 prof_in_filt_domain = .true.
2601 prof_in_filt_domain = .true.
2606 if ( data_is_local .and. (.NOT.localize_data) )
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)
2621 num_levs = num_levs + 1
2623 if ( num_levs == 0 ) cycle
2625 if ( prof_in_filt_domain )
then 2650 if ( lat < 65.0 )
then 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)
2662 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2664 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2665 &
'i0,j0 out of bounds in woas01. '//trim(emsg_local), fatal)
2669 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2671 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2672 &
'i0,j0 out of bounds in woas02. '//trim(emsg_local), fatal)
2675 write (unit=emsg_local, fmt=
'("pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2677 call error_mesg(
'oda_core_mod::open_profile_dataset',&
2678 &
'i0,j0 out of bounds in woas03. '//trim(emsg_local), fatal)
2686 if (
interp%wti(1,1,2) < 1.0 )
then 2691 if (
interp%wtj(1,1,2) < 1.0 )
then 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)
2702 write (unit=stdout_unit, fmt=
'("woas.pe,i0,j0= ",3I8,"isd_filt,ied_filt,jsd_filt,jed_filt= ",4I8)')&
2704 out_bound_point = out_bound_point + 1
2706 if (
interp%wti(1,1,2) < 1.0 )
then 2711 if (
interp%wtj(1,1,2) < 1.0 )
then 2719 if ( i0 < 1 .or. j0 < 1 )
then 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 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 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 2747 if (
grd%mask(i0,j0,1) == 0.0 )
then 2757 if (depth(k) <
grd%z(1))
then 2763 call error_mesg(
'oda_core_mod::open_profile_dataset_woa05s',&
2764 &
'Profile k_index is greater than nk', fatal)
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 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 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 2790 if (
grd%mask(i0,j0,k0) == 0.0 )
then 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 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 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 2815 if (
grd%mask(i0,j0,k0+1) == 0.0 )
then 2833 call mpp_close(unit)
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 2842 subroutine get_obs_sst(model_time, Prof, nprof, no_prf0, sst_climo, Filter_domain)
2845 integer,
intent(inout) :: nprof
2846 integer,
intent(in) :: no_prf0
2848 type(
domain2d),
intent(in) :: filter_domain
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
2857 character(len=128) :: sst_filename, emsg_local
2859 type(
fieldtype),
dimension(:),
allocatable :: fields
2860 type(
time_type) :: tdiff, sst_time0, time1
2862 n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
2866 stdout_unit = stdout()
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
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
2879 if ( mpp_pe() == mpp_root_pe() )
then 2880 write (unit=stdout_unit, fmt=
'("time_idx = ",I8)') time_idx
2883 sst_filename =
"INPUT/sst_daily.nc" 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)
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)
2893 call mpp_get_fields(unit, fields)
2895 select case ( mpp_get_field_name(fields(i)) )
2897 call mpp_read(unit, fields(i), filter_domain, sst_climo%sst_obs, tindex=time_idx)
2903 sst_time0 =
set_date(iy0, in0, id0, ih0, im0, is0)
2910 tdiff = model_time -
profiles(i)%time
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)
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)
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.',&
2936 prof(nprof+no_prf0)%tdiff = tdiff
2942 if ( mpp_pe() == mpp_root_pe() )
then 2943 write (unit=stdout_unit, fmt=
'("no of sst records: ",I8)') nprof
2947 call mpp_close(unit)
2953 integer,
intent(inout) :: nprof
2954 integer,
intent(in) :: no_prf0
2956 real :: ri0, rj0, lon_woa05
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
2964 character(len=32) :: axisname
2965 character(len=128) :: woa05t_filename
2967 type(
fieldtype),
dimension(:),
allocatable :: fields
2971 stdout_unit = stdout()
2973 call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
2978 woa05t_filename =
"INPUT/woa05_temp.nc" 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)
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)
2988 call mpp_get_fields(unit, fields)
2993 select case ( mpp_get_field_name(fields(i)) )
2999 woa05_time0 =
set_date(iy0, in0, id0, ih0, im0, is0)
3004 tdiff = model_time -
profiles(i)%time
3007 if ( lon_woa05 < 0.0 ) lon_woa05 = lon_woa05 + 360.0
3008 if ( lon_woa05 > 360.0 ) lon_woa05 = lon_woa05 - 360.0
3011 if ( i0 < 1 ) i0 = 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.',&
3028 if ( abs(
profiles(i)%data(k)) > 1.e3 .or.&
3029 & abs(
profiles(i)%depth(k)) > 1.e5 )
then 3034 prof(no_prf0+nprof)%tdiff = tdiff
3038 if ( mpp_pe() == mpp_root_pe() )
then 3039 write (unit=stdout_unit, fmt=
'("no of woa05t records: ",I8)') nprof
3043 call mpp_close(unit)
3049 integer,
intent(inout) :: nprof
3050 integer,
intent(in) :: no_prf0
3052 real :: ri0, rj0, lon_woa05
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
3060 character(len=128) :: woa05s_filename
3062 type(
fieldtype),
dimension(:),
allocatable :: fields
3066 stdout_unit = stdout()
3068 call get_date(model_time, iy0,in0,id0,ih0,im0,is0)
3073 woa05s_filename =
"INPUT/woa05_salt.nc" 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)
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)
3083 call mpp_get_fields(unit, fields)
3088 select case ( mpp_get_field_name(fields(i)) )
3094 woa05_time0 =
set_date(iy0, in0, id0, ih0, im0, is0)
3099 tdiff = model_time -
profiles(i)%time
3102 if ( lon_woa05 < 0.0 ) lon_woa05 = lon_woa05 + 360.0
3103 if ( lon_woa05 > 360.0 ) lon_woa05 = lon_woa05 - 360.0
3106 if ( i0 < 1 ) i0 = 1
3111 if ( j0 < 1 ) j0 = 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',&
3123 if ( abs(
profiles(i)%data(k)) > 1.e3 .or.&
3124 & abs(
profiles(i)%depth(k)) > 1.e5 )
then 3129 prof(no_prf0+nprof)%tdiff = tdiff
3133 if ( mpp_pe() == mpp_root_pe() )
then 3134 write (unit=stdout_unit, fmt=
'("no of woa05t records: ",I8)') nprof
3138 call mpp_close(unit)
3142 character(len=*),
intent(in) :: filename
3143 integer,
intent(in) :: obs_variable
3144 logical,
intent(in),
optional :: localize
3146 integer,
parameter :: MAX_LEVELS = 1000
3148 real :: lon, lat, rms_err
3150 real,
dimension(MAX_LEVELS) :: depth, data
3152 integer :: inst_type, var_id
3153 integer :: num_levs, k, kk, i, j, i0, j0
3154 integer :: stdout_unit
3156 logical :: data_is_local, localize_data
3157 logical,
dimension(MAX_LEVELS) :: flag
3159 character(len=32) :: anal_fldname
3161 if (
PRESENT(localize) )
then 3162 localize_data = localize
3164 localize_data = .true.
3167 stdout_unit = stdout()
3169 anal_fldname =
'eta' 3170 var_id = obs_variable
3173 do j=1,
size(
x_grid, dim=1)
3174 do i=1,
size(
x_grid, dim=2)
3180 data_is_local = .true.
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
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.
3194 if ( data_is_local .and. (.NOT.localize_data) )
then 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 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)
3215 num_levs = num_levs+1
3217 if ( num_levs == 0 ) cycle
3243 if ( i0 < 1 .or. j0 < 1 )
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 3258 if (depth(k) <
grd%z(1))
then 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 3276 character(len=*),
intent(in) :: filename
3277 integer,
intent(in) :: obs_variable
3278 logical,
intent(in),
optional :: localize
3280 integer,
parameter :: MAX_LEVELS = 1000
3283 real :: lon, lat, rms_err
3284 real,
dimension(MAX_LEVELS) :: depth, data
3286 integer :: inst_type, var_id
3287 integer :: num_levs, k, kk, i, j, i0, j0
3288 integer :: stdout_unit
3290 logical :: data_is_local, localize_data
3291 logical,
dimension(MAX_LEVELS) :: flag
3293 character(len=32) :: anal_fldname
3295 if (
PRESENT(localize) )
then 3296 localize_data = localize
3298 localize_data = .true.
3301 stdout_unit = stdout()
3303 anal_fldname =
'suv' 3304 var_id = obs_variable
3314 data_is_local = .true.
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
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.
3328 if ( data_is_local .and. (.NOT.localize_data) )
then 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 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)
3349 num_levs = num_levs + 1
3351 if ( num_levs == 0 ) cycle
3377 if ( i0 < 1 .or. j0 < 1 )
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 3392 if (depth(k) <
grd%z(1))
then 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 3409 subroutine get_obs_suv(model_time, Prof, nprof, no_prf0)
3412 integer,
intent(inout) :: nprof
3413 integer,
intent(in) :: no_prf0
3418 real :: sfc_lon, sfc_lat, ri0, rj0
3419 real,
dimension(1440,1070,1) :: sfc_u, sfc_v
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
3427 character(len=80) :: sfc_filename
3428 character(len=256) :: emsg_local
3430 type(
fieldtype),
dimension(:),
allocatable :: fields
3433 n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
3435 stdout_unit = stdout()
3437 call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
3442 if ( in0 == 1 )
then 3443 time_idx = (iy0-1984)*365 + id0
3447 time_idx = time_idx + (iy0-1984)*365 + n_days(i_m)
3449 time_idx = time_idx + id0
3452 if ( mpp_pe() == mpp_root_pe() )
then 3453 write (unit=stdout_unit, fmt=
'("time_idx = ",I8)') time_idx
3456 sfc_time0 =
set_date(iy0, in0, id0, ih0, im0, is0)
3458 sfc_filename =
"INPUT/sfc_current.198401-198412.nc" 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)
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)
3468 call mpp_get_fields(unit, fields)
3470 select case ( mpp_get_field_name(fields(i)) )
3472 call mpp_read(unit, fields(i), sfc_u, tindex=time_idx)
3474 call mpp_read(unit, fields(i), sfc_v, tindex=time_idx)
3481 tdiff = model_time -
profiles(i)%time
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)
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)
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',&
3508 profiles(i)%data(1) = sfc_u(i0,j0,1)
3509 profiles(i)%data(2) = sfc_v(i0,j0,1)
3513 prof(nprof+no_prf0)%tdiff = tdiff
3518 call mpp_close(unit)
3521 subroutine get_obs_eta(model_time, Prof, nprof, no_prf0)
3524 integer,
intent(inout) :: nprof
3525 integer,
intent(in) :: no_prf0
3530 real :: eta_lon, eta_lat, ri0, rj0
3531 real,
dimension(1440,1070) :: eta_t
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
3539 character(len=80) :: eta_filename
3540 character(len=256) :: emsg_local
3542 type(
fieldtype),
dimension(:),
allocatable :: fields
3545 n_days = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
3547 stdout_unit = stdout()
3549 call get_date(model_time, iy0, in0, id0, ih0, im0, is0)
3554 if ( in0 == 1 )
then 3555 time_idx = (iy0-1976)*365 + id0 - 1
3559 time_idx = time_idx + n_days(i_m)
3561 time_idx = (iy0-1976)*365 + time_idx + id0 - 1
3564 if ( mpp_pe() == mpp_root_pe() )
then 3565 write (unit=stdout_unit, fmt=
'("time_idx = ",I8)') time_idx
3568 sfc_time0 =
set_date(iy0, in0, id0, ih0, im0, is0)
3570 eta_filename=
'INPUT/ocean.19760101-20001231.eta_t.nc' 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)
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)
3580 call mpp_get_fields(unit, fields)
3582 select case ( mpp_get_field_name(fields(i)) )
3584 call mpp_read(unit, fields(i), eta_t, tindex=time_idx)
3591 tdiff = model_time -
profiles(i)%time
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)
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)
3612 if ( eta_t(i0,j0) > -9.9 )
then 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.',&
3623 prof(nprof+no_prf0)%tdiff = tdiff
3629 call mpp_close(unit)
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
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
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
integer function, public check_nml_error(IOSTAT, NML_NAME)
type(ocean_profile_type), dimension(:), allocatable, target profiles
real, dimension(:, :), allocatable x_grid_uv
integer, save, public salt_id
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
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
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
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
integer, parameter, public unknown
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
real, dimension(:), allocatable woa05_lon
integer, parameter, public drop_profiler
real eta_obs_end_lat
set obs domain
integer, parameter, public tao
moorings
real function, public frac_index(value, array)
real, parameter, public deg_to_rad
Radians per degree [rad/deg].
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)
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)
real, dimension(:,:), allocatable, save mask_tao
Derived type containing the data.
type(grid_type), pointer grd
real, dimension(:,:), allocatable obs_sst