! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! + +
! + glimmer_anomcouple.f90 - part of the Glimmer-CISM ice model +
! + +
! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!
! Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
! Glimmer-CISM contributors - see AUTHORS file for list of contributors
!
! This file is part of Glimmer-CISM.
!
! Glimmer-CISM is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 2 of the License, or (at
! your option) any later version.
!
! Glimmer-CISM is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with Glimmer-CISM. If not, see .
!
! Glimmer-CISM is hosted on BerliOS.de:
! https://developer.berlios.de/projects/glimmer-cism/
!
! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#ifdef HAVE_CONFIG_H
#include "config.inc"
#endif
module glimmer_anomcouple
!*FD This module provides code to handle anomaly coupling. Although
!*FD written for use with GLINT, it has general applicability. Temperature coupling
!*FD is done linearly, precipitation proportionally.
use glimmer_global
implicit none
character(9),dimension(5),parameter :: xvars=(/ &
'longitude', &
'lon ', &
'x0 ', &
'x1 ', &
'x '/)
character(8),dimension(5),parameter :: yvars=(/ &
'latitude', &
'lat ', &
'y0 ', &
'y1 ', &
'y '/)
character(4),dimension(1),parameter :: tvars=(/ &
'time'/)
type anomaly_coupling
logical :: enabled = .false.
character(fname_length) :: fname_reference !*FD File containing reference climate
character(fname_length) :: fname_modelclim !*FD File containing mean model climate
integer :: nslices !*FD Number of time-slices in climatologies
real(rk),dimension(:,:,:),pointer :: temp_ref => null() !*FD Reference climate (temperature)
real(rk),dimension(:,:,:),pointer :: temp_mod => null() !*FD Model climate (temperature)
real(rk),dimension(:,:,:),pointer :: prcp_ref => null() !*FD Reference climate (precip)
real(rk),dimension(:,:,:),pointer :: prcp_mod => null() !*FD Model climate (precip)
real(rk),dimension(:) ,pointer :: time => null() !*FD Time axis (fraction of year)
integer :: nx,ny !*FD Grid dimensions (for convenience)
character(20) :: pvarname_ref='prcp '
character(20) :: tvarname_ref='artm '
character(20) :: pvarname_mod='prcp '
character(20) :: tvarname_mod='artm '
logical :: mult_precip = .false. !*FD set true if we're multiplying precip
end type anomaly_coupling
private
public :: anomaly_coupling, anomaly_init, anomaly_calc
contains
subroutine anomaly_init(params,config)
use glimmer_config
type(anomaly_coupling),intent(out) :: params !*FD Parameters to be initialised
type(ConfigSection),pointer :: config !*FD Configuation file
call anomaly_readconfig(params,config)
if (params%enabled) then
call anomaly_readdata(params)
call anomaly_printconfig(params)
end if
end subroutine anomaly_init
!------------------------------------------------------------------------------------------
subroutine anomaly_calc(params,time,rawtemp,rawprcp,anomtemp,anomprcp)
type(anomaly_coupling),intent(in) :: params !*FD Parameters to be initialised
real(rk) :: time
real(rk),dimension(:,:),intent(in) :: rawtemp, rawprcp
real(rk),dimension(:,:),intent(out) :: anomtemp,anomprcp
real(rk),dimension(size(rawtemp,1),size(rawtemp,2)) :: tempm,prcpm,tempr,prcpr
integer :: first
real(sp) :: frac
integer :: i,j
if (params%enabled) then
call anomaly_index(params%time,time,first,frac)
tempm=(1.0-frac)*params%temp_mod(:,:,first)+frac*params%temp_mod(:,:,first+1)
prcpm=(1.0-frac)*params%prcp_mod(:,:,first)+frac*params%prcp_mod(:,:,first+1)
tempr=(1.0-frac)*params%temp_ref(:,:,first)+frac*params%temp_ref(:,:,first+1)
prcpr=(1.0-frac)*params%prcp_ref(:,:,first)+frac*params%prcp_ref(:,:,first+1)
anomtemp=rawtemp-tempm+tempr
if (params%mult_precip) then
do i=1,size(anomprcp,1)
do j=1,size(anomprcp,2)
if (prcpm(i,j)/=0.0_rk) then
anomprcp(i,j)=rawprcp(i,j)*prcpr(i,j)/prcpm(i,j)
else if (rawprcp(i,j)==0.0_rk) then
anomprcp(i,j)=prcpr(i,j)
else if (prcpr(i,j)==0.0_rk) then
anomprcp(i,j)=rawprcp(i,j)
else
anomprcp(i,j)=0.0_rk
end if
end do
end do
else
anomprcp=max(rawprcp-prcpm+prcpr,0.0_rk)
end if
else
anomprcp=rawprcp
anomtemp=rawtemp
end if
end subroutine anomaly_calc
!------------------------------------------------------------------------------------------
! PRIVATE subroutines
!------------------------------------------------------------------------------------------
subroutine anomaly_readconfig(params,config)
use glimmer_config
type(anomaly_coupling),intent(out) :: params !*FD Parameters to be initialised
type(ConfigSection),pointer :: config !*FD Configuation file
! local variables
type(ConfigSection), pointer :: section
integer :: mprcp
call GetSection(config,section,'anomaly coupling')
if (associated(section)) then
mprcp = 0
call GetValue(section,'reference',params%fname_reference)
call GetValue(section,'model', params%fname_modelclim)
call GetValue(section,'precipvar_ref', params%pvarname_ref)
call GetValue(section,'precipvar_model',params%pvarname_mod)
call GetValue(section,'tempvar_ref', params%tvarname_ref)
call GetValue(section,'tempvar_model', params%tvarname_mod)
call GetValue(section,'multiply_precip',mprcp)
if (mprcp==1) params%mult_precip=.true.
params%enabled = .true.
else
params%enabled = .false.
end if
end subroutine anomaly_readconfig
!------------------------------------------------------------------------------------------
subroutine anomaly_printconfig(params)
use glimmer_log
type(anomaly_coupling),intent(inout) :: params !*FD Parameters to be initialised
character(len=msg_length) :: message
call write_log_div
call write_log('Anomaly coupling')
call write_log("----------------")
write(message,*)" Reference climate:",trim(params%fname_reference)
call write_log(message)
write(message,*)" Variables: ",trim(params%tvarname_ref),', ',trim(params%pvarname_ref)
call write_log(message)
write(message,*)" Model climate: ",trim(params%fname_modelclim)
call write_log(message)
write(message,*)" Variables: ",trim(params%tvarname_mod),', ',trim(params%pvarname_mod)
call write_log(message)
write(message,*)" Number of slices: ",params%nslices
call write_log(message)
call write_log("")
end subroutine anomaly_printconfig
!------------------------------------------------------------------------------------------
subroutine anomaly_readdata(params)
use glimmer_log
type(anomaly_coupling),intent(inout) :: params !*FD Parameters to be initialised
integer,dimension(4) :: nx,ny,nt
real(rk),dimension(:),pointer :: timemod => null()
real(rk),dimension(:),pointer :: timeref => null()
call anomaly_readnc(params%fname_reference,params%pvarname_ref,params%prcp_ref,timeref,nx(1),ny(1),nt(1))
call anomaly_readnc(params%fname_reference,params%tvarname_ref,params%temp_ref,timeref,nx(2),ny(2),nt(2))
call anomaly_readnc(params%fname_modelclim,params%pvarname_mod,params%prcp_mod,timemod,nx(3),ny(3),nt(3))
call anomaly_readnc(params%fname_modelclim,params%tvarname_mod,params%temp_mod,timemod,nx(4),ny(4),nt(4))
if (any(nx(1)/=nx(2:4)).or.any(ny(1)/=ny(2:4)).or.any(nt(1)/=nt(2:4))) &
call write_log("Anomaly coupling: sizes of arrays in climate files do not agree", &
GM_FATAL,__FILE__,__LINE__)
params%nx=nx(1)
params%ny=ny(1)
params%nslices=nt(1)
if (.not.all(abs(timemod-timeref)<1e-8)) &
call write_log("Anomaly coupling: time axes in climate files do not agree",GM_FATAL,__FILE__,__LINE__)
if (associated(params%time)) then
deallocate(params%time)
params%time => null()
end if
allocate(params%time(params%nslices+2))
params%time=timemod
end subroutine anomaly_readdata
!------------------------------------------------------------------------------------------
subroutine anomaly_readnc(fname,varname,data,timeaxis,nx,ny,nt)
use netcdf
use glimmer_log
use glimmer_filenames
character(*), intent(in) :: fname
character(*), intent(in) :: varname
real(rk),dimension(:,:,:),pointer :: data
real(rk),dimension(:), pointer :: timeaxis
integer, intent(out) :: nx,ny,nt
! Local variables
integer :: status, ncid, varid, tvarid, ndims, i
integer,dimension(3) :: dimids
integer,dimension(3) :: dimnames
character(30) :: dntemp,timevar
real(sp) :: interval
! Open file
status=nf90_open(filenames_inputname(process_path(fname)),NF90_NOWRITE,ncid)
call nc_errorhandle(__FILE__,__LINE__,status)
! Look for required variable
status=nf90_inq_varid(ncid,varname,varid)
call nc_errorhandle(__FILE__,__LINE__,status)
! Check we have three dimensions
status=nf90_inquire_variable(ncid,varid,ndims=ndims)
call nc_errorhandle(__FILE__,__LINE__,status)
if (ndims/=3) call write_log("Anomaly coupling: file "//trim(process_path(fname))//", variable "// &
trim(varname)//" should have three dimensions",GM_FATAL,__FILE__,__LINE__)
status=nf90_inquire_variable(ncid,varid,dimids=dimids)
call nc_errorhandle(__FILE__,__LINE__,status)
! Check we have some sensible dimension names in the right order:
! must be x,y,t (this is t,y,x in netcdf-speak...)
status=nf90_inquire_dimension(ncid,dimids(1),dntemp,nx)
call nc_errorhandle(__FILE__,__LINE__,status)
if (.not.any(dntemp==xvars)) &
call write_log("Anomaly coupling: first dimension in climate file "//trim(process_path(fname))// &
" is not x or longitude",GM_FATAL,__FILE__,__LINE__)
status=nf90_inquire_dimension(ncid,dimids(2),dntemp,ny)
call nc_errorhandle(__FILE__,__LINE__,status)
if (.not.any(dntemp==yvars)) &
call write_log("Anomaly coupling: second dimension in climate file "//trim(process_path(fname))// &
" is not y or latitude",GM_FATAL,__FILE__,__LINE__)
status=nf90_inquire_dimension(ncid,dimids(3),dntemp,nt)
call nc_errorhandle(__FILE__,__LINE__,status)
if (.not.any(dntemp==tvars)) &
call write_log("Anomaly coupling: third dimension in climate file "//trim(process_path(fname))// &
" is not time",GM_FATAL,__FILE__,__LINE__)
timevar=dntemp
! If we've got this far, we can retrieve the data itself
if (associated(data)) then
deallocate(data)
data => null()
end if
allocate(data(nx,ny,nt+2))
status=nf90_get_var(ncid,varid,data(:,:,2:nt+1))
call nc_errorhandle(__FILE__,__LINE__,status)
data(:,:,1) =data(:,:,nt+1)
data(:,:,nt+2)=data(:,:,2)
! Now we try and get the time data
if (associated(timeaxis)) then
deallocate(timeaxis)
timeaxis => null()
end if
allocate(timeaxis(nt+2))
status=nf90_inq_varid(ncid,timevar,tvarid)
select case (status)
case(NF90_NOERR)
status=nf90_get_var(ncid,tvarid,timeaxis(2:nt+1))
call nc_errorhandle(__FILE__,__LINE__,status)
case(NF90_ENOTVAR)
! Time variable not found - construct our own
interval=1.0/real(nt)
do i=1,nt
timeaxis(i+1)=(i-1)*interval+interval/2.0
end do
call write_log('Anomaly coupling: Created time-axis')
case default
! Some other error - bail out
call nc_errorhandle(__FILE__,__LINE__,status)
end select
! Fix up time boundaries
timeaxis(1) =-1.0+timeaxis(nt+1)
timeaxis(nt+2)=1.0+timeaxis(2)
! Close the file
status=nf90_close(ncid)
call nc_errorhandle(__FILE__,__LINE__,status)
end subroutine anomaly_readnc
subroutine anomaly_index(timeaxis,time,first,frac)
use glimmer_log
real(rk),dimension(:),intent(in) :: timeaxis
real(rk), intent(in) :: time
integer, intent(out) :: first
real(sp), intent(out) :: frac
first=1
do
if (time>=timeaxis(first).and.time