No description
subroutine cart_to_latlon(np, q, xs, ys)
! vector version of cart_to_latlon1
integer, intent(in):: np
real, intent(inout):: q(3,np)
real, intent(inout):: xs(np), ys(np)
! local
real, parameter:: esl=1.e-10
real (f_p):: p(3)
real (f_p):: dist, lat, lon
integer i,k
do i=1,np
do k=1,3
p(k) = q(k,i)
enddo
dist = sqrt(p(1)**2 + p(2)**2 + p(3)**2)
do k=1,3
p(k) = p(k) / dist
enddo
if ( (abs(p(1))+abs(p(2))) < esl ) then
lon = 0.
else
lon = atan2( p(2), p(1) ) ! range [-pi,pi]
endif
if ( lon < 0.) lon = 2.*pi + lon
lat = asin(p(3))
xs(i) = lon
ys(i) = lat
! q Normalized:
do k=1,3
q(k,i) = p(k)
enddo
enddo
end subroutine cart_to_latlon
!
!---------------------------------------------------------------------
!> \brief latlon2xyz receives the variable p as input and returns e
!! as output in order to map (lon, lat) to (x,y,z).
!!
!! \param [in] No description
!! \param [out] No description
subroutine latlon2xyz(p, e)
!
! Routine to map (lon, lat) to (x,y,z)
!
real, intent(in) :: p(2)
real, intent(out):: e(3)
integer n
real (f_p):: q(2)
real (f_p):: e1, e2, e3
do n=1,2
q(n) = p(n)
enddo
e1 = cos(q(2)) * cos(q(1))
e2 = cos(q(2)) * sin(q(1))
e3 = sin(q(2))
!-----------------------------------
! Truncate to the desired precision:
!-----------------------------------
e(1) = e1
e(2) = e2
e(3) = e3
end subroutine latlon2xyz
!
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief check_climo_units checks the units that the climatology
!! data is using. This is needed to allow for conversion of
!! datasets to mixing ratios which is what the vertical
!! interpolation scheme requires. The default is to assume no
!! conversion is needed. If the units are those of a column
!! burden (kg/m2) then conversion to mixing ratio is flagged.
!!
!! \param [in] The units which you will be checking
function check_climo_units(units)
! Function to check the units that the climatology data is using.
! This is needed to allow for conversion of datasets to mixing ratios which is what the
! vertical interpolation scheme requires
! The default is to assume no conversion is needed.
! If the units are those of a column burden (kg/m2) then conversion to mixing ratio is flagged.
!
character(len=*), intent(in) :: units
integer :: check_climo_units
check_climo_units = NO_CONV
select case(chomp(units))
case('kg/m2', 'kg/m^2', 'kg/m**2', 'kg m^-2', 'kg m**-2')
check_climo_units = KG_M2
case('molecules/cm2/s', 'molecule/cm2/s', 'molec/cm2/s')
check_climo_units = KG_M2
case('kg/m2/s')
check_climo_units = KG_M2
end select
end function check_climo_units
!
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief init_clim_diag is a routine to register diagnostic fields
!! for the climatology file. This routine calculates the domain
!! decompostion of the climatology fields for later export
!! through send_data. The ids created here are for column
!! burdens that will diagnose the vertical interpolation
!! routine.
!!
!! \param [inout] The interpolate type containing the
!! names of the fields in the climatology file
!! \param [in] The axes of the model
!! \param [in] The model initialization time
!!
!! \throw FATAL, "init_clim_diag : You must call interpolator_init before calling init_clim_diag"
!! \throw FATAL, "init_clim_diag : Trying to set up too many diagnostic fields for the climatology data"
subroutine init_clim_diag(clim_type, mod_axes, init_time)
!
! Routine to register diagnostic fields for the climatology file.
! This routine calculates the domain decompostion of the climatology fields
! for later export through send_data.
! The ids created here are for column burdens that will diagnose the vertical interpolation routine.
! climo_diag_id : 'module_name = climo' is intended for use with the model vertical resolution.
! hinterp_id : 'module_name = 'hinterp' is intended for use with the climatology vertical resolution.
! INTENT INOUT :
! clim_type : The interpolate type containing the names of the fields in the climatology file.
!
! INTENT IN :
! mod_axes : The axes of the model.
! init_time : The model initialization time.
!
type(interpolate_type), intent(inout) :: clim_type
integer , intent(in) :: mod_axes(:)
type(time_type) , intent(in) :: init_time
integer :: axes(2),nxd,nyd,ndivs,i
type(domain2d) :: domain
integer :: domain_layout(2), iscomp, iecomp,jscomp,jecomp
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "init_clim_diag : You must call interpolator_init before calling init_clim_diag")
ndivs = mpp_npes()
nxd = size(clim_type%lon(:))
nyd = size(clim_type%lat(:))
! Define the domain decomposition of the climatology file. This may be (probably is) different from the model domain.
call mpp_define_layout ((/1,nxd,1,nyd/), ndivs, domain_layout)
call mpp_define_domains((/1,nxd,1,nyd/),domain_layout, domain,xhalo=0,yhalo=0)
call mpp_get_compute_domain (domain, iscomp, iecomp, jscomp, jecomp)
axes(1) = diag_axis_init(clim_type%file_name(1:5)//'x',clim_type%lon,units='degrees',cart_name='x',domain2=domain)
axes(2) = diag_axis_init(clim_type%file_name(1:5)//'y',clim_type%lat,units='degrees',cart_name='y',domain2=domain)
clim_type%is = iscomp
clim_type%ie = iecomp
clim_type%js = jscomp
clim_type%je = jecomp
!init_time = set_date(1980,1,1,0,0,0)
if ((num_clim_diag + size(clim_type%field_name(:))) .gt. max_diag_fields ) &
call mpp_error(FATAL, "init_clim_diag : Trying to set up too many diagnostic fields for the climatology data")
do i=1,size(clim_type%field_name(:))
climo_diag_name(i+num_clim_diag) = clim_type%field_name(i)
climo_diag_id(i+num_clim_diag) = register_diag_field('climo',clim_type%field_name(i),axes(1:2),init_time,&
'climo_'//clim_type%field_name(i), 'kg/kg', missing_value)
hinterp_id(i+num_clim_diag) = register_diag_field('hinterp',clim_type%field_name(i),mod_axes(1:2),init_time,&
'interp_'//clim_type%field_name(i),'kg/kg' , missing_value)
enddo
! Total number of climatology diagnostics (num_clim_diag). This can be from multiple climatology fields with different spatial axes.
! It is simply a holder for the diagnostic indices.
num_clim_diag = num_clim_diag+size(clim_type%field_name(:))
clim_diag_initialized = .true.
end subroutine init_clim_diag
!
!---------------------------------------------------------------------
!> \brief obtain_interpolator_time_slices makes sure that the
!! appropriate time slices are available for interpolation on
!! this time step.
!!
!! \param [inout] The interpolate type previously defined
!! by a call to interpolator_init
!! \param [in] The model time that you wish to interpolate to
!!
!! \throw FATAL "interpolator_timeslice 1: file="
!! \throw FATAL "interpolator_timeslice 2: file="
!! \throw FATAL "interpolator_timeslice 3: file="
!! \throw FATAL "interpolator_timeslice 4: file="
!! \throw FATAL "interpolator_timeslice 5: file="
!! \throw FATAL "interpolator_timeslice : No data from the previous
!! climatology time but we have the next time. How did
!! this happen?"
subroutine obtain_interpolator_time_slices (clim_type, Time)
! Makes sure that appropriate time slices are available for interpolation
! on this time step
!
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
!
! INTENT IN
! Time : The model time that you wish to interpolate to.
type(interpolate_type), intent(inout) :: clim_type
type(time_type) , intent(in) :: Time
integer :: taum, taup
integer :: modyear, modmonth, modday, modhour, modminute, modsecond
integer :: climyear, climmonth, climday, climhour, climminute, climsecond
integer :: year1, month1, day, hour, minute, second
integer :: climatology, m
type(time_type) :: t_prev, t_next
type(time_type), dimension(2) :: month
integer :: indexm, indexp, yearm, yearp
integer :: i, n
character(len=256) :: err_msg
if (clim_type%climatological_year) then
!++lwh
if (size(clim_type%time_slice) > 1) then
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, modtime=YEAR, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_timeslice 1: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
else
taum = 1
taup = 1
clim_type%tweight = 0.
end if
!--lwh
else
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_timeslice 2: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
endif
if(clim_type%TIME_FLAG .eq. BILINEAR ) then
! Check if delta-time is greater than delta of first two climatology time-slices.
if ( (Time - clim_type%time_slice(taum) ) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) .or. &
(clim_type%time_slice(taup) - Time) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) ) then
! The difference between the model time and the last climatology time-slice previous to the model time.
! We need 2 time levels.
clim_type%itaum=0
clim_type%itaup=0
! Assume this is monthly data. So we need to get the data applicable to the model date but substitute
! the climatology year into the appropriate place.
! We need to get the previous months data for the climatology year before
! and after the model year.
call get_date(Time, modyear, modmonth, modday, modhour, modminute, modsecond)
call get_date(clim_type%time_slice(taum), climyear, climmonth, climday, climhour, climminute, climsecond)
climatology = 1
do m = 1, size(clim_type%clim_times(:,:),2)
!Assume here that a climatology is for 1 year and consists of 12 months starting in January.
call get_date(clim_type%clim_times(1,m), year1, month1, day, hour, minute, second)
if (year1 == climyear) climatology = m
enddo
do m = 1,12
!Find which month we are trying to look at and set clim_date[mp] to the dates spanning that.
call get_date(clim_type%clim_times(m,climatology), year1, month1, day, hour, minute, second)
if ( month1 == modmonth ) then
!RSHBUGFX if ( modday <= day ) then
if ( modday < day ) then
indexm = m-1 ; indexp = m
else
indexm = m ; indexp = m+1
endif
endif
enddo
if ( indexm == 0 ) then
indexm = 12
yearm = modyear - 1
else
yearm = modyear
endif
call get_date(clim_type%time_slice(indexm+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(1) = set_date(yearm, indexm, climday, climhour, climminute, climsecond)
if ( indexp == 13 ) then
indexp = 1
yearp = modyear + 1
else
yearp = modyear
endif
call get_date(clim_type%time_slice(indexp+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(2) = set_date(yearp, indexp, climday, climhour, climminute, climsecond)
call time_interp(Time, month, clim_type%tweight3, taum, taup, err_msg=err_msg ) ! tweight3 is the time weight between the months.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight3 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_timeslice 3: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexm+(climatology-1)*12)
month(2) = clim_type%time_slice(indexm+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_prev = set_date(yearm, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_prev, month, clim_type%tweight1, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight1 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_timeslice 4: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexp+(climatology-1)*12)
month(2) = clim_type%time_slice(indexp+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_next = set_date(yearp, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_next, month, clim_type%tweight2, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight2 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_timeslice 5: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
if (indexm == clim_type%indexm(1) .and. &
indexp == clim_type%indexp(1) .and. &
climatology == clim_type%climatology(1)) then
else
clim_type%indexm(:) = indexm
clim_type%indexp(:) = indexp
clim_type%climatology(:) = climatology
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), &
clim_type%indexm(i)+(clim_type%climatology(i)-1)*12,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), &
clim_type%indexp(i)+(clim_type%climatology(i)-1)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_nyear(:,:,:,i), &
clim_type%indexm(i)+clim_type%climatology(i)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_nyear(:,:,:,i), &
clim_type%indexp(i)+clim_type%climatology(i)*12,i,Time)
end do
endif
else ! We are within a climatology data set
do i=1, size(clim_type%field_name(:))
if (taum /= clim_type%time_init(i,1) .or. &
taup /= clim_type%time_init(i,2) ) then
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), taum,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), taup,i,Time)
clim_type%time_init(i,1) = taum
clim_type%time_init(i,2) = taup
endif
end do
! clim_type%pmon_nyear = 0.0
! clim_type%nmon_nyear = 0.0
! set to zero so when next return to bilinear section will be sure to
! have proper data (relevant when running fixed_year case for more than
! one year in a single job)
clim_type%indexm(:) = 0
clim_type%indexp(:) = 0
clim_type%climatology(:) = 0
! clim_type%tweight3 = 0.0 ! This makes [pn]mon_nyear irrelevant. Set them to 0 to test.
clim_type%tweight1 = 0.0
clim_type%tweight2 = 0.0
clim_type%tweight3 = clim_type%tweight
endif
endif !(BILINEAR)
if(clim_type%TIME_FLAG .eq. LINEAR .and. &
(.not. read_all_on_init) ) then
! We need 2 time levels. Check we have the correct data.
clim_type%itaum=0
clim_type%itaup=0
do n=1,size(clim_type%time_init,2)
if (clim_type%time_init(1,n) .eq. taum ) clim_type%itaum = n
if (clim_type%time_init(1,n) .eq. taup ) clim_type%itaup = n
enddo
if (clim_type%itaum.eq.0 .and. clim_type%itaup.eq.0) then
!Neither time is set so we need to read 2 time slices.
!Set up
! field(:,:,:,1) as the previous time slice.
! field(:,:,:,2) as the next time slice.
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,1,i), taum,i,Time)
clim_type%time_init(i,1) = taum
clim_type%itaum = 1
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,2,i), taup,i,Time)
clim_type%time_init(i,2) = taup
clim_type%itaup = 2
end do
endif ! clim_type%itaum.eq.clim_type%itaup.eq.0
if (clim_type%itaum.eq.0 .and. clim_type%itaup.ne.0) then
! Can't think of a situation where we would have the next time level but not the previous.
call mpp_error(FATAL,'interpolator_timeslice : No data from the previous climatology time &
& but we have the next time. How did this happen?')
endif
if (clim_type%itaum.ne.0 .and. clim_type%itaup.eq.0) then
!We have the previous time step but not the next time step data
clim_type%itaup = 1
if (clim_type%itaum .eq. 1 ) clim_type%itaup = 2
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,clim_type%itaup,i), taup,i, Time)
clim_type%time_init(i,clim_type%itaup)=taup
end do
endif
endif! TIME_FLAG
clim_type%separate_time_vary_calc = .true.
!-------------------------------------------------------------------
end subroutine obtain_interpolator_time_slices
!#####################################################################
!
!---------------------------------------------------------------------
!> \brief unset_interpolator_time_flag sets a flag in clim_type to
!! false.
!!
!! \param [inout] The interpolate type containing the names of the fields in the climatology file
subroutine unset_interpolator_time_flag (clim_type)
type(interpolate_type), intent(inout) :: clim_type
clim_type%separate_time_vary_calc = .false.
end subroutine unset_interpolator_time_flag
!#####################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_4D receives a field name as input and
!! interpolates the field to model a 4D grid and time axis.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] The model time that you wish to interpolate to
!! \param [in] The half level model pressure field
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_4D : You must call interpolator_init
!! before calling interpolator"
!! \throw FATAL "interpolator_mod: cannot use 4D interface to interpolator for this file"
!! \throw FATAL "interpolator_4D 1: file="
!! \throw FATAL "interpolator_4D 2: file="
!! \throw FATAL "interpolator_4D 3: file="
!! \throw FATAL "interpolator_4D 4: file="
!! \throw FATAL "interpolator_4D 5: file="
!! \throw FATAL "interpolator_3D : No data from the previous climatology
!! time but we have the next time. How did this happen?"
!! \throw NOTE "Interpolator: model surface pressure is greater than
!! climatology surface pressure for "
!! \throw NOTE "Interpolator: model top pressure is less than
!! climatology top pressure for "
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_4D(clim_type, Time, phalf, interp_data, &
field_name, is,js, clim_units)
!
! Return 4-D field interpolated to model grid and time
!
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
!
! INTENT IN
! field_name : The name of a field that you wish to interpolate.
! all variables within this interpolate_type variable
! will be interpolated on this call. field_name may
! be any one of the variables.
! Time : The model time that you wish to interpolate to.
! phalf : The half level model pressure field.
! is, js : The indices of the physics window.
!
! INTENT OUT
! interp_data : The model fields with the interpolated climatology data.
! clim_units : The units of field_name
!
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
type(time_type) , intent(in) :: Time
real, dimension(:,:,:), intent(in) :: phalf
real, dimension(:,:,:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
integer :: taum, taup, ilon
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:)),size(clim_type%field_name(:)))
real :: p_fact(size(interp_data,1),size(interp_data,2))
real :: col_data(size(interp_data,1),size(interp_data,2), &
size(clim_type%field_name(:)))
real :: pclim(size(clim_type%halflevs(:)))
integer :: istart,iend,jstart,jend
logical :: result, found
logical :: found_field=.false.
integer :: modyear, modmonth, modday, modhour, modminute, modsecond
integer :: climyear, climmonth, climday, climhour, climminute, climsecond
integer :: year1, month1, day, hour, minute, second
integer :: climatology, m
type(time_type) :: t_prev, t_next
type(time_type), dimension(2) :: month
integer :: indexm, indexp, yearm, yearp
integer :: i, j, k, n
character(len=256) :: err_msg
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_4D : You must call interpolator_init before calling interpolator")
do n=2,size(clim_type%field_name(:))
if (clim_type%vert_interp(n) /= clim_type%vert_interp(n-1) .or. &
clim_type%out_of_bounds(n) /= clim_type%out_of_bounds(n-1)) then
if (mpp_pe() == mpp_root_pe() ) then
print *, 'processing file ' // trim(clim_type%file_name)
endif
call mpp_error (FATAL, 'interpolator_mod: &
&cannot use 4D interface to interpolator for this file')
endif
end do
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
!!++lwh
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
!--lwh
found_field=.true.
exit
endif
end do
i = 1
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
!----------------------------------------------------------------------
! skip the time interpolation portion of this routine if subroutine
! obtain_interpolator_time_slices has already been called on this
! stewp for this interpolate_type variable.
!----------------------------------------------------------------------
if ( .not. clim_type%separate_time_vary_calc) then
! print *, 'TIME INTERPOLATION NOT SEPARATED 4d--', &
! trim(clim_type%file_name), mpp_pe()
if (clim_type%climatological_year) then
!++lwh
if (size(clim_type%time_slice) > 1) then
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, modtime=YEAR, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_4D 1: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
else
taum = 1
taup = 1
clim_type%tweight = 0.
end if
!--lwh
else
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_4D 2: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
endif
if(clim_type%TIME_FLAG .eq. BILINEAR ) then
! Check if delta-time is greater than delta of first two climatology time-slices.
if ( (Time - clim_type%time_slice(taum) ) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) .or. &
(clim_type%time_slice(taup) - Time) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) ) then
! The difference between the model time and the last climatology time-slice previous to the model time.
! We need 2 time levels.
clim_type%itaum=0
clim_type%itaup=0
! Assume this is monthly data. So we need to get the data applicable to the model date but substitute
! the climatology year into the appropriate place.
! We need to get the previous months data for the climatology year before
! and after the model year.
call get_date(Time, modyear, modmonth, modday, modhour, modminute, modsecond)
call get_date(clim_type%time_slice(taum), climyear, climmonth, climday, climhour, climminute, climsecond)
climatology = 1
do m = 1, size(clim_type%clim_times(:,:),2)
!Assume here that a climatology is for 1 year and consists of 12 months starting in January.
call get_date(clim_type%clim_times(1,m), year1, month1, day, hour, minute, second)
if (year1 == climyear) climatology = m
enddo
do m = 1,12
!Find which month we are trying to look at and set clim_date[mp] to the dates spanning that.
call get_date(clim_type%clim_times(m,climatology), year1, month1, day, hour, minute, second)
if ( month1 == modmonth ) then
!RSHBUGFX if ( modday <= day ) then
if ( modday < day ) then
indexm = m-1 ; indexp = m
else
indexm = m ; indexp = m+1
endif
endif
enddo
if ( indexm == 0 ) then
indexm = 12
yearm = modyear - 1
else
yearm = modyear
endif
call get_date(clim_type%time_slice(indexm+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(1) = set_date(yearm, indexm, climday, climhour, climminute, climsecond)
if ( indexp == 13 ) then
indexp = 1
yearp = modyear + 1
else
yearp = modyear
endif
call get_date(clim_type%time_slice(indexp+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(2) = set_date(yearp, indexp, climday, climhour, climminute, climsecond)
call time_interp(Time, month, clim_type%tweight3, taum, taup, err_msg=err_msg ) ! tweight3 is the time weight between the months.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight3 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_4D 3: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexm+(climatology-1)*12)
month(2) = clim_type%time_slice(indexm+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_prev = set_date(yearm, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_prev, month, clim_type%tweight1, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight1 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_4D 4: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexp+(climatology-1)*12)
month(2) = clim_type%time_slice(indexp+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_next = set_date(yearp, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_next, month, clim_type%tweight2, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight2 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_4D 5: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
if (indexm == clim_type%indexm(1) .and. &
indexp == clim_type%indexp(1) .and. &
climatology == clim_type%climatology(1)) then
else
clim_type%indexm(:) = indexm
clim_type%indexp(:) = indexp
clim_type%climatology(:) = climatology
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), &
clim_type%indexm(i)+(clim_type%climatology(i)-1)*12,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), &
clim_type%indexp(i)+(clim_type%climatology(i)-1)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_nyear(:,:,:,i), &
clim_type%indexm(i)+clim_type%climatology(i)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_nyear(:,:,:,i), &
clim_type%indexp(i)+clim_type%climatology(i)*12,i,Time)
end do
endif
else ! We are within a climatology data set
do i=1, size(clim_type%field_name(:))
if (taum /= clim_type%time_init(i,1) .or. &
taup /= clim_type%time_init(i,2) ) then
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), taum,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), taup,i,Time)
clim_type%time_init(i,1) = taum
clim_type%time_init(i,2) = taup
endif
end do
! clim_type%pmon_nyear = 0.0
! clim_type%nmon_nyear = 0.0
! set to zero so when next return to bilinear section will be sure to
! have proper data (relevant when running fixed_year case for more than
! one year in a single job)
clim_type%indexm(:) = 0
clim_type%indexp(:) = 0
clim_type%climatology(:) = 0
! clim_type%tweight3 = 0.0 ! This makes [pn]mon_nyear irrelevant. Set them to 0 to test.
clim_type%tweight1 = 0.0
clim_type%tweight2 = 0.0
clim_type%tweight3 = clim_type%tweight
endif
endif !(BILINEAR)
if(clim_type%TIME_FLAG .eq. LINEAR .and. &
(.not. read_all_on_init) ) then
! We need 2 time levels. Check we have the correct data.
clim_type%itaum=0
clim_type%itaup=0
do n=1,size(clim_type%time_init,2)
if (clim_type%time_init(1,n) .eq. taum ) clim_type%itaum = n
if (clim_type%time_init(1,n) .eq. taup ) clim_type%itaup = n
enddo
if (clim_type%itaum.eq.0 .and. clim_type%itaup.eq.0) then
!Neither time is set so we need to read 2 time slices.
!Set up
! field(:,:,:,1) as the previous time slice.
! field(:,:,:,2) as the next time slice.
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,1,i), taum,i,Time)
clim_type%time_init(i,1) = taum
clim_type%itaum = 1
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,2,i), taup,i,Time)
clim_type%time_init(i,2) = taup
clim_type%itaup = 2
end do
endif ! clim_type%itaum.eq.clim_type%itaup.eq.0
if (clim_type%itaum.eq.0 .and. clim_type%itaup.ne.0) then
! Can't think of a situation where we would have the next time level but not the previous.
call mpp_error(FATAL,'interpolator_3D : No data from the previous climatology time &
& but we have the next time. How did this happen?')
endif
if (clim_type%itaum.ne.0 .and. clim_type%itaup.eq.0) then
!We have the previous time step but not the next time step data
clim_type%itaup = 1
if (clim_type%itaum .eq. 1 ) clim_type%itaup = 2
do i=1, size(clim_type%field_name(:))
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,clim_type%itaup,i), taup,i, Time)
clim_type%time_init(i,clim_type%itaup)=taup
end do
endif
endif! TIME_FLAG
endif ! (.not. separate_time_vary_calc)
select case(clim_type%TIME_FLAG)
case (LINEAR)
do n=1, size(clim_type%field_name(:))
hinterp_data(:,:,:,n) = (1.-clim_type%tweight)* &
clim_type%data(istart:iend,jstart:jend,:,clim_type%itaum,n) + &
clim_type%tweight* &
clim_type%data(istart:iend,jstart:jend,:,clim_type%itaup,n)
end do
! case (SEASONAL)
! Do sine fit to data at this point
case (BILINEAR)
do n=1, size(clim_type%field_name(:))
hinterp_data(:,:,:,n) = (1.-clim_type%tweight1)*(1.-clim_type%tweight3)* &
clim_type%pmon_pyear(istart:iend,jstart:jend,:,n) + &
(1.-clim_type%tweight2)*clim_type%tweight3* &
clim_type%nmon_pyear(istart:iend,jstart:jend,:,n) + &
clim_type%tweight1* (1.-clim_type%tweight3)* &
clim_type%pmon_nyear(istart:iend,jstart:jend,:,n) + &
clim_type%tweight2* clim_type%tweight3* &
clim_type%nmon_nyear(istart:iend,jstart:jend,:,n)
end do
end select
select case(clim_type%level_type)
case(PRESSURE)
p_fact = 1.0
case(SIGMA)
p_fact = maxval(phalf,3)! max pressure in the column !(:,:,size(phalf,3))
end select
col_data(:,:,:)=0.0
do i= 1, size(clim_type%field_name(:))
select case(clim_type%mr(i))
case(NO_CONV)
do k = 1,size(hinterp_data,3)
col_data(:,:,i) = col_data(:,:,i) + hinterp_data(:,:,k,i)* &
(clim_type%halflevs(k+1)-clim_type%halflevs(k))/grav
enddo
case(KG_M2)
do k = 1,size(hinterp_data,3)
col_data(:,:,i) = col_data(:,:,i) + hinterp_data(:,:,k,i)
hinterp_data(:,:,k,i) = hinterp_data(:,:,k,i)/ &
((clim_type%halflevs(k+1)-clim_type%halflevs(k))*p_fact)
enddo
end select
enddo
do i= 1, size(clim_type%field_name(:))
found = .false.
do j = 1,size(climo_diag_name(:))
if ( trim(adjustl(lowercase(climo_diag_name(j)))) .eq. trim(adjustl(lowercase(clim_type%field_name(i))))) then
found = .true.
exit
endif
enddo
if (found) then
if (hinterp_id(j) > 0 ) then
result = send_data(hinterp_id(j),col_data(:,:,i),Time,is_in=istart,js_in=jstart)
endif
endif
end do
i = 1
!++lwh
do j = 1, size(phalf,2)
do ilon=1,size(phalf,1)
pclim = p_fact(ilon,j)*clim_type%halflevs
if ( maxval(phalf(ilon,j,:)) > maxval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model surface pressure&
& is greater than climatology surface pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( maxloc(pclim) ) = maxval( phalf(ilon,j,:) )
! case(ZERO)
! pclim( maxloc(pclim)) = 0
end select
endif
if ( minval(phalf(ilon,j,:)) < minval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model top pressure&
& is less than climatology top pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( minloc(pclim) ) = minval( phalf(ilon,j,:) )
! case(ZERO)
! pclim( maxloc(pclim)) = 0
end select
endif
select case(clim_type%vert_interp(i))
case(INTERP_WEIGHTED_P)
call interp_weighted_scalar(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:,:),interp_data(ilon,j,:,:))
case(INTERP_LINEAR_P)
do n=1, size(clim_type%field_name(:))
call interp_linear(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:,n),interp_data(ilon,j,:,n))
end do
! case(INTERP_LOG)
end select
enddo
enddo
!--lwh
do i= 1, size(clim_type%field_name(:))
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(interp_data,3)
interp_data(:,:,k,i) = interp_data(:,:,k,i)*(phalf(:,:,k+1)-phalf(:,:,k))
enddo
end select
end do
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_4D
!
!#######################################################################
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_3D receives a field name as input and
!! interpolates the field to model a 3D grid and time axis.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] The model time that you wish to interpolate to
!! \param [in] The half level model pressure field
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_3D : You must call interpolator_init
!! before calling interpolator"
!! \throw FATAL "interpolator_3D 1: file="
!! \throw FATAL "interpolator_3D 2: file="
!! \throw FATAL "interpolator_3D 3: file="
!! \throw FATAL "interpolator_3D 4: file="
!! \throw FATAL "interpolator_3D 5: file="
!! \throw FATAL "interpolator_3D : No data from the previous climatology
!! time but we have the next time. How did this happen?"
!! \throw NOTE "Interpolator: model surface pressure is greater than
!! climatology surface pressure for "
!! \throw NOTE "Interpolator: model top pressure is less than
!! climatology top pressure for "
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_3D(clim_type, Time, phalf, interp_data,field_name, is,js, clim_units)
!
! Return 3-D field interpolated to model grid and time
!
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
!
! INTENT IN
! field_name : The name of the field that you wish to interpolate.
! Time : The model time that you wish to interpolate to.
! phalf : The half level model pressure field.
! is, js : The indices of the physics window.
!
! INTENT OUT
! interp_data : The model field with the interpolated climatology data.
! clim_units : The units of field_name
!
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
type(time_type) , intent(in) :: Time
real, dimension(:,:,:), intent(in) :: phalf
real, dimension(:,:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
integer :: taum, taup, ilon
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:)))
real :: p_fact(size(interp_data,1),size(interp_data,2))
real :: col_data(size(interp_data,1),size(interp_data,2))
real :: pclim(size(clim_type%halflevs(:)))
integer :: istart,iend,jstart,jend
logical :: result, found
logical :: found_field=.false.
integer :: modyear, modmonth, modday, modhour, modminute, modsecond
integer :: climyear, climmonth, climday, climhour, climminute, climsecond
integer :: year1, month1, day, hour, minute, second
integer :: climatology, m
type(time_type) :: t_prev, t_next
type(time_type), dimension(2) :: month
integer :: indexm, indexp, yearm, yearp
integer :: i, j, k, n
character(len=256) :: err_msg
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_3D : You must call interpolator_init before calling interpolator")
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
!++lwh
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
!--lwh
found_field=.true.
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
!----------------------------------------------------------------------
! skip the time interpolation portion of this routine if subroutine
! obtain_interpolator_time_slices has already been called on this
! stewp for this interpolate_type variable.
!----------------------------------------------------------------------
if ( .not. clim_type%separate_time_vary_calc) then
! print *, 'TIME INTERPOLATION NOT SEPARATED 3d--', &
! trim(clim_type%file_name), mpp_pe()
if (clim_type%climatological_year) then
!++lwh
if (size(clim_type%time_slice) > 1) then
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, modtime=YEAR, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_3D 1: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
else
taum = 1
taup = 1
clim_type%tweight = 0.
end if
!--lwh
else
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_3D 2: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
endif
! if(clim_type%TIME_FLAG .ne. LINEAR ) then
if(clim_type%TIME_FLAG .ne. LINEAR .or. read_all_on_init ) then
clim_type%itaum=taum
clim_type%itaup=taup
endif
if(clim_type%TIME_FLAG .eq. BILINEAR ) then
! Check if delta-time is greater than delta of first two climatology time-slices.
if ( (Time - clim_type%time_slice(taum) ) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) .or. &
(clim_type%time_slice(taup) - Time) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) ) then
! The difference between the model time and the last climatology time-slice previous to the model time.
! We need 2 time levels.
clim_type%itaum=0
clim_type%itaup=0
! Assume this is monthly data. So we need to get the data applicable to the model date but substitute
! the climatology year into the appropriate place.
! We need to get the previous months data for the climatology year before
! and after the model year.
call get_date(Time, modyear, modmonth, modday, modhour, modminute, modsecond)
call get_date(clim_type%time_slice(taum), climyear, climmonth, climday, climhour, climminute, climsecond)
climatology = 1
do m = 1, size(clim_type%clim_times(:,:),2)
!Assume here that a climatology is for 1 year and consists of 12 months starting in January.
call get_date(clim_type%clim_times(1,m), year1, month1, day, hour, minute, second)
if (year1 == climyear) climatology = m
enddo
do m = 1,12
!Find which month we are trying to look at and set clim_date[mp] to the dates spanning that.
call get_date(clim_type%clim_times(m,climatology), year1, month1, day, hour, minute, second)
if ( month1 == modmonth ) then
!RSHBUGFX if ( modday <= day ) then
if ( modday < day ) then
indexm = m-1 ; indexp = m
else
indexm = m ; indexp = m+1
endif
endif
enddo
if ( indexm == 0 ) then
indexm = 12
yearm = modyear - 1
else
yearm = modyear
endif
call get_date(clim_type%time_slice(indexm+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(1) = set_date(yearm, indexm, climday, climhour, climminute, climsecond)
if ( indexp == 13 ) then
indexp = 1
yearp = modyear + 1
else
yearp = modyear
endif
call get_date(clim_type%time_slice(indexp+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(2) = set_date(yearp, indexp, climday, climhour, climminute, climsecond)
call time_interp(Time, month, clim_type%tweight3, taum, taup, err_msg=err_msg ) ! tweight3 is the time weight between the months.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight3 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_3D 3: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexm+(climatology-1)*12)
month(2) = clim_type%time_slice(indexm+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_prev = set_date(yearm, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_prev, month, clim_type%tweight1, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight1 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_3D 4: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexp+(climatology-1)*12)
month(2) = clim_type%time_slice(indexp+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_next = set_date(yearp, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_next, month, clim_type%tweight2, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight2 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_3D 5: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
if (indexm == clim_type%indexm(i) .and. &
indexp == clim_type%indexp(i) .and. &
climatology == clim_type%climatology(i)) then
else
clim_type%indexm(i) = indexm
clim_type%indexp(i) = indexp
clim_type%climatology(i) = climatology
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), &
clim_type%indexm(i)+(clim_type%climatology(i)-1)*12,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), &
clim_type%indexp(i)+(clim_type%climatology(i)-1)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_nyear(:,:,:,i), &
clim_type%indexm(i)+clim_type%climatology(i)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_nyear(:,:,:,i), &
clim_type%indexp(i)+clim_type%climatology(i)*12,i,Time)
endif
else ! We are within a climatology data set
if (taum /= clim_type%time_init(i,1) .or. &
taup /= clim_type%time_init(i,2) ) then
call read_data(clim_type,clim_type%field_type(i), clim_type%pmon_pyear(:,:,:,i), taum,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), clim_type%nmon_pyear(:,:,:,i), taup,i,Time)
!RSHbug clim_type%pmon_nyear = 0.0
!RSHbug clim_type%nmon_nyear = 0.0
! clim_type%pmon_nyear(:,:,:,i) = 0.0
! clim_type%nmon_nyear(:,:,:,i) = 0.0
! set to zero so when next return to bilinear section will be sure to
! have proper data (relevant when running fixed_year case for more than
! one year in a single job)
clim_type%indexm(i) = 0
clim_type%indexp(i) = 0
clim_type%climatology(i) = 0
clim_type%time_init(i,1) = taum
clim_type%time_init(i,2) = taup
endif
! clim_type%tweight3 = 0.0 ! This makes [pn]mon_nyear irrelevant. Set them to 0 to test.
clim_type%tweight1 = 0.0 ; clim_type%tweight2 = 0.0
clim_type%tweight3 = clim_type%tweight
endif
endif ! (BILINEAR)
if(clim_type%TIME_FLAG .eq. LINEAR .and. &
(.not. read_all_on_init) ) then
! We need 2 time levels. Check we have the correct data.
clim_type%itaum=0
clim_type%itaup=0
do n=1,size(clim_type%time_init,2)
if (clim_type%time_init(i,n) .eq. taum ) clim_type%itaum = n
if (clim_type%time_init(i,n) .eq. taup ) clim_type%itaup = n
enddo
if (clim_type%itaum.eq.0 .and. clim_type%itaup.eq.0) then
!Neither time is set so we need to read 2 time slices.
!Set up
! field(:,:,:,1) as the previous time slice.
! field(:,:,:,2) as the next time slice.
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,1,i), taum,i,Time)
clim_type%time_init(i,1) = taum
clim_type%itaum = 1
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,2,i), taup,i,Time)
clim_type%time_init(i,2) = taup
clim_type%itaup = 2
endif ! clim_type%itaum.eq.clim_type%itaup.eq.0
if (clim_type%itaum.eq.0 .and. clim_type%itaup.ne.0) then
! Can't think of a situation where we would have the next time level but not the previous.
call mpp_error(FATAL,'interpolator_3D : No data from the previous climatology time &
& but we have the next time. How did this happen?')
endif
if (clim_type%itaum.ne.0 .and. clim_type%itaup.eq.0) then
!We have the previous time step but not the next time step data
clim_type%itaup = 1
if (clim_type%itaum .eq. 1 ) clim_type%itaup = 2
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,clim_type%itaup,i), taup,i, Time)
clim_type%time_init(i,clim_type%itaup)=taup
endif
endif! TIME_FLAG
endif !( .not. clim_type%separate_time_vary_calc)
select case(clim_type%TIME_FLAG)
case (LINEAR)
hinterp_data = (1.-clim_type%tweight) * clim_type%data(istart:iend,jstart:jend,:,clim_type%itaum,i) + &
clim_type%tweight * clim_type%data(istart:iend,jstart:jend,:,clim_type%itaup,i)
! case (SEASONAL)
! Do sine fit to data at this point
case (BILINEAR)
hinterp_data = &
(1.-clim_type%tweight1) * (1.-clim_type%tweight3) * clim_type%pmon_pyear(istart:iend,jstart:jend,:,i) + &
(1.-clim_type%tweight2) * clim_type%tweight3 * clim_type%nmon_pyear(istart:iend,jstart:jend,:,i) + &
clim_type%tweight1 * (1.-clim_type%tweight3) * clim_type%pmon_nyear(istart:iend,jstart:jend,:,i) + &
clim_type%tweight2 * clim_type%tweight3 * clim_type%nmon_nyear(istart:iend,jstart:jend,:,i)
end select
select case(clim_type%level_type)
case(PRESSURE)
p_fact = 1.0
case(SIGMA)
p_fact = maxval(phalf,3)! max pressure in the column !(:,:,size(phalf,3))
end select
col_data(:,:)=0.0
select case(clim_type%mr(i))
case(NO_CONV)
do k = 1,size(hinterp_data,3)
col_data(:,:) = col_data(:,:) + hinterp_data(:,:,k)* &
(clim_type%halflevs(k+1)-clim_type%halflevs(k))/grav
enddo
case(KG_M2)
do k = 1,size(hinterp_data,3)
col_data(:,:) = col_data(:,:) + hinterp_data(:,:,k)
hinterp_data(:,:,k) = hinterp_data(:,:,k)/ &
((clim_type%halflevs(k+1)-clim_type%halflevs(k))*p_fact)
enddo
end select
found = .false.
do j = 1,size(climo_diag_name(:))
if ( trim(adjustl(lowercase(climo_diag_name(j)))) .eq. trim(adjustl(lowercase(clim_type%field_name(i))))) then
found = .true.
exit
endif
enddo
if (found) then
if (hinterp_id(j) > 0 ) then
result = send_data(hinterp_id(j),col_data,Time,is_in=istart,js_in=jstart)
endif
endif
!++lwh
do j = 1, size(phalf,2)
do ilon=1,size(phalf,1)
pclim = p_fact(ilon,j)*clim_type%halflevs
if ( maxval(phalf(ilon,j,:)) > maxval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model surface pressure&
& is greater than climatology surface pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( maxloc(pclim) ) = maxval( phalf(ilon,j,:) )
! case(ZERO)
! pclim( maxloc(pclim)) = 0
end select
endif
if ( minval(phalf(ilon,j,:)) < minval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model top pressure&
& is less than climatology top pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( minloc(pclim) ) = minval( phalf(ilon,j,:) )
! case(ZERO)
! pclim( maxloc(pclim)) = 0
end select
endif
select case(clim_type%vert_interp(i))
case(INTERP_WEIGHTED_P)
call interp_weighted_scalar(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:),interp_data(ilon,j,:))
case(INTERP_LINEAR_P)
call interp_linear(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:),interp_data(ilon,j,:))
! case(INTERP_LOG)
end select
enddo
enddo
!--lwh
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(interp_data,3)
interp_data(:,:,k) = interp_data(:,:,k)*(phalf(:,:,k+1)-phalf(:,:,k))
enddo
end select
endif !field_name
enddo !End of i loop
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_3D
!
!#######################################################################
!
!++lwh
!---------------------------------------------------------------------
!> \brief interpolator_2D receives a field name as input and
!! interpolates the field to model a 2D grid and time axis.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] The model time that you wish to interpolate to
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_2D : You must call interpolator_init
!! before calling interpolator"
!! \throw FATAL "interpolator_2D 1: file="
!! \throw FATAL "interpolator_2D 2: file="
!! \throw FATAL "interpolator_2D 3: file="
!! \throw FATAL "interpolator_2D 4: file="
!! \throw FATAL "interpolator_2D 5: file="
!! \throw FATAL "interpolator_2D : No data from the previous climatology
!! time but we have the next time. How did this happen?"
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_2D(clim_type, Time, interp_data, field_name, is, js, clim_units)
!
! Return 2-D field interpolated to model grid and time
!
!
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
!
! INTENT IN
! field_name : The name of the field that you wish to interpolate.
! Time : The model time that you wish to interpolate to.
! is, js : The indices of the physics window.
!
! INTENT OUT
! interp_data : The model field with the interpolated climatology data.
! clim_units : The units of field_name
!
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
type(time_type) , intent(in) :: Time
real, dimension(:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
integer :: taum, taup
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:)))
integer :: istart,iend,jstart,jend
logical :: result, found
logical :: found_field=.false.
integer :: modyear, modmonth, modday, modhour, modminute, modsecond
integer :: climyear, climmonth, climday, climhour, climminute, climsecond
integer :: year1, month1, day, hour, minute, second
integer :: climatology, m
type(time_type) :: t_prev, t_next
type(time_type), dimension(2) :: month
integer :: indexm, indexp, yearm, yearp
integer :: j, i, n
character(len=256) :: err_msg
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_2D : You must call interpolator_init before calling interpolator")
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
!++lwh
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
!--lwh
found_field=.true.
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
!----------------------------------------------------------------------
! skip the time interpolation portion of this routine if subroutine
! obtain_interpolator_time_slices has already been called on this
! stewp for this interpolate_type variable.
!----------------------------------------------------------------------
if ( .not. clim_type%separate_time_vary_calc) then
! print *, 'TIME INTERPOLATION NOT SEPARATED 2d--', &
! trim(clim_type%file_name), mpp_pe()
if (clim_type%climatological_year) then
!++lwh
if (size(clim_type%time_slice) > 1) then
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, modtime=YEAR, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_2D 1: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
else
taum = 1
taup = 1
clim_type%tweight = 0.
end if
!--lwh
else
call time_interp(Time, clim_type%time_slice, clim_type%tweight, taum, taup, err_msg=err_msg )
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_2D 2: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
endif
! If the climatology file has seasonal, a split time-line or has all the data
! read in then enter this loop.
!
if(clim_type%TIME_FLAG .ne. LINEAR .or. read_all_on_init) then
clim_type%itaum=taum
clim_type%itaup=taup
endif
! if(clim_type%TIME_FLAG .eq. BILINEAR ) then
! ! Check if delta-time is greater than delta of first two climatology time-slices.
! if ( (Time - clim_type%time_slice(taum) ) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) .or. &
! (clim_type%time_slice(taup) - Time) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) ) then
! ! The difference between the model time and the last climatology time-slice previous to the model time.
! ! We need 2 time levels. Check we have the correct data.
! itaum=0
! itaup=0
! ! Assume this is monthly data. So we need to get the data applicable to the model date but substitute
! ! the climatology year into the appropriate place.
!
! call get_date(Time, modyear, modmonth, modday, modhour, modminute, modsecond)
! call get_date(clim_type%time_slice(taum), climyear, climmonth, climday, climhour, climminute, climsecond)
! clim_datem = set_date(climyear, modmonth, modday, modhour, modminute, modsecond)
! call time_interp(clim_datem, clim_type%time_slice, tweight1, taum1, taup1 )
!
!
! call get_date(clim_type%time_slice(taup), climyear, climmonth, climday, climhour, climminute, climsecond)
! clim_datep = set_date(climyear, modmonth, modday, modhour, modminute, modsecond)
!
!
! endif
!
! endif
if(clim_type%TIME_FLAG .eq. BILINEAR ) then
! Check if delta-time is greater than delta of first two climatology time-slices.
if ( (Time - clim_type%time_slice(taum) ) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) .or. &
(clim_type%time_slice(taup) - Time) > ( clim_type%time_slice(2)- clim_type%time_slice(1) ) ) then
! The difference between the model time and the last climatology time-slice previous to the model time.
! We need 2 time levels.
clim_type%itaum=0
clim_type%itaup=0
! Assume this is monthly data. So we need to get the data applicable to the model date but substitute
! the climatology year into the appropriate place.
! We need to get the previous months data for the climatology year before
! and after the model year.
call get_date(Time, modyear, modmonth, modday, modhour, modminute, modsecond)
call get_date(clim_type%time_slice(taum), climyear, climmonth, climday, climhour, climminute, climsecond)
climatology = 1
do m = 1, size(clim_type%clim_times(:,:),2)
!Assume here that a climatology is for 1 year and consists of 12 months starting in January.
call get_date(clim_type%clim_times(1,m), year1, month1, day, hour, minute, second)
if (year1 == climyear) climatology = m
enddo
do m = 1,12
!Find which month we are trying to look at and set clim_date[mp] to the dates spanning that.
call get_date(clim_type%clim_times(m,climatology), year1, month1, day, hour, minute, second)
if ( month1 == modmonth ) then
!RSHBUGFX if ( modday <= day ) then
if ( modday < day ) then
indexm = m-1 ; indexp = m
else
indexm = m ; indexp = m+1
endif
endif
enddo
if ( indexm == 0 ) then
indexm = 12
yearm = modyear - 1
else
yearm = modyear
endif
call get_date(clim_type%time_slice(indexm+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(1) = set_date(yearm, indexm, climday, climhour, climminute, climsecond)
if ( indexp == 13 ) then
indexp = 1
yearp = modyear + 1
else
yearp = modyear
endif
call get_date(clim_type%time_slice(indexp+(climatology-1)*12), &
climyear, climmonth, climday, climhour, climminute, climsecond)
month(2) = set_date(yearp, indexp, climday, climhour, climminute, climsecond)
call time_interp(Time, month, clim_type%tweight3, taum, taup, err_msg=err_msg ) ! tweight3 is the time weight between the months.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight3 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_2D 3: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexm+(climatology-1)*12)
month(2) = clim_type%time_slice(indexm+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_prev = set_date(yearm, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_prev, month, clim_type%tweight1, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight1 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_2D 4: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
month(1) = clim_type%time_slice(indexp+(climatology-1)*12)
month(2) = clim_type%time_slice(indexp+climatology*12)
call get_date(month(1), climyear, climmonth, climday, climhour, climminute, climsecond)
t_next = set_date(yearp, climmonth, climday, climhour, climminute, climsecond)
call time_interp(t_next, month, clim_type%tweight2, taum, taup, err_msg=err_msg ) !tweight1 is the time weight between the climatology years.
if ( .not. retain_cm3_bug ) then
if (taum==2 .and. taup==2) clim_type%tweight2 = 1. ! protect against post-perth time_interp behavior
end if
if(trim(err_msg) /= '') then
call mpp_error(FATAL,'interpolator_2D 5: '//trim(err_msg)//' file='//trim(clim_type%file_name), FATAL)
endif
if (indexm == clim_type%indexm(i) .and. &
indexp == clim_type%indexp(i) .and. &
climatology == clim_type%climatology(i)) then
else
clim_type%indexm(i) = indexm
clim_type%indexp(i) = indexp
clim_type%climatology(i) = climatology
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_pyear(:,:,:,i), &
clim_type%indexm(i)+(clim_type%climatology(i)-1)*12,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_pyear(:,:,:,i), &
clim_type%indexp(i)+(clim_type%climatology(i)-1)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%pmon_nyear(:,:,:,i), &
clim_type%indexm(i)+clim_type%climatology(i)*12,i,Time)
call read_data(clim_type,clim_type%field_type(i), &
clim_type%nmon_nyear(:,:,:,i), &
clim_type%indexp(i)+clim_type%climatology(i)*12,i,Time)
endif
else ! We are within a climatology data set
if (taum /= clim_type%time_init(i,1) .or. &
taup /= clim_type%time_init(i,2) ) then
call read_data(clim_type,clim_type%field_type(i), clim_type%pmon_pyear(:,:,:,i), taum,i,Time)
! Read the data for the next month in the previous climatology.
call read_data(clim_type,clim_type%field_type(i), clim_type%nmon_pyear(:,:,:,i), taup,i,Time)
!RSHbug clim_type%pmon_nyear = 0.0
!RSHbug clim_type%nmon_nyear = 0.0
! clim_type%pmon_nyear(:,:,:,i) = 0.0
! clim_type%nmon_nyear(:,:,:,i) = 0.0
! set to zero so when next return to bilinear section will be sure to
! have proper data (relevant when running fixed_year case for more than
! one year in a single job)
clim_type%indexm(i) = 0
clim_type%indexp(i) = 0
clim_type%climatology(i) = 0
clim_type%time_init(i,1) = taum
clim_type%time_init(i,2) = taup
endif
! clim_type%tweight3 = 0.0 ! This makes [pn]mon_nyear irrelevant. Set them to 0 to test.
clim_type%tweight1 = 0.0 ; clim_type%tweight2 = 0.0
clim_type%tweight3 = clim_type%tweight
endif
endif ! (BILINEAR)
if(clim_type%TIME_FLAG .eq. LINEAR .and. &
(.not. read_all_on_init) ) then
! We need 2 time levels. Check we have the correct data.
clim_type%itaum=0
clim_type%itaup=0
do n=1,size(clim_type%time_init,2)
if (clim_type%time_init(i,n) .eq. taum ) clim_type%itaum = n
if (clim_type%time_init(i,n) .eq. taup ) clim_type%itaup = n
enddo
if (clim_type%itaum.eq.0 .and. clim_type%itaup.eq.0) then
!Neither time is set so we need to read 2 time slices.
!Set up
! field(:,:,:,1) as the previous time slice.
! field(:,:,:,2) as the next time slice.
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,1,i), taum,i,Time)
clim_type%time_init(i,1) = taum
clim_type%itaum = 1
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,2,i), taup,i,Time)
clim_type%time_init(i,2) = taup
clim_type%itaup = 2
endif ! clim_type%itaum.eq.clim_type%itaup.eq.0
if (clim_type%itaum.eq.0 .and. clim_type%itaup.ne.0) then
! Can't think of a situation where we would have the next time level but not the previous.
call mpp_error(FATAL,'interpolator_2D : No data from the previous climatology time but we have&
& the next time. How did this happen?')
endif
if (clim_type%itaum.ne.0 .and. clim_type%itaup.eq.0) then
!We have the previous time step but not the next time step data
clim_type%itaup = 1
if (clim_type%itaum .eq. 1 ) clim_type%itaup = 2
call read_data(clim_type,clim_type%field_type(i), clim_type%data(:,:,:,clim_type%itaup,i), taup,i, Time)
clim_type%time_init(i,clim_type%itaup)=taup
endif
endif! TIME_FLAG .eq. LINEAR .and. (.not. read_all_on_init)
endif ! (.not. separate_time_vary_calc)
select case(clim_type%TIME_FLAG)
case (LINEAR)
hinterp_data = (1.-clim_type%tweight)*clim_type%data(istart:iend,jstart:jend,:,clim_type%itaum,i) &
+ clim_type%tweight*clim_type%data(istart:iend,jstart:jend,:,clim_type%itaup,i)
! case (SEASONAL)
! Do sine fit to data at this point
case (BILINEAR)
hinterp_data = &
(1.-clim_type%tweight1) * (1.-clim_type%tweight3) * clim_type%pmon_pyear(istart:iend,jstart:jend,:,i) + &
(1.-clim_type%tweight2) * clim_type%tweight3 * clim_type%nmon_pyear(istart:iend,jstart:jend,:,i) + &
clim_type%tweight1 * (1.-clim_type%tweight3) * clim_type%pmon_nyear(istart:iend,jstart:jend,:,i) + &
clim_type%tweight2 * clim_type%tweight3 * clim_type%nmon_nyear(istart:iend,jstart:jend,:,i)
end select
found = .false.
do j = 1,size(climo_diag_name(:))
if (trim(adjustl(lowercase(climo_diag_name(j)))) .eq. trim(adjustl(lowercase(clim_type%field_name(i))))) then
found = .true.
exit
endif
enddo
if (found) then
if (hinterp_id(j) > 0 ) then
result = send_data(hinterp_id(j),hinterp_data,Time,is_in=istart,js_in=jstart)
endif
endif
interp_data(:,:) = hinterp_data(:,:,1)
endif !field_name
enddo !End of i loop
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_2D
!--lwh
!
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_4D_no_time_axis receives a field name as input and
!! interpolates the field to model a 4D grid.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] The half level model pressure field
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_4D_no_time_axis : You must call
!! interpolator_init before calling interpolator"
!! \throw FATAL "interpolator_mod: cannot use 4D interface to
!! interpolator for this file"
!! \throw NOTE "Interpolator: model surface pressure is greater than
!! surface pressure of input data for "
!! \throw NOTE "Interpolator: model top pressure is less than surface
!! pressure of input data for "
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_4D_no_time_axis(clim_type, phalf, interp_data, field_name, is,js, clim_units)
! Return 4-D field interpolated to model grid
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
! INTENT IN
! field_name : The name of a field that you wish to interpolate.
! all variables within this interpolate_type variable
! will be interpolated on this call. field_name may
! be any one of the variables.
! phalf : The half level model pressure field.
! is, js : The indices of the physics window.
! INTENT OUT
! interp_data : The model fields
! clim_units : The units of field_name
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
real, dimension(:,:,:), intent(in) :: phalf
real, dimension(:,:,:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
integer :: ilon
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:)),size(clim_type%field_name(:)))
real :: p_fact(size(interp_data,1),size(interp_data,2))
real :: pclim(size(clim_type%halflevs(:)))
integer :: istart,iend,jstart,jend
logical :: result
logical :: found_field=.false.
integer :: i, j, k, n
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_4D_no_time_axis : You must call interpolator_init before calling interpolator")
do n=2,size(clim_type%field_name(:))
if (clim_type%vert_interp(n) /= clim_type%vert_interp(n-1) .or. &
clim_type%out_of_bounds(n) /= clim_type%out_of_bounds(n-1)) then
if (mpp_pe() == mpp_root_pe() ) then
print *, 'processing file ' // trim(clim_type%file_name)
endif
call mpp_error (FATAL, 'interpolator_mod: &
&cannot use 4D interface to interpolator for this file')
endif
end do
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
found_field=.true.
exit
endif
end do
i = 1
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
do n=1, size(clim_type%field_name(:))
hinterp_data(:,:,:,n) = clim_type%data(istart:iend,jstart:jend,:,1,n)
end do
select case(clim_type%level_type)
case(PRESSURE)
p_fact = 1.0
case(SIGMA)
p_fact = maxval(phalf,3)! max pressure in the column !(:,:,size(phalf,3))
end select
do i= 1, size(clim_type%field_name(:))
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(hinterp_data,3)
hinterp_data(:,:,k,i) = hinterp_data(:,:,k,i)/((clim_type%halflevs(k+1)-clim_type%halflevs(k))*p_fact)
enddo
end select
enddo
i = 1
do j = 1, size(phalf,2)
do ilon=1,size(phalf,1)
pclim = p_fact(ilon,j)*clim_type%halflevs
if ( maxval(phalf(ilon,j,:)) > maxval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model surface pressure&
& is greater than surface pressure of input data for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( maxloc(pclim) ) = maxval( phalf(ilon,j,:) )
end select
endif
if ( minval(phalf(ilon,j,:)) < minval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model top pressure&
& is less than top pressure of input data for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( minloc(pclim) ) = minval( phalf(ilon,j,:) )
end select
endif
select case(clim_type%vert_interp(i))
case(INTERP_WEIGHTED_P)
call interp_weighted_scalar(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:,:),interp_data(ilon,j,:,:))
case(INTERP_LINEAR_P)
do n=1, size(clim_type%field_name(:))
call interp_linear(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:,n),interp_data(ilon,j,:,n))
end do
end select
enddo
enddo
do i= 1, size(clim_type%field_name(:))
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(interp_data,3)
interp_data(:,:,k,i) = interp_data(:,:,k,i)*(phalf(:,:,k+1)-phalf(:,:,k))
enddo
end select
end do
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_4D_no_time_axis
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_3D_no_time_axis receives a field name as input and
!! interpolates the field to model a 3D grid.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] The half level model pressure field
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_3D_no_time_axis : You must call
!! interpolator_init before calling interpolator"
!! \throw FATAL "interpolator_mod: cannot use 4D interface to
!! interpolator for this file"
!! \throw NOTE "Interpolator: model surface pressure is greater than
!! climatology surface pressure for "
!! \throw NOTE "Interpolator: model top pressure is less than
!! climatology top pressure for "
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_3D_no_time_axis(clim_type, phalf, interp_data, field_name, is,js, clim_units)
! Return 3-D field interpolated to model grid
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
! INTENT IN
! field_name : The name of the field that you wish to interpolate.
! phalf : The half level model pressure field.
! is, js : The indices of the physics window.
! INTENT OUT
! interp_data : The model field with the interpolated climatology data.
! clim_units : The units of field_name
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
real, dimension(:,:,:), intent(in) :: phalf
real, dimension(:,:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
!real :: tweight, tweight1, tweight2, tweight3
real :: tweight !< No description
real :: tweight1 !< The time weight between the climatology years
real :: tweight2 !< No description
real :: tweight3 !< The time weight between the months
integer :: taum, taup, ilon !< No description
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:))) !< No description
real :: p_fact(size(interp_data,1),size(interp_data,2)) !< No description
real :: pclim(size(clim_type%halflevs(:))) !< No description
integer :: istart,iend,jstart,jend !< No description
logical :: result !< No description
logical :: found_field=.false. !< No description
integer :: i, j, k, n !< No description
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_3D_no_time_axis : You must call interpolator_init before calling interpolator")
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
found_field=.true.
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
hinterp_data = clim_type%data(istart:iend,jstart:jend,:,1,i)
select case(clim_type%level_type)
case(PRESSURE)
p_fact = 1.0
case(SIGMA)
p_fact = maxval(phalf,3)! max pressure in the column !(:,:,size(phalf,3))
end select
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(hinterp_data,3)
hinterp_data(:,:,k) = hinterp_data(:,:,k)/((clim_type%halflevs(k+1)-clim_type%halflevs(k))*p_fact)
enddo
end select
do j = 1, size(phalf,2)
do ilon=1,size(phalf,1)
pclim = p_fact(ilon,j)*clim_type%halflevs
if ( maxval(phalf(ilon,j,:)) > maxval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model surface pressure&
& is greater than climatology surface pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( maxloc(pclim) ) = maxval( phalf(ilon,j,:) )
end select
endif
if ( minval(phalf(ilon,j,:)) < minval(pclim) ) then
if (verbose > 3) then
call mpp_error(NOTE,"Interpolator: model top pressure&
& is less than climatology top pressure for "&
// trim(clim_type%file_name))
endif
select case(clim_type%out_of_bounds(i))
case(CONSTANT)
pclim( minloc(pclim) ) = minval( phalf(ilon,j,:) )
end select
endif
select case(clim_type%vert_interp(i))
case(INTERP_WEIGHTED_P)
call interp_weighted_scalar(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:),interp_data(ilon,j,:))
case(INTERP_LINEAR_P)
call interp_linear(pclim, phalf(ilon,j,:),hinterp_data(ilon,j,:),interp_data(ilon,j,:))
end select
enddo
enddo
select case(clim_type%mr(i))
case(KG_M2)
do k = 1,size(interp_data,3)
interp_data(:,:,k) = interp_data(:,:,k)*(phalf(:,:,k+1)-phalf(:,:,k))
enddo
end select
endif !field_name
enddo !End of i loop
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_3D_no_time_axis
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_2D_no_time_axis receives a field name as input and
!! interpolates the field to model a 2D grid.
!!
!! \param [inout] The interpolate type previously defined by a call to interpolator_init
!! \param [in] The name of a field that you wish to interpolate
!! \param [in] OPTIONAL: Index for the physics window
!! \param [in] OPTIONAL: Index for the physics window
!! \param [out] The model fields with the interpolated climatology data
!! \param [out] OPTIONAL: The units of field_name
!!
!! \throw FATAL "interpolator_2D_no_time_axis : You must call
!! interpolator_init before calling interpolator"
!! \throw FATAL "Interpolator: the field name is not contained in this
!! intepolate_type: "
subroutine interpolator_2D_no_time_axis(clim_type, interp_data, field_name, is, js, clim_units)
! Return 2-D field interpolated to model grid
! INTENT INOUT
! clim_type : The interpolate type previously defined by a call to interpolator_init
! INTENT IN
! field_name : The name of the field that you wish to interpolate.
! is, js : The indices of the physics window.
! INTENT OUT
! interp_data : The model field with the interpolated climatology data.
! clim_units : The units of field_name
type(interpolate_type), intent(inout) :: clim_type
character(len=*) , intent(in) :: field_name
real, dimension(:,:), intent(out) :: interp_data
integer , intent(in) , optional :: is,js
character(len=*) , intent(out), optional :: clim_units
real :: tweight, tweight1, tweight2, tweight3
integer :: taum, taup, ilon
real :: hinterp_data(size(interp_data,1),size(interp_data,2),size(clim_type%levs(:)))
real :: p_fact(size(interp_data,1),size(interp_data,2))
integer :: istart,iend,jstart,jend
logical :: result
logical :: found_field=.false.
integer :: j, k, i, n
if (.not. module_is_initialized .or. .not. associated(clim_type%lon)) &
call mpp_error(FATAL, "interpolator_2D_no_time_axis : You must call interpolator_init before calling interpolator")
istart = 1
if (present(is)) istart = is
iend = istart - 1 + size(interp_data,1)
jstart = 1
if (present(js)) jstart = js
jend = jstart - 1 + size(interp_data,2)
do i= 1,size(clim_type%field_name(:))
if ( trim(adjustl(lowercase(field_name))) == trim(adjustl(lowercase(clim_type%field_name(i)))) ) then
found_field=.true.
if(present(clim_units)) then
call mpp_get_atts(clim_type%field_type(i),units=clim_units)
clim_units = chomp(clim_units)
endif
hinterp_data = clim_type%data(istart:iend,jstart:jend,:,1,i)
interp_data(:,:) = hinterp_data(:,:,1)
endif !field_name
enddo !End of i loop
if( .not. found_field) then !field name is not in interpolator file.ERROR.
call mpp_error(FATAL,"Interpolator: the field name is not contained in this &
&intepolate_type: "//trim(field_name))
endif
end subroutine interpolator_2D_no_time_axis
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief interpolator_end receives interpolate data as input
!! and deallocates its memory.
!!
!! \param [inout] The interpolate type whose components will be deallocated
subroutine interpolator_end(clim_type)
! Subroutine to deallocate the interpolate type clim_type.
!
! INTENT INOUT
! clim_type : allocate type whose components will be deallocated.
!
type(interpolate_type), intent(inout) :: clim_type
integer :: logunit
logunit=stdlog()
if ( mpp_pe() == mpp_root_pe() ) then
write (logunit,'(/,(a))') 'Exiting interpolator, have a nice day ...'
end if
if (associated (clim_type%lat )) deallocate(clim_type%lat)
if (associated (clim_type%lon )) deallocate(clim_type%lon)
if (associated (clim_type%latb )) deallocate(clim_type%latb)
if (associated (clim_type%lonb )) deallocate(clim_type%lonb)
if (associated (clim_type%levs )) deallocate(clim_type%levs)
if (associated (clim_type%halflevs)) deallocate(clim_type%halflevs)
call horiz_interp_del(clim_type%interph)
if (associated (clim_type%time_slice)) deallocate(clim_type%time_slice)
if (associated (clim_type%field_type)) deallocate(clim_type%field_type)
if (associated (clim_type%field_name)) deallocate(clim_type%field_name)
if (associated (clim_type%time_init )) deallocate(clim_type%time_init)
if (associated (clim_type%mr )) deallocate(clim_type%mr)
if (associated (clim_type%data)) then
deallocate(clim_type%data)
endif
if (associated (clim_type%pmon_pyear)) then
deallocate(clim_type%pmon_pyear)
deallocate(clim_type%pmon_nyear)
deallocate(clim_type%nmon_nyear)
deallocate(clim_type%nmon_pyear)
endif
!! RSH mod
if( .not. (clim_type%TIME_FLAG .eq. LINEAR .and. &
! read_all_on_init)) .or. clim_type%TIME_FLAG .eq. BILINEAR ) then
read_all_on_init) ) then
call mpp_close(clim_type%unit)
endif
module_is_initialized = .false.
end subroutine interpolator_end
!
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief read_data receives various climate data as inputs and
!! returns a horizontally interpolated climatology field.
!!
!! \param [in] The interpolate type which contains the data
!! \param [in] The field type
!! \param [in] The index of the time slice of the climatology that you wish to read
!! \param [in] OPTIONAL: The index of the field name that you are trying to read
!! \param [in] OPTIONAL: The model time. Used for diagnostic purposes only
!! \param [out] The horizontally interpolated climatology field. This
! field will still be on the climatology vertical grid
subroutine read_data(clim_type,src_field, hdata, nt,i, Time)
!
! INTENT IN
! clim_type : The interpolate type which contains the data
! src_field : The field type
! nt : The index of the time slice of the climatology that you wish to read.
! i : The index of the field name that you are trying to read. (optional)
! Time : The model time. Used for diagnostic purposes only. (optional)
!
! INTENT OUT
!
! hdata : The horizontally interpolated climatology field. This
! field will still be on the climatology vertical grid.
!
type(interpolate_type) , intent(in) :: clim_type
type(fieldtype) , intent(in) :: src_field
integer , intent(in) :: nt
real , intent(out) :: hdata(:,:,:)
integer , optional, intent(in) :: i
type(time_type), optional, intent(in) :: Time
integer :: k, km
! sjs
real, allocatable :: climdata(:,:,:), climdata2(:,:,:)
allocate(climdata(size(clim_type%lon(:)),size(clim_type%lat(:)), &
size(clim_type%levs(:))))
call mpp_read(clim_type%unit,src_field, climdata,nt)
! if vertical index increases upward, flip the data so that lowest
! pressure level data is at index 1, rather than the highest pressure
! level data. the indices themselves were previously flipped.
if (clim_type%vertical_indices == INCREASING_UPWARD) then
allocate(climdata2(size(clim_type%lon(:)), &
size(clim_type%lat(:)), &
size(clim_type%levs(:))))
km = size(clim_type%levs(:))
do k=1, km
climdata2(:,:,k) = climdata(:,:,km+1-k)
end do
climdata = climdata2
deallocate (climdata2)
endif
call horiz_interp(clim_type%interph, climdata, hdata)
if (clim_diag_initialized) &
call diag_read_data(clim_type,climdata,i, Time)
deallocate(climdata)
end subroutine read_data
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief read_data_no_time_axis receives various climate data as inputs and
!! returns a horizontally interpolated climatology field without the
!! time axis.
!!
!! \param [in] The interpolate type which contains the data
!! \param [in] The field type
!! \param [in] OPTIONAL: The index of the field name that you are trying to read
!! \param [out] The horizontally interpolated climatology field. This
! field will still be on the climatology vertical grid
subroutine read_data_no_time_axis(clim_type,src_field, hdata, i)
! INTENT IN
! clim_type : The interpolate type which contains the data
! src_field : The field type
! i : The index of the field name that you are trying to read. (optional)
! INTENT OUT
! hdata : The horizontally interpolated climatology field. This
! field will still be on the climatology vertical grid.
type(interpolate_type) , intent(in) :: clim_type
type(fieldtype) , intent(in) :: src_field
real , intent(out) :: hdata(:,:,:)
integer , optional, intent(in) :: i
integer :: k, km
! sjs
real, allocatable :: climdata(:,:,:), climdata2(:,:,:)
allocate(climdata(size(clim_type%lon(:)),size(clim_type%lat(:)), size(clim_type%levs(:))))
call mpp_read(clim_type%unit,src_field, climdata)
! if vertical index increases upward, flip the data so that lowest
! pressure level data is at index 1, rather than the highest pressure
! level data. the indices themselves were previously flipped.
if (clim_type%vertical_indices == INCREASING_UPWARD) then
allocate(climdata2(size(clim_type%lon(:)), &
size(clim_type%lat(:)), &
size(clim_type%levs(:))))
km = size(clim_type%levs(:))
do k=1, km
climdata2(:,:,k) = climdata(:,:,km+1-k)
end do
climdata = climdata2
deallocate (climdata2)
endif
call horiz_interp(clim_type%interph, climdata, hdata)
deallocate(climdata)
end subroutine read_data_no_time_axis
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief diag_read_data receives the data read in by read_data as
!! inputs and runs a diagnosis.
!!
!! \param [in] The interpolate type which contains the data
!! \param [in] The data read in from file that is being diagnosed
!! \param [in] The index of the field name that you are diagnosing
!! \param [in] The model time.
subroutine diag_read_data(clim_type,model_data, i, Time)
!
! A routine to diagnose the data read in by read_data
!
! INTENT IN
! clim_type : The interpolate type.
! model_data : The data read in from file that is being diagnosed.
! i : The index of the field name that you are diagnosing.
! Time : The model time
!
type(interpolate_type), intent(in) :: clim_type
real , intent(in) :: model_data(:,:,:)
integer , intent(in) :: i
type(time_type) , intent(in) :: Time
integer :: j,k
real :: col_data(size(model_data,1),size(model_data,2))
logical :: result, found
found = .false.
do j = 1,size(climo_diag_name(:))
if (trim(adjustl(lowercase(climo_diag_name(j)))) .eq. trim(adjustl(lowercase(clim_type%field_name(i))))) then
found = .true.
exit
endif
enddo
if(found) then
if(climo_diag_id(j)>0) then
col_data(:,:)=0.0
do k=1,size(model_data,3)
col_data(:,:) = col_data(:,:) + &
model_data(:,:,k)* &
(clim_type%halflevs(k+1)-clim_type%halflevs(k))/grav
enddo
result = send_data(climo_diag_id(j),col_data(clim_type%is:clim_type%ie,clim_type%js:clim_type%je),Time)
endif
endif
end subroutine diag_read_data
!
!#######################################################################
!
!++lwh
!
!---------------------------------------------------------------------
!> \brief query_interpolator receives an interpolate type as input
!! and returns the number of fields and field names.
!!
!! \param [in] The interpolate type which contains the data
!! \param [out] OPTIONAL: No description
!! \param [out] OPTIONAL: No description
subroutine query_interpolator( clim_type, nfields, field_names )
!
! Query an interpolate_type variable to find the number of fields and field names.
!
type(interpolate_type), intent(in) :: clim_type
integer, intent(out), optional :: nfields
character(len=*), dimension(:), intent(out), optional :: field_names
if( present( nfields ) ) nfields = SIZE( clim_type%field_name(:) )
if( present( field_names ) ) field_names = clim_type%field_name
end subroutine query_interpolator
!--lwh
!
!#######################################################################
!
!---------------------------------------------------------------------
!> \brief chomp receives a string from NetCDF files and removes
!! CHAR(0) from the end of this string.
!!
!! \param [in] The string from the NetCDF file
function chomp(string)
!
! A function to remove CHAR(0) from the end of strings read from NetCDF files.
!
character(len=*), intent(in) :: string
character(len=64) :: chomp
integer :: len
len = len_trim(string)
if (string(len:len) == CHAR(0)) len = len -1
chomp = string(:len)
end function chomp
!
!#################################################################
!
!
!---------------------------------------------------------------------
!> \brief interp_weighted_scalar_2D receives the variables grdin,
!! grdout, and datin as inputs and returns datout.
!!
!! \param [in] No description
!! \param [in] No description
!! \param [in] No description
!! \param [out] No description
subroutine interp_weighted_scalar_2D (grdin, grdout, datin, datout )
real, intent(in), dimension(:) :: grdin, grdout
real, intent(in), dimension(:,:) :: datin
real, intent(out), dimension(:,:) :: datout
integer :: j, k, n
if (size(grdin(:)).ne. (size(datin,1)+1)) &
call mpp_error(FATAL,'interp_weighted_scalar : input data and pressure do not have the same number of levels')
if (size(grdout(:)).ne. (size(datout,1 )+1)) &
call mpp_error(FATAL,'interp_weighted_scalar : output data and pressure do not have the same number of levels')
do k = 1, size(datout,1 )
datout(k,:) = 0.0
do j = 1, size(datin,1 )
if ( grdin(j) <= grdout(k) .and. &
grdin(j+1) >= grdout(k) .and. &
grdin(j+1) <= grdout(k+1) ) then
do n= 1, size(datin,2)
datout(k,n) = datout(k,n) + datin(j,n)*(grdin(j+1)-grdout(k))
end do
else if ( grdin(j) >= grdout(k) .and. &
grdin(j) <= grdout(k+1) .and. &
grdin(j+1) >= grdout(k+1) ) then
do n= 1, size(datin,2)
datout(k,n) = datout(k,n) + datin(j,n)*(grdout(k+1)-grdin(j))
end do
else if ( grdin(j) >= grdout(k) .and. &
grdin(j+1) <= grdout(k+1) ) then
do n= 1, size(datin,2)
datout(k,n) = datout(k,n) + datin(j,n)*(grdin(j+1)-grdin(j))
end do
else if ( grdin(j) <= grdout(k) .and. &
grdin(j+1) >= grdout(k+1) ) then
do n= 1, size(datin,2)
datout(k,n) = datout(k,n) + datin(j,n)*(grdout(k+1)-grdout(k))
end do
endif
enddo
do n= 1, size(datin,2)
datout(k,n) = datout(k,n)/(grdout(k+1)-grdout(k))
end do
enddo
end subroutine interp_weighted_scalar_2D
!
!---------------------------------------------------------------------
!> \brief interp_weighted_scalar_1D receives the variables grdin,
!! grdout, and datin as inputs and returns datout.
!!
!! \param [in] No description
!! \param [in] No description
!! \param [in] No description
!! \param [out] No description
subroutine interp_weighted_scalar_1D (grdin, grdout, datin, datout )
real, intent(in), dimension(:) :: grdin, grdout, datin
real, intent(out), dimension(:) :: datout
integer :: j, k
if (size(grdin(:)).ne. (size(datin(:))+1)) &
call mpp_error(FATAL,'interp_weighted_scalar : input data and pressure do not have the same number of levels')
if (size(grdout(:)).ne. (size(datout(:))+1)) &
call mpp_error(FATAL,'interp_weighted_scalar : output data and pressure do not have the same number of levels')
do k = 1, size(datout(:))
datout(k) = 0.0
do j = 1, size(datin(:))
if ( grdin(j) <= grdout(k) .and. &
grdin(j+1) >= grdout(k) .and. &
grdin(j+1) <= grdout(k+1) ) then
datout(k) = datout(k) + datin(j)*(grdin(j+1)-grdout(k))
else if ( grdin(j) >= grdout(k) .and. &
grdin(j) <= grdout(k+1) .and. &
grdin(j+1) >= grdout(k+1) ) then
datout(k) = datout(k) + datin(j)*(grdout(k+1)-grdin(j))
else if ( grdin(j) >= grdout(k) .and. &
grdin(j+1) <= grdout(k+1) ) then
datout(k) = datout(k) + datin(j)*(grdin(j+1)-grdin(j))
else if ( grdin(j) <= grdout(k) .and. &
grdin(j+1) >= grdout(k+1) ) then
datout(k) = datout(k) + datin(j)*(grdout(k+1)-grdout(k))
endif
enddo
datout(k) = datout(k)/(grdout(k+1)-grdout(k))
enddo
end subroutine interp_weighted_scalar_1D
!
!#################################################################
!
!---------------------------------------------------------------------
!> \brief interp_linear receives the variables grdin,
!! grdout, and datin as inputs and returns a linear
!! interpolation.
!!
!! \param [in] No description
!! \param [in] No description
!! \param [in] No description
!! \param [out] No description
subroutine interp_linear ( grdin, grdout, datin, datout )
real, intent(in), dimension(:) :: grdin, grdout, datin
real, intent(out), dimension(:) :: datout
integer :: j, k, n
real :: wt
if (size(grdin(:)).ne. (size(datin(:))+1)) &
call mpp_error(FATAL,'interp_linear : input data and pressure do not have the same number of levels')
if (size(grdout(:)).ne. (size(datout(:))+1)) &
call mpp_error(FATAL,'interp_linear : output data and pressure do not have the same number of levels')
n = size(grdin(:))
do k= 1, size(datout(:))
! ascending grid values
if (grdin(1) < grdin(n)) then
do j = 2, size(grdin(:))-1
if (grdout(k) <= grdin(j)) exit
enddo
! descending grid values
else
do j = size(grdin(:)), 3, -1
if (grdout(k) <= grdin(j-1)) exit
enddo
endif
! linear interpolation
wt = (grdout(k)-grdin(j-1)) / (grdin(j)-grdin(j-1))
!print '(a,2i3,4f6.1)', 'k,j=',k,j,grdout(k),grdin(j-1),grdin(j),wt
! constant value extrapolation
! wt = min(max(wt,0.),1.)
datout(k) = (1.-wt)*datin(j-1) + wt*datin(j)
enddo
end subroutine interp_linear
!
!########################################################################
end module interpolator_mod
!
!#######################################################################
!