1 !***********************************************************************
2 !* GNU Lesser General Public License
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
20 !> @defgroup amip_interp_mod amip_interp_mod
21 !> @ingroup amip_interp
22 !> @brief Provides observed sea surface temperature and ice mask data sets that have been
23 !! interpolated onto your model's grid.
25 !> @author Bruce Wyman
27 !> When using these routines three possible data sets are available:
29 !! 1. AMIP @link http://www-pcmdi.llnl.gov/amip @endlink from Jan 1979 to Jan 1989 (2 deg x 2 deg)
30 !! 2. Reynolds OI @link amip_interp.rey_oi.txt @endlink from Nov 1981 to Jan 1999 (1 deg x 1 deg)
31 !! 3. Reynolds EOF @link ftp://podaac.jpl.nasa.gov/pub/sea_surface_temperature/reynolds/rsst/doc/rsst.html
32 !! @endlink from Jan 1950 to Dec 1998 (2 deg x 2 deg)
34 !! All original data are observed monthly means. This module
35 !! interpolates linearly in time between pairs of monthly means.
36 !! Horizontal interpolation is done using the horiz_interp module.
38 !! When a requested date falls outside the range of dates available
39 !! a namelist option allows for use of the climatological monthly
40 !! mean values which are computed from all of the data in a particular
43 !! from Jan 1979 to Jan 1989 (2 deg x 2 deg).\n\n
45 !! from Nov 1981 to Jan 1999 (1 deg x 1 deg)\n
46 !! The analysis uses in situ and satellite SST's plus
47 !! SST's simulated by sea-ice cover.\n\n
49 !! from Jan 1950 to Dec 1998 (2 deg x 2 deg)\n
50 !! NCEP Reynolds Historical Reconstructed Sea Surface Temperature
51 !! The analysis uses both in-situ SSTs and satellite derived SSTs
52 !! from the NOAA Advanced Very High Resolution Radiometer.
53 !! In-situ data is used from 1950 to 1981, while both AVHRR derived
54 !! satellite SSTs and in-situ data are used from 1981 to the
57 !> @note The data set used by this module have been reformatted as 32-bit IEEE.
58 !! The data values are packed into 16-bit integers.
60 !! The data sets are read from the following files:
62 !! amip1 INPUT/amip1_sst.data
63 !! reynolds_io INPUT/reyoi_sst.data
64 !! reynolds_eof INPUT/reynolds_sst.data
68 !> File for amip_interp_mod
70 !> @addtogroup amip_interp_mod
72 module amip_interp_mod
74 use time_interp_mod, only: time_interp, fraction_of_year
76 use time_manager_mod, only: time_type, operator(+), operator(>), &
77 get_date, set_time, set_date
80 use get_cal_time_mod, only: get_cal_time
84 use horiz_interp_mod, only: horiz_interp_init, horiz_interp, &
85 horiz_interp_new, horiz_interp_del, &
86 horiz_interp_type, assignment(=)
88 use fms_mod, only: error_mesg, write_version_number, &
89 NOTE, WARNING, FATAL, stdlog, check_nml_error, &
90 mpp_pe, lowercase, mpp_root_pe, &
91 NOTE, mpp_error, fms_error_handler
93 use constants_mod, only: TFREEZE, pi
94 use platform_mod, only: R4_KIND, I2_KIND
95 use mpp_mod, only: input_nml_file
96 use fms2_io_mod, only: FmsNetcdfFile_t, fms2_io_file_exists=>file_exists, open_file, close_file, &
97 get_dimension_size, fms2_io_read_data=>read_data
102 !-----------------------------------------------------------------------
103 !----------------- Public interfaces -----------------------------------
105 public amip_interp_init, get_amip_sst, get_amip_ice, amip_interp_new, &
106 amip_interp_del, amip_interp_type, assignment(=)
108 !-----------------------------------------------------------------------
109 !----------------- Public Data -----------------------------------
110 integer :: i_sst = 1200
111 integer :: j_sst = 600
112 real, parameter:: big_number = 1.E30
113 logical :: forecast_mode = .false.
114 real, allocatable, dimension(:,:) :: sst_ncep, sst_anom
116 public i_sst, j_sst, sst_ncep, sst_anom, forecast_mode, use_ncep_sst
118 !-----------------------------------------------------------------------
119 !--------------------- private below here ------------------------------
121 ! ---- version number -----
123 ! Include variable "version" to be written to log file.
124 #include<file_version.h>
126 real, allocatable:: temp1(:,:), temp2(:,:)
128 real, allocatable, dimension(:,:) :: tempamip
130 !-----------------------------------------------------------------------
131 !------ private defined data type --------
135 !> @brief Private data type for representing a calendar date
136 !> @ingroup amip_interp_mod
139 integer :: year, month, day
142 !> Assignment overload to allow native assignment between amip_interp_type variables.
143 !> @ingroup amip_interp_mod
144 interface assignment(=)
145 module procedure amip_interp_type_eq
148 !> Private logical equality overload for amip_interp_type
149 !> @ingroup amip_interp_mod
150 interface operator (==)
151 module procedure date_equals
154 !> Private logical inequality overload for amip_interp_type
155 !> @ingroup amip_interp_mod
156 interface operator (/=)
157 module procedure date_not_equals
160 !> Private logical greater than overload for amip_interp_type
161 !> @ingroup amip_interp_mod
162 interface operator (>)
163 module procedure date_gt
167 !> Initializes data needed for the horizontal
168 !! interpolation between the sst data and model grid.
170 !> The returned variable of type amip_interp_type is needed when
171 !! calling get_amip_sst and get_amip_ice.
174 !! Longitude in radians of the model's grid box edges (1d lat/lon grid case)
175 !! or at grid box mid-point (2d case for arbitrary grids).
177 !! Latitude in radians of the model's grid box edges (1d lat/lon grid case)
178 !! or at grid box mid-point (2d case for arbitrary grids).
180 !! A mask for the model grid.
182 !! Flag the specifies that monthly mean climatological values will be used.
184 !! Flag the specifies that the annual mean climatological
185 !! will be used. If both use_annual = use_climo = true,
186 !! then use_annual = true will be used.
187 !> @param interp_method
188 !! specify the horiz_interp scheme. = "conservative" means conservative scheme,
189 !! = "bilinear" means bilinear interpolation.
191 !> @return interp, a defined data type variable needed when calling get_amip_sst and get_amip_ice.
195 !! Interp = amip_interp_new ( lon, lat, mask, use_climo, use_annual, interp_method )
197 !! This function may be called to initialize multiple variables
198 !! of type amip_interp_type. However, there currently is no
199 !! call to release the storage used by this variable.
201 !! The size of input augment mask must be a function of the size
202 !! of input augments lon and lat. The first and second dimensions
203 !! of mask must equal (size(lon,1)-1, size(lat,2)-1).
205 !> @throws "FATAL: the value of the namelist parameter DATA_SET being used is not allowed"
206 !! Check the value of namelist variable DATA_SET.
208 !> @throws "FATAL: requested input data set does not exist"
209 !! The data set requested is valid but the data does not exist in
210 !! the INPUT subdirectory. You may have requested amip2 data which
211 !! has not been officially set up.
212 !! See the section on DATA SETS to properly set the data up.
214 !> @throws "FATAL: use_climo mismatch"
215 !! The namelist variable date_out_of_range = 'fail' and the amip_interp_new
216 !! argument use_climo = true. This combination is not allowed.
218 !> @throws "FATAL: use_annual(climo) mismatch"
219 !! The namelist variable date_out_of_range = 'fail' and the amip_interp_new
220 !! argument use_annual = true. This combination is not allowed.
222 !> @ingroup amip_interp_mod
223 interface amip_interp_new
224 module procedure amip_interp_new_1d
225 module procedure amip_interp_new_2d
229 !----- public data type ------
231 !> @brief Contains information needed by the interpolation module (exchange_mod) and buffers data.
232 !> @ingroup amip_interp_mod
233 type amip_interp_type
235 type (horiz_interp_type) :: Hintrp, Hintrp2 ! add by JHC
236 real, pointer :: data1(:,:) =>NULL(), &
238 type (date_type) :: Date1, Date2
239 logical :: use_climo, use_annual
240 logical :: I_am_initialized=.false.
243 !> @addtogroup amip_interp_mod
245 !-----------------------------------------------------------------------
246 ! ---- resolution/grid variables ----
248 integer :: mobs, nobs
249 real, allocatable :: lon_bnd(:), lat_bnd(:)
251 ! ---- global unit & date ----
253 integer, parameter :: maxc = 128
255 character(len=maxc) :: file_name_sst, file_name_ice
256 type(FmsNetcdfFile_t), target :: fileobj_sst, fileobj_ice
258 type (date_type) :: Curr_date = date_type( -99, -99, -99 )
259 type (date_type) :: Date_end = date_type( -99, -99, -99 )
262 integer(I2_KIND) :: ice_crit
264 logical :: module_is_initialized = .false.
266 !-----------------------------------------------------------------------
269 character(len=24) :: data_set = 'amip1' !< use 'amip1', 'amip2', 'reynolds_eof'
270 !! 'reynolds_oi', 'hurrell', or 'daily',
271 !! when "use_daily=.T."
274 character(len=16) :: date_out_of_range = 'fail' !< use 'fail', 'initclimo', or 'climo'
276 real :: tice_crit = -1.80 !< in degC or degK
277 integer :: verbose = 0 !< 0 <= verbose <= 3
279 logical :: use_zonal = .false. !< parameters for prescribed zonal sst option
280 real :: teq = 305. !< parameters for prescribed zonal sst option
281 real :: tdif = 50. !< parameters for prescribed zonal sst option
282 real :: tann = 20. !< parameters for prescribed zonal sst option
283 real :: tlag = 0.875 !< parameters for prescribed zonal sst option
286 integer :: amip_date(3)=(/-1,-1,-1/) !< amip date for repeating single day (rsd) option
288 real :: sst_pert = 0. !< global temperature perturbation used for sensitivity experiments
290 character(len=6) :: sst_pert_type = 'fixed' !< use 'random' or 'fixed'
291 logical :: do_sst_pert = .false.
292 logical :: use_daily = .false. !< if '.true.', give 'data_set = 'daily''
294 logical :: use_ncep_sst = .false. !< SJL: During nudging: use_ncep_sst = .T.; no_anom_sst = .T.
295 !! during forecast: use_ncep_sst = .T.; no_anom_sst = .F.
296 logical :: no_anom_sst = .true. !< SJL: During nudging: use_ncep_sst = .T.; no_anom_sst = .T.
297 !! during forecast: use_ncep_sst = .T.; no_anom_sst = .F.
298 logical :: use_ncep_ice = .false. !< For seasonal forecast: use_ncep_ice = .F.
299 logical :: interp_oi_sst = .false. !< changed to false for regular runs
300 logical :: use_mpp_io = .false. !< Set to .true. to use mpp_io, otherwise fms2io is used
302 !> @page amip_interp_nml @ref amip_interp_mod Namelist
304 !> @var character(len=24) data_set
305 !! Name/type of SST data that will be used.
306 !! Possible values (case-insensitive) are:
310 !! See the @ref amip_interp_oi page for more information
311 !! @var character(len=16) date_out_of_range
312 !! Controls the use of climatological monthly mean data when
313 !! the requested date falls outside the range of the data set.<BR/>
314 !! Possible values are:
316 !! fail - program will fail if requested date is prior
317 !! to or after the data set period.
318 !! initclimo - program uses climatological requested data is
319 !! prior to data set period and will fail if
320 !! requested date is after data set period.
321 !! climo - program uses climatological data anytime.
323 !! @var real tice_crit
324 !! Freezing point of sea water in degC or degK. Defaults to -1.80
325 !! @var integer verbose
326 !! Controls printed output, 0 <= verbose <= 3, default=0
327 !! additional parameters for controlling zonal prescribed sst ----
328 !! these parameters only have an effect when use_zonal=.true. ----
329 !! @var logical use_zonal
330 !! Flag to selected zonal sst or data set. Default=.false.
332 !! sst at the equator. Default=305
334 !! Equator to pole sst difference. Default=50
336 !! Amplitude of annual cycle. Default=20
338 !! Offset for time of year (for annual cycle). Default=0.875
339 !! @var integer amip_date
340 !! Single calendar date in integer "(year,month,day)" format
341 !! that is used only if set with year>0, month>0, day>0.
342 !! If used, model calendar date is replaced by this date,
343 !! but model time of day is still used to determine ice/sst.
344 !! Used for repeating-single-day (rsd) experiments.
345 !! Default=/-1,-1,-1/
346 !! @var real sst_pert
347 !! Temperature perturbation in degrees Kelvin added onto the SST.
348 !! The perturbation is globally-uniform (even near sea-ice).
349 !! It is only used when abs(sst_pert) > 1.e-4. SST perturbation runs
350 !! may be useful in accessing model sensitivities.
352 namelist /amip_interp_nml/ use_ncep_sst, no_anom_sst, use_ncep_ice, tice_crit, &
353 interp_oi_sst, data_set, date_out_of_range, &
354 use_zonal, teq, tdif, tann, tlag, amip_date, &
356 sst_pert, sst_pert_type, do_sst_pert, &
359 verbose, i_sst, j_sst, forecast_mode, &
362 !-----------------------------------------------------------------------
367 !> Retrieve sea surface temperature data and interpolated grid
368 subroutine get_amip_sst (Time, Interp, sst, err_msg, lon_model, lat_model)
370 type (time_type), intent(in) :: Time !< Time to interpolate
371 type (amip_interp_type), intent(inout) :: Interp !< Holds data for interpolation
372 real, intent(out) :: sst(:,:) !< Sea surface temperature data
373 character(len=*), optional, intent(out) :: err_msg !< Holds error message string if present
375 real, dimension(mobs,nobs) :: sice
377 integer :: year1, year2, month1, month2
379 type (date_type) :: Date1, Date2, Udate1, Udate2
381 type(time_type) :: Amip_Time
382 integer :: tod(3),dum(3)
385 real, intent(in), dimension(:,:), optional :: lon_model, lat_model
387 integer :: i, j, mobs_sst, nobs_sst
389 type (time_type) :: Udate
390 character(len=4) :: yyyy
391 integer :: nrecords, ierr, k, yr, mo, dy
392 integer, dimension(:), allocatable :: ryr, rmo, rdy
393 character(len=30) :: time_unit
394 real, dimension(:), allocatable :: timeval
395 character(len=maxc) :: ncfilename
396 type(FmsNetcdfFile_t) :: fileobj
397 logical :: the_file_exists
399 logical, parameter :: DEBUG = .false. !> switch for debugging output
400 !> These are fms_io specific
403 if(present(err_msg)) err_msg = ''
404 if(.not.Interp%I_am_initialized) then
405 if(fms_error_handler('get_amip_sst','The amip_interp_type variable is not initialized',err_msg)) return
408 !-----------------------------------------------------------------------
409 !----- compute zonally symetric sst ---------------
411 if ( use_ncep_sst .and. forecast_mode ) no_anom_sst = .false.
413 if (all(amip_date>0)) then
414 call get_date(Time,dum(1),dum(2),dum(3),tod(1),tod(2),tod(3))
415 Amip_Time = set_date(amip_date(1),amip_date(2),amip_date(3),tod(1),tod(2),tod(3))
421 if ( .not.use_daily ) then
424 if ( .not. allocated(temp1) ) allocate (temp1(mobs,nobs))
425 if ( .not. allocated(temp2) ) allocate (temp2(mobs,nobs))
428 call zonal_sst (Amip_Time, sice, temp1)
429 call horiz_interp ( Interp%Hintrp, temp1, sst )
432 !-----------------------------------------------------------------------
433 !---------- get new observed sea surface temperature -------------------
435 ! ---- time interpolation for months -----
436 call time_interp (Amip_Time, fmonth, year1, year2, month1, month2)
437 ! ---- force climatology ----
438 if (Interp % use_climo) then
441 if (Interp % use_annual) then
445 ! ---------------------------
447 Date1 = date_type( year1, month1, 0 )
448 Date2 = date_type( year2, month2, 0 )
450 ! -- open/rewind file --
452 !-----------------------------------------------------------------------
455 if (Date1 /= Interp % Date1) then
456 ! ---- use Date2 for Date1 ----
457 if (Date1 == Interp % Date2) then
458 Interp % Date1 = Interp % Date2
459 Interp % data1 = Interp % data2
460 temp1(:,:) = temp2(:,:) ! SJL BUG fix: June 24, 2011
462 call read_record ('sst', Date1, Udate1, temp1)
463 if ( use_ncep_sst .and. (.not. no_anom_sst) ) then
464 temp1(:,:) = temp1(:,:) + sst_anom(:,:)
466 call horiz_interp ( Interp%Hintrp, temp1, Interp%data1 )
467 call clip_data ('sst', Interp%data1)
468 Interp % Date1 = Date1
472 !-----------------------------------------------------------------------
474 if (Date2 /= Interp % Date2) then
475 call read_record ('sst', Date2, Udate2, temp2)
476 if ( use_ncep_sst .and. (.not. no_anom_sst) ) then
477 temp2(:,:) = temp2(:,:) + sst_anom(:,:)
479 call horiz_interp ( Interp%Hintrp, temp2, Interp%data2 )
480 call clip_data ('sst', Interp%data2)
481 Interp % Date2 = Date2
484 !-----------------------------------------------------------------------
485 !---------- time interpolation (between months) of sst's ---------------
486 !-----------------------------------------------------------------------
487 sst = Interp % data1 + fmonth * (Interp % data2 - Interp % data1)
489 !-------------------------------------------------------------------------------
490 ! SJL mods for NWP and TCSF ---
491 ! Nudging runs: (Note: NCEP SST updated only every 6-hr)
492 ! Compute SST anomaly from global SST datasets for subsequent forecast runs
493 !-------------------------------------------------------------------------------
494 if ( use_ncep_sst .and. no_anom_sst ) then
495 sst_anom(:,:) = sst_ncep(:,:) - (temp1(:,:) + fmonth*(temp2(:,:) - temp1(:,:)) )
496 call horiz_interp ( Interp%Hintrp, sst_ncep, sst )
497 call clip_data ('sst', sst)
502 call get_date(Amip_Time,jhctod(1),jhctod(2),jhctod(3),jhctod(4),jhctod(5),jhctod(6))
503 if (mpp_pe() == 0) then
504 write (*,200) 'JHC: use_daily = F, AMIP_Time: ',jhctod(1),jhctod(2),jhctod(3),jhctod(4),jhctod(5), &
506 write (*,300) 'JHC: use_daily = F, interped SST: ', sst(1,1),sst(5,5),sst(10,10)
515 call get_date(Amip_Time,jhctod(1),jhctod(2),jhctod(3),jhctod(4),jhctod(5),jhctod(6))
516 if (mpp_pe() == mpp_root_pe()) write(*,200) 'amip_interp_mod: use_daily = T, Amip_Time = ',jhctod(1), &
517 & jhctod(2),jhctod(3),jhctod(4),jhctod(5),jhctod(6)
519 yr = jhctod(1); mo = jhctod(2); dy = jhctod(3)
521 write (yyyy,'(i4)') jhctod(1)
523 file_name_sst = 'INPUT/' // 'sst.day.mean.'//yyyy//'.v2.nc'
524 ncfilename = trim(file_name_sst)
525 time_unit = 'days since 1978-01-01 00:00:00'
527 mobs_sst = 1440; nobs_sst = 720
529 call set_sst_grid_edges_daily(mobs_sst, nobs_sst)
530 call horiz_interp_new ( Interp%Hintrp2, lon_bnd, lat_bnd, &
531 lon_model, lat_model, interp_method="bilinear" )
533 the_file_exists = fms2_io_file_exists(ncfilename)
535 if ( (.NOT. the_file_exists) ) then
536 call mpp_error ('amip_interp_mod', &
537 'cannot find daily SST input data file: '//trim(ncfilename), NOTE)
539 if (mpp_pe() == mpp_root_pe()) call mpp_error ('amip_interp_mod', &
540 'Reading NetCDF formatted daily SST from: '//trim(ncfilename), NOTE)
542 if(.not. open_file(fileobj, trim(ncfilename), 'read')) &
543 call error_mesg ('get_amip_sst', 'Error in opening file '//trim(ncfilename), FATAL)
545 call get_dimension_size(fileobj, 'TIME', nrecords)
546 if (nrecords < 1) call mpp_error('amip_interp_mod', &
547 'Invalid number of SST records in daily SST data file: '//trim(ncfilename), FATAL)
548 allocate(timeval(nrecords), ryr(nrecords), rmo(nrecords), rdy(nrecords))
549 call fms2_io_read_data(fileobj, 'TIME', timeval)
552 if (mpp_pe() == 0) then
553 print *, 'JHC: nrecords = ', nrecords
554 print *, 'JHC: TIME = ', timeval
561 Udate = get_cal_time (timeval(k), time_unit, 'julian')
562 call get_date(Udate,jhctod(1),jhctod(2),jhctod(3),jhctod(4),jhctod(5),jhctod(6))
563 ryr(k) = jhctod(1); rmo(k) = jhctod(2); rdy(k) = jhctod(3)
565 if ( yr == ryr(k) .and. mo == rmo(k) .and. dy == rdy (k) ) ierr = 0
571 if (mpp_pe() == 0) then
572 print *, 'JHC: k =', k
573 print *, 'JHC: ryr(k) rmo(k) rdy(k)',ryr(k), rmo(k), rdy(k)
574 print *, 'JHC: yr mo dy ',yr, mo, dy
578 if (ierr .ne. 0) call mpp_error('amip_interp_mod', &
579 'Model time is out of range not in SST data: '//trim(ncfilename), FATAL)
580 endif ! if(file_exist(ncfilename))
583 !---- read NETCDF data ----
584 if ( .not. allocated(tempamip) ) allocate (tempamip(mobs_sst,nobs_sst))
586 if (the_file_exists) then
587 call fms2_io_read_data(fileobj, 'SST', tempamip, unlim_dim_level=k)
588 call close_file(fileobj)
589 tempamip = tempamip + TFREEZE
593 if (mpp_pe() == 0) then
594 print*, 'JHC: TFREEZE = ', TFREEZE
597 print*, lbound(tempamip)
598 print*, ubound(tempamip)
599 write(*,300) 'JHC: tempamip : ', tempamip(100,100), tempamip(200,200), tempamip(300,300)
603 call horiz_interp ( Interp%Hintrp2, tempamip, sst )
604 call clip_data ('sst', sst)
609 if (mpp_pe() == 400) then
610 write(*,300)'JHC: use_daily = T, daily SST: ', sst(1,1),sst(5,5),sst(10,10)
611 print *,'JHC: use_daily = T, daily SST: ', sst
615 200 format(a35, 6(i5,1x))
616 300 format(a35, 3(f7.3,2x))
621 ! add by JHC: add on non-zero sea surface temperature perturbation (namelist option)
622 ! This perturbation may be useful in accessing model sensitivities
624 if ( do_sst_pert ) then
626 if ( trim(sst_pert_type) == 'fixed' ) then
628 else if ( trim(sst_pert_type) == 'random' ) then
632 if (mpp_pe() == 0) then
633 print*, 'mobs = ', mobs
634 print*, 'nobs = ', nobs
640 do i = 1, size(sst,1)
641 do j = 1, size(sst,2)
642 call random_number(pert)
643 sst (i,j) = sst (i,j) + sst_pert*((pert-0.5)*2)
651 !-----------------------------------------------------------------------
653 end subroutine get_amip_sst
655 !> AMIP interpolation for ice
656 subroutine get_amip_ice (Time, Interp, ice, err_msg)
658 type (time_type), intent(in) :: Time !< Time to interpolate
659 type (amip_interp_type), intent(inout) :: Interp !< Holds data for interpolation
660 real, intent(out) :: ice(:,:) !< ice data
661 character(len=*), optional, intent(out) :: err_msg !< Holds error message string if present
663 real, dimension(mobs,nobs) :: sice, temp
665 integer :: year1, year2, month1, month2
667 type (date_type) :: Date1, Date2, Udate1, Udate2
669 type(time_type) :: Amip_Time
670 integer :: tod(3),dum(3)
672 if(present(err_msg)) err_msg = ''
673 if(.not.Interp%I_am_initialized) then
674 if(fms_error_handler('get_amip_ice','The amip_interp_type variable is not initialized',err_msg)) return
677 !-----------------------------------------------------------------------
678 !----- compute zonally symetric sst ---------------
681 if (any(amip_date>0)) then
683 call get_date(Time,dum(1),dum(2),dum(3),tod(1),tod(2),tod(3))
685 Amip_Time = set_date(amip_date(1),amip_date(2),amip_date(3),tod(1),tod(2),tod(3))
695 call zonal_sst (Amip_Time, sice, temp)
696 call horiz_interp ( Interp%Hintrp, sice, ice )
699 !-----------------------------------------------------------------------
700 !---------- get new observed sea surface temperature -------------------
702 ! ---- time interpolation for months -----
704 call time_interp (Amip_Time, fmonth, year1, year2, month1, month2)
706 ! ---- force climatology ----
707 if (Interp % use_climo) then
710 if (Interp % use_annual) then
714 ! ---------------------------
716 Date1 = date_type( year1, month1, 0 )
717 Date2 = date_type( year2, month2, 0 )
720 !-----------------------------------------------------------------------
722 if (Date1 /= Interp % Date1) then
723 ! ---- use Date2 for Date1 ----
724 if (Date1 == Interp % Date2) then
725 Interp % Date1 = Interp % Date2
726 Interp % data1 = Interp % data2
728 !-- SJL -------------------------------------------------------------
729 ! Can NOT use ncep_sst to determine sea_ice For seasonal forecast
730 ! Use climo sea ice for seasonal runs
731 if ( use_ncep_sst .and. use_ncep_ice ) then
732 where ( sst_ncep <= (TFREEZE+tice_crit) )
738 call read_record ('ice', Date1, Udate1, sice)
740 !--------------------------------------------------------------------
741 call horiz_interp ( Interp%Hintrp, sice, Interp%data1 )
742 call clip_data ('ice', Interp%data1)
743 Interp % Date1 = Date1
747 !-----------------------------------------------------------------------
749 if (Date2 /= Interp % Date2) then
751 !-- SJL -------------------------------------------------------------
752 if ( use_ncep_sst .and. use_ncep_ice ) then
753 where ( sst_ncep <= (TFREEZE+tice_crit) )
759 call read_record ('ice', Date2, Udate2, sice)
761 !--------------------------------------------------------------------
762 call horiz_interp ( Interp%Hintrp, sice, Interp%data2 )
763 call clip_data ('ice', Interp%data2)
764 Interp % Date2 = Date2
768 !-----------------------------------------------------------------------
769 !---------- time interpolation (between months) ------------------------
770 !-----------------------------------------------------------------------
772 ice = Interp % data1 + fmonth * (Interp % data2 - Interp % data1)
776 !-----------------------------------------------------------------------
778 end subroutine get_amip_ice
780 !#######################################################################
782 !> @return A newly created @ref amip_interp_type
783 function amip_interp_new_1d ( lon , lat , mask , use_climo, use_annual, &
784 interp_method ) result (Interp)
786 real, intent(in), dimension(:) :: lon, lat
787 logical, intent(in), dimension(:,:) :: mask
788 character(len=*), intent(in), optional :: interp_method
789 logical, intent(in), optional :: use_climo, use_annual
791 type (amip_interp_type) :: Interp
793 if(.not.module_is_initialized) call amip_interp_init
795 Interp % use_climo = .false.
796 if (present(use_climo)) Interp % use_climo = use_climo
797 Interp % use_annual = .false.
798 if (present(use_annual)) Interp % use_annual = use_annual
800 if ( date_out_of_range == 'fail' .and. Interp%use_climo ) &
801 call error_mesg ('amip_interp_new_1d', 'use_climo mismatch', FATAL)
803 if ( date_out_of_range == 'fail' .and. Interp%use_annual ) &
804 call error_mesg ('amip_interp_new_1d', 'use_annual(climo) mismatch', FATAL)
806 Interp % Date1 = date_type( -99, -99, -99 )
807 Interp % Date2 = date_type( -99, -99, -99 )
809 !-----------------------------------------------------------------------
810 ! ---- initialization of horizontal interpolation ----
812 call horiz_interp_new ( Interp%Hintrp, lon_bnd, lat_bnd, &
813 lon, lat, interp_method= interp_method )
815 allocate ( Interp % data1 (size(lon(:))-1,size(lat(:))-1), &
816 Interp % data2 (size(lon(:))-1,size(lat(:))-1) )
818 Interp%I_am_initialized = .true.
820 end function amip_interp_new_1d
822 !> @return A newly created @ref amip_interp_type
823 function amip_interp_new_2d ( lon , lat , mask , use_climo, use_annual, &
824 interp_method ) result (Interp)
826 real, intent(in), dimension(:,:) :: lon, lat
827 logical, intent(in), dimension(:,:) :: mask
828 character(len=*), intent(in), optional :: interp_method
829 logical, intent(in), optional :: use_climo, use_annual
831 type (amip_interp_type) :: Interp
833 if(.not.module_is_initialized) call amip_interp_init
835 Interp % use_climo = .false.
836 if (present(use_climo)) Interp % use_climo = use_climo
837 Interp % use_annual = .false.
838 if (present(use_annual)) Interp % use_annual = use_annual
840 if ( date_out_of_range == 'fail' .and. Interp%use_climo ) &
841 call error_mesg ('amip_interp_new_2d', 'use_climo mismatch', FATAL)
843 if ( date_out_of_range == 'fail' .and. Interp%use_annual ) &
844 call error_mesg ('amip_interp_new_2d', 'use_annual(climo) mismatch', FATAL)
846 Interp % Date1 = date_type( -99, -99, -99 )
847 Interp % Date2 = date_type( -99, -99, -99 )
849 !-----------------------------------------------------------------------
850 ! ---- initialization of horizontal interpolation ----
852 call horiz_interp_new ( Interp%Hintrp, lon_bnd, lat_bnd, &
853 lon, lat, interp_method = interp_method)
855 allocate ( Interp % data1 (size(lon,1),size(lat,2)), &
856 Interp % data2 (size(lon,1),size(lat,2)))
858 Interp%I_am_initialized = .true.
860 end function amip_interp_new_2d
862 !#######################################################################
864 !> initialize @ref amip_interp_mod for use
865 subroutine amip_interp_init()
867 integer :: unit,io,ierr
869 !-----------------------------------------------------------------------
871 call horiz_interp_init
873 ! ---- read namelist ----
875 read (input_nml_file, amip_interp_nml, iostat=io)
876 ierr = check_nml_error(io,'amip_interp_nml')
878 ! ----- write namelist/version info -----
879 call write_version_number("AMIP_INTERP_MOD", version)
882 if (mpp_pe() == 0) then
883 write (unit,nml=amip_interp_nml)
887 !! USE_MPP_IO_WARNING
888 call mpp_error ('amip_interp_mod', &
889 'MPP_IO is no longer supported. Please remove use_mpp_io from amip_interp_nml',&
892 if ( .not. use_ncep_sst ) interp_oi_sst = .false.
894 ! ---- freezing point of sea water in deg K ---
896 tice_crit_k = tice_crit
897 if ( tice_crit_k < 200. ) tice_crit_k = tice_crit_k + TFREEZE
898 ice_crit = nint((tice_crit_k-TFREEZE)*100., I2_KIND)
900 ! ---- set up file dependent variable ----
901 ! ---- global file name ----
902 ! ---- grid box edges ----
903 ! ---- initialize zero size grid if not pe 0 ------
905 if (lowercase(trim(data_set)) == 'amip1') then
906 file_name_sst = 'INPUT/' // 'amip1_sst.data'
907 file_name_ice = 'INPUT/' // 'amip1_sst.data'
908 mobs = 180; nobs = 91
909 call set_sst_grid_edges_amip1
911 call error_mesg ('amip_interp_init', 'using AMIP 1 sst', NOTE)
912 Date_end = date_type( 1989, 1, 0 )
913 else if (lowercase(trim(data_set)) == 'amip2') then
914 file_name_sst = 'INPUT/' // 'amip2_sst.data'
915 file_name_ice = 'INPUT/' // 'amip2_ice.data'
916 mobs = 360; nobs = 180
917 call set_sst_grid_edges_oi
918 ! --- specfied min for amip2 ---
921 call error_mesg ('amip_interp_init', 'using AMIP 2 sst', NOTE)
922 Date_end = date_type( 1996, 3, 0 )
923 else if (lowercase(trim(data_set)) == 'hurrell') then
924 file_name_sst = 'INPUT/' // 'hurrell_sst.data'
925 file_name_ice = 'INPUT/' // 'hurrell_ice.data'
926 mobs = 360; nobs = 180
927 call set_sst_grid_edges_oi
928 ! --- specfied min for hurrell ---
931 call error_mesg ('amip_interp_init', 'using HURRELL sst', NOTE)
932 Date_end = date_type( 2011, 8, 16 ) ! updated by JHC
934 else if (lowercase(trim(data_set)) == 'daily') then
935 file_name_sst = 'INPUT/' // 'hurrell_sst.data'
936 file_name_ice = 'INPUT/' // 'hurrell_ice.data'
937 mobs = 360; nobs = 180
938 call set_sst_grid_edges_oi
940 call error_mesg ('amip_interp_init', 'using AVHRR daily sst', NOTE)
941 Date_end = date_type( 2011, 8, 16 )
943 else if (lowercase(trim(data_set)) == 'reynolds_eof') then
944 file_name_sst = 'INPUT/' // 'reynolds_sst.data'
945 file_name_ice = 'INPUT/' // 'reynolds_sst.data'
946 mobs = 180; nobs = 90
947 call set_sst_grid_edges_oi
949 call error_mesg ('amip_interp_init', &
950 'using NCEP Reynolds Historical Reconstructed SST', NOTE)
951 Date_end = date_type( 1998, 12, 0 )
952 else if (lowercase(trim(data_set)) == 'reynolds_oi') then
953 file_name_sst = 'INPUT/' // 'reyoi_sst.data'
954 file_name_ice = 'INPUT/' // 'reyoi_sst.data'
955 !--- Added by SJL ----------------------------------------------
956 if ( use_ncep_sst ) then
957 mobs = i_sst; nobs = j_sst
958 if (.not. allocated (sst_ncep)) then
959 allocate (sst_ncep(i_sst,j_sst))
960 sst_ncep(:,:) = big_number
962 if (.not. allocated (sst_anom)) then
963 allocate (sst_anom(i_sst,j_sst))
964 sst_anom(:,:) = big_number
967 mobs = 360; nobs = 180
969 !--- Added by SJL ----------------------------------------------
970 call set_sst_grid_edges_oi
972 call error_mesg ('amip_interp_init', 'using Reynolds OI SST', &
974 Date_end = date_type( 1999, 1, 0 )
976 call error_mesg ('amip_interp_init', 'the value of the &
977 &namelist parameter DATA_SET being used is not allowed', FATAL)
980 if (verbose > 1 .and. mpp_pe() == 0) &
981 print *, 'ice_crit,tice_crit_k=',ice_crit,tice_crit_k
983 ! --- check existence of sst data file ??? ---
984 file_name_sst = trim(file_name_sst)//'.nc'
985 file_name_ice = trim(file_name_ice)//'.nc'
987 if (.not. fms2_io_file_exists(trim(file_name_sst)) ) then
988 call error_mesg ('amip_interp_init', &
989 'file '//trim(file_name_sst)//' does not exist', FATAL)
991 if (.not. fms2_io_file_exists(trim(file_name_ice)) ) then
992 call error_mesg ('amip_interp_init', &
993 'file '//trim(file_name_ice)//' does not exist', FATAL)
996 if (.not. open_file(fileobj_sst, trim(file_name_sst), 'read')) &
997 call error_mesg ('amip_interp_init', 'Error in opening file '//trim(file_name_sst), FATAL)
998 if (.not. open_file(fileobj_ice, trim(file_name_ice), 'read')) &
999 call error_mesg ('amip_interp_init', 'Error in opening file '//trim(file_name_ice), FATAL)
1000 module_is_initialized = .true.
1002 end subroutine amip_interp_init
1004 !#######################################################################
1006 !> Frees data associated with a amip_interp_type variable. Should be used for any
1007 !! variables initialized via @ref amip_interp_new.
1008 !> @param[inout] Interp A defined data type variable initialized by amip_interp_new and used
1009 !! when calling get_amip_sst and get_amip_ice.
1010 subroutine amip_interp_del (Interp)
1011 type (amip_interp_type), intent(inout) :: Interp
1012 if(associated(Interp%data1)) deallocate(Interp%data1)
1013 if(associated(Interp%data2)) deallocate(Interp%data2)
1014 if(allocated(lon_bnd)) deallocate(lon_bnd)
1015 if(allocated(lat_bnd)) deallocate(lat_bnd)
1016 call horiz_interp_del ( Interp%Hintrp )
1018 Interp%I_am_initialized = .false.
1020 end subroutine amip_interp_del
1022 !#######################################################################
1024 subroutine set_sst_grid_edges_amip1
1027 real :: hpie, dlon, dlat, wb, sb
1029 allocate ( lon_bnd(mobs+1), lat_bnd(nobs+1) )
1031 ! ---- compute grid edges (do only once) -----
1035 dlon = 4.*hpie/float(mobs); wb = -0.5*dlon
1037 lon_bnd(i) = wb + dlon * float(i-1)
1039 lon_bnd(mobs+1) = lon_bnd(1) + 4.*hpie
1041 dlat = 2.*hpie/float(nobs-1); sb = -hpie + 0.5*dlat
1042 lat_bnd(1) = -hpie; lat_bnd(nobs+1) = hpie
1044 lat_bnd(j) = sb + dlat * float(j-2)
1047 end subroutine set_sst_grid_edges_amip1
1049 !#######################################################################
1050 subroutine set_sst_grid_edges_oi
1053 real :: hpie, dlon, dlat, wb, sb
1056 if(allocated(lon_bnd)) deallocate(lon_bnd)
1057 if(allocated(lat_bnd)) deallocate(lat_bnd)
1059 allocate ( lon_bnd(mobs+1), lat_bnd(nobs+1) )
1061 ! ---- compute grid edges (do only once) -----
1065 dlon = 4.*hpie/float(mobs); wb = 0.0
1068 lon_bnd(i) = wb + dlon * float(i-1)
1070 lon_bnd(mobs+1) = lon_bnd(1) + 4.*hpie
1072 dlat = 2.*hpie/float(nobs); sb = -hpie
1073 lat_bnd(1) = sb; lat_bnd(nobs+1) = hpie
1075 lat_bnd(j) = sb + dlat * float(j-1)
1078 end subroutine set_sst_grid_edges_oi
1079 !#######################################################################
1081 subroutine set_sst_grid_edges_daily(mobs_sst, nobs_sst)
1083 integer :: i, j, mobs_sst, nobs_sst
1084 real :: hpie, dlon, dlat, wb, sb
1086 if(allocated(lon_bnd)) deallocate(lon_bnd)
1087 if(allocated(lat_bnd)) deallocate(lat_bnd)
1088 allocate ( lon_bnd(mobs_sst+1), lat_bnd(nobs_sst+1) )
1090 ! ---- compute grid edges (do only once) -----
1094 dlon = 4.*hpie/float(mobs_sst); wb = 0.0
1096 do i = 2, mobs_sst+1
1097 lon_bnd(i) = wb + dlon * float(i-1)
1099 lon_bnd(mobs_sst+1) = lon_bnd(1) + 4.*hpie
1101 dlat = 2.*hpie/float(nobs_sst); sb = -hpie
1102 lat_bnd(1) = sb; lat_bnd(nobs_sst+1) = hpie
1104 lat_bnd(j) = sb + dlat * float(j-1)
1107 end subroutine set_sst_grid_edges_daily
1109 !#######################################################################
1112 subroutine a2a_bilinear(nx, ny, dat1, n1, n2, dat2)
1113 integer, intent(in):: nx, ny
1114 integer, intent(in):: n1, n2
1115 real, intent(in) :: dat1(nx,ny)
1116 real, intent(out):: dat2(n1,n2) !> output interpolated data
1119 real:: lon1(nx), lat1(ny)
1120 real:: lon2(n1), lat2(n2)
1121 real:: dx1, dy1, dx2, dy2
1123 real:: a1, b1, c1, c2, c3, c4
1124 integer i1, i2, jc, i0, j0, it, jt
1128 !-----------------------------------------------------------
1129 ! * Interpolate from "FMS" 1x1 SST data grid to a finer grid
1130 ! lon: 0.5, 1.5, ..., 359.5
1131 ! lat: -89.5, -88.5, ... , 88.5, 89.5
1132 !-----------------------------------------------------------
1134 dx1 = 360./real(nx) !> INput Grid
1135 dy1 = 180./real(ny) !> INput Grid
1138 lon1(i) = 0.5*dx1 + real(i-1)*dx1
1141 lat1(j) = -90. + 0.5*dy1 + real(j-1)*dy1
1144 dx2 = 360./real(n1) !> OutPut Grid:
1145 dy2 = 180./real(n2) !> OutPut Grid:
1148 lon2(i) = 0.5*dx2 + real(i-1)*dx2
1151 lat2(j) = -90. + 0.5*dy2 + real(j-1)*dy2
1158 if ( yc<lat1(1) ) then
1161 elseif ( yc>lat1(ny) ) then
1166 if ( yc>=lat1(j0) .and. yc<=lat1(j0+1) ) then
1169 b1 = (yc-lat1(jc)) / dy1
1179 if ( xc>lon1(nx) ) then
1181 a1 = (xc-lon1(nx)) / dx1
1182 elseif ( xc<lon1(1) ) then
1184 a1 = (xc+360.-lon1(nx)) / dx1
1187 if ( xc>=lon1(i0) .and. xc<=lon1(i0+1) ) then
1190 a1 = (xc-lon1(i1)) / dx1
1198 if ( a1<-0.001 .or. a1>1.001 .or. b1<-0.001 .or. b1>1.001 ) then
1199 write(*,*) i,j,a1, b1
1200 call mpp_error(FATAL,'a2a bilinear interpolation')
1203 c1 = (1.-a1) * (1.-b1)
1208 ! Bilinear interpolation:
1209 dat2(i,j) = c1*dat1(i1,jc) + c2*dat1(i2,jc) + c3*dat1(i2,jc+1) + c4*dat1(i1,jc+1)
1213 5000 continue ! j-loop
1215 end subroutine a2a_bilinear
1217 !#######################################################################
1219 !> @brief Returns the size (i.e., number of longitude and latitude
1220 !! points) of the observed data grid.
1221 !! @throws FATAL have not called amip_interp_new
1222 !! Must call amip_interp_new before get_sst_grid_size.
1223 subroutine get_sst_grid_size (nlon, nlat)
1225 integer, intent(out) :: nlon !> The number of longitude points (first dimension) in the
1226 !! observed data grid. For AMIP 1 nlon = 180, and the Reynolds nlon = 360.
1227 integer, intent(out) :: nlat !> The number of latitude points (second dimension) in the
1228 !! observed data grid. For AMIP 1 nlon = 91, and the Reynolds nlon = 180.
1230 if ( .not.module_is_initialized ) call amip_interp_init
1232 nlon = mobs; nlat = nobs
1234 end subroutine get_sst_grid_size
1236 !#######################################################################
1238 !> @brief Returns the grid box boundaries of the observed data grid.
1240 !! @throws FATAL, have not called amip_interp_new
1241 !! Must call amip_interp_new before get_sst_grid_boundary.
1243 !! @throws FATAL, invalid argument dimensions
1244 !! The size of the output argument arrays do not agree with
1245 !! the size of the observed data. See the documentation for
1246 !! interfaces get_sst_grid_size and get_sst_grid_boundary.
1247 subroutine get_sst_grid_boundary (blon, blat, mask)
1249 real, intent(out) :: blon(:) !> The grid box edges (in radians) for longitude points of the
1250 !! observed data grid. The size of this argument must be nlon+1.
1251 real, intent(out) :: blat(:) !> The grid box edges (in radians) for latitude points of the
1252 !! observed data grid. The size of this argument must be nlat+1.
1253 logical, intent(out) :: mask(:,:)
1255 if ( .not.module_is_initialized ) call amip_interp_init
1257 ! ---- check size of argument(s) ----
1259 if (size(blon(:)) /= mobs+1 .or. size(blat(:)) /= nobs+1) &
1260 call error_mesg ('get_sst_grid_boundary in amip_interp_mod', &
1261 'invalid argument dimensions', FATAL)
1263 ! ---- return grid box edges -----
1268 ! ---- masking (data exists at all points) ----
1273 end subroutine get_sst_grid_boundary
1275 !#######################################################################
1277 subroutine read_record (type, Date, Adate, dat)
1279 character(len=*), intent(in) :: type
1280 type (date_type), intent(in) :: Date
1281 type (date_type), intent(inout) :: Adate
1282 real, intent(out) :: dat(mobs,nobs)
1283 real :: tmp_dat(360,180)
1285 integer(I2_KIND) :: idat(mobs,nobs)
1286 integer :: nrecords, yr, mo, dy, ierr, k
1287 integer, dimension(:), allocatable :: ryr, rmo, rdy
1288 character(len=maxc) :: ncfilename, ncfieldname
1289 type(FmsNetcdfFile_t), pointer :: fileobj
1291 !---- set file and field name for NETCDF data sets ----
1294 if(type(1:3) == 'sst') then
1295 ncfilename = trim(file_name_sst)
1296 fileobj => fileobj_sst
1297 else if(type(1:3) == 'ice') then
1298 ncfilename = trim(file_name_ice)
1299 fileobj => fileobj_ice
1300 if (lowercase(trim(data_set)) == 'amip2' .or. &
1301 lowercase(trim(data_set)) == 'hurrell' .or. &
1302 lowercase(trim(data_set)) == 'daily') ncfieldname = 'ice' ! modified by JHC
1305 dy = 0 ! only processing monthly data
1307 if (verbose > 2 .and. mpp_pe() == 0) &
1308 print *, 'looking for date = ', Date
1310 ! This code can handle amip1, reynolds, or reyoi type SST data files in netCDF format
1311 if (mpp_pe() == mpp_root_pe()) call mpp_error ('amip_interp_mod', &
1312 'Reading NetCDF formatted input data file: '//trim(ncfilename), NOTE)
1314 call fms2_io_read_data (fileobj, 'nrecords', nrecords)
1315 if (nrecords < 1) call mpp_error('amip_interp_mod', &
1316 'Invalid number of SST records in SST datafile: '//trim(ncfilename), FATAL)
1317 allocate(ryr(nrecords), rmo(nrecords), rdy(nrecords))
1318 call fms2_io_read_data(fileobj, 'yr', ryr)
1319 call fms2_io_read_data(fileobj, 'mo', rmo)
1320 call fms2_io_read_data(fileobj, 'dy', rdy)
1324 yr = ryr(k); mo = rmo(k)
1325 Adate = date_type( yr, mo, 0)
1327 if (verbose > 2 .and. mpp_pe() == 0) &
1328 print *, '....... checking ', Adate
1329 if (Date == Adate) ierr = 0
1330 if (yr == 0 .and. mo == Date%month) ierr = 0
1333 if (ierr .ne. 0) call mpp_error('amip_interp_mod', &
1334 'Model time is out of range not in SST data: '//trim(ncfilename), FATAL)
1335 deallocate(ryr, rmo, rdy)
1336 !PRINT *, 'New SST data: ', k, yr, mo, dy, Date%year, Date%month, Date%day, ryr(1), rmo(1)
1338 !---- check if climatological data should be used ----
1340 if (yr == 0 .or. mo == 0) then
1342 if (date_out_of_range == 'fail' ) ierr = 1
1343 if (date_out_of_range == 'initclimo' .and. &
1344 Date > Date_end ) ierr = 1
1345 if (ierr /= 0) call error_mesg &
1346 ('read_record in amip_interp_mod', &
1347 'climo data read when NO climo data requested', FATAL)
1350 !---- read NETCDF data ----
1352 if ( interp_oi_sst ) then
1353 call fms2_io_read_data(fileobj, ncfieldname, tmp_dat, unlim_dim_level=k)
1354 ! interpolate tmp_dat(360, 180) ---> dat(mobs,nobs) (to enable SST anom computation)
1355 if ( mobs/=360 .or. nobs/=180 ) then
1356 call a2a_bilinear(360, 180, tmp_dat, mobs, nobs, dat)
1358 dat(:,:) = tmp_dat(:,:)
1361 call fms2_io_read_data(fileobj, ncfieldname, dat, unlim_dim_level=k)
1363 idat = nint(dat, I2_KIND) ! reconstruct packed data for reproducibility
1365 !---- unpacking of data ----
1367 if (type(1:3) == 'ice') then
1368 !---- create fractional [0,1] ice mask
1369 if (lowercase(trim(data_set)) /= 'amip2' .and. lowercase(trim(data_set)) /= 'hurrell') then
1370 where ( idat <= ice_crit )
1378 else if (type(1:3) == 'sst') then
1379 !---- unpack sst ----
1380 if (lowercase(trim(data_set)) /= 'amip2' .and. lowercase(trim(data_set)) /= 'hurrell') then
1381 dat = real(idat)*0.01 + TFREEZE
1387 end subroutine read_record
1389 !#######################################################################
1391 subroutine clip_data (type, dat)
1393 character(len=*), intent(in) :: type
1394 real, intent(inout) :: dat(:,:)
1396 if (type(1:3) == 'ice') then
1397 dat = min(max(dat,0.0),1.0)
1398 else if (type(1:3) == 'sst') then
1399 dat = max(tice_crit_k,dat)
1402 end subroutine clip_data
1404 !#######################################################################
1406 !> @return logical answer
1407 function date_equals (Left, Right) result (answer)
1408 type (date_type), intent(in) :: Left, Right
1411 if (Left % year == Right % year .and. &
1412 Left % month == Right % month .and. &
1413 Left % day == Right % day ) then
1419 end function date_equals
1421 !#######################################################################
1423 !> @return logical answer
1424 function date_not_equals (Left, Right) result (answer)
1425 type (date_type), intent(in) :: Left, Right
1428 if (Left % year == Right % year .and. &
1429 Left % month == Right % month .and. &
1430 Left % day == Right % day ) then
1436 end function date_not_equals
1438 !#######################################################################
1440 !> @return logical answer
1441 function date_gt (Left, Right) result (answer)
1442 type (date_type), intent(in) :: Left, Right
1444 integer :: i, dif(3)
1446 dif(1) = Left%year - Right%year
1447 dif(2) = Left%month - Right%month
1448 dif(3) = Left%day - Right%day
1451 if (dif(i) == 0) cycle
1452 if (dif(i) < 0) exit
1453 if (dif(i) > 0) then
1459 end function date_gt
1461 !#######################################################################
1463 subroutine print_dates (Time, Date1, Udate1, &
1464 Date2, Udate2, fmonth)
1466 type (time_type), intent(in) :: Time
1467 type (date_type), intent(in) :: Date1, Udate1, Date2, Udate2
1468 real, intent(in) :: fmonth
1470 integer :: year, month, day, hour, minute, second
1472 call get_date (Time, year, month, day, hour, minute, second)
1474 write (*,10) year,month,day, hour,minute,second
1476 write (*,30) Date1, Udate1
1477 write (*,40) Date2, Udate2
1479 10 format (/,' date(y/m/d h:m:s) = ',i4,2('/',i2.2),1x,2(i2.2,':'),i2.2)
1480 20 format (' fmonth = ',f9.7)
1481 30 format (' date1(y/m/d) = ',i4,2('/',i2.2),6x, &
1482 'used = ',i4,2('/',i2.2),6x )
1483 40 format (' date2(y/m/d) = ',i4,2('/',i2.2),6x, &
1484 'used = ',i4,2('/',i2.2),6x )
1486 end subroutine print_dates
1488 !#######################################################################
1490 subroutine zonal_sst (Time, ice, sst)
1492 type (time_type), intent(in) :: Time
1493 real, intent(out) :: ice(mobs,nobs), sst(mobs,nobs)
1495 real :: tpi, fdate, eps, ph, sph, sph2, ts
1500 ! teq = sst at equator
1501 ! tdif = equator to pole sst difference
1502 ! tann = amplitude of annual cycle
1503 ! tlag = offset for time of year (for annual cycle)
1508 fdate = fraction_of_year (Time)
1510 eps = sin( tpi*(fdate-tlag) ) * tann
1514 ph = 0.5*(lat_bnd(j)+lat_bnd(j+1))
1518 ts = teq - tdif*sph2 - eps*sph
1524 where ( sst < tice_crit_k )
1532 end subroutine zonal_sst
1534 !#######################################################################
1536 subroutine amip_interp_type_eq(amip_interp_out, amip_interp_in)
1537 type(amip_interp_type), intent(inout) :: amip_interp_out
1538 type(amip_interp_type), intent(in) :: amip_interp_in
1540 if(.not.amip_interp_in%I_am_initialized) then
1541 call mpp_error(FATAL,'amip_interp_type_eq: amip_interp_type variable on right hand side is unassigned')
1544 amip_interp_out%Hintrp = amip_interp_in%Hintrp
1545 amip_interp_out%data1 => amip_interp_in%data1
1546 amip_interp_out%data2 => amip_interp_in%data2
1547 amip_interp_out%Date1 = amip_interp_in%Date1
1548 amip_interp_out%Date2 = amip_interp_in%Date2
1549 amip_interp_out%Date1 = amip_interp_in%Date1
1550 amip_interp_out%Date2 = amip_interp_in%Date2
1551 amip_interp_out%use_climo = amip_interp_in%use_climo
1552 amip_interp_out%use_annual = amip_interp_in%use_annual
1553 amip_interp_out%I_am_initialized = .true.
1555 end subroutine amip_interp_type_eq
1557 !#######################################################################
1559 end module amip_interp_mod
1564 ! Add AMIP 2 data set.
1566 ! Other data sets (or extend current data sets).