! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! + + ! + glimmer_ts.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 !> handling time series !! !! \author Magnus Hagdorn !! \date 2006 !! !! this module provides support for reading in tabulated ASCII data such as !! time series. The data can then be accessed through functions which !! interpolated the data. module glimmer_ts !> time series derived type type glimmer_tseries integer :: numt=0 !< number of times in time series integer :: numv=1 !< number of values per time integer :: current=1 !< current position in ts real, dimension(:), pointer :: times=>NULL() !< array holding times real, dimension(:,:), pointer :: values=>NULL()!< array holding values end type glimmer_tseries interface glimmer_ts_step module procedure glimmer_ts_step_array, glimmer_ts_step_scalar end interface interface glimmer_ts_linear module procedure glimmer_ts_linear_array,glimmer_ts_linear_scalar end interface private :: get_i contains !> read tabulated ASCII file subroutine glimmer_read_ts(ts,fname,numv) use glimmer_log use glimmer_global, only : msg_length implicit none type(glimmer_tseries) :: ts !< time series data character(len=*), intent(in) :: fname !< read from this file integer, intent(in),optional :: numv !< number of values per time ! local variables real :: d1,d2,fact=1. integer i,j,ios character(len=msg_length) :: message if (present(numv)) then ts%numv = numv else ts%numv = 1 end if open(99,file=trim(fname),status='old',iostat=ios) if (ios.ne.0) then call write_log('Error opening file: '//trim(fname),type=GM_FATAL) end if ! find number of times and checking if ts is strictly monotonic ios=0 d1 = 1 do d2 = d1 read(99,*,iostat=ios) d1 d1 = fact*d1 if (ios.ne.0) then exit end if ts%numt = ts%numt + 1 if (ts%numt.eq.1) then cycle else if (ts%numt.eq.2) then if (d1.gt.d2) then fact = 1. else if (d1.lt.d2) then fact = -1. d1 = -d1 else write(message,*) 'Error, time series in file: '//trim(fname)//' is not monotonic line: ',ts%numt call write_log(message,type=GM_FATAL) end if else if (d1.le.d2) then write(message,*) 'Error, time series in file: '//trim(fname)//' is not monotonic line: ',ts%numt call write_log(message,type=GM_FATAL) end if end if end do rewind(99) allocate(ts%times(ts%numt)) allocate(ts%values(ts%numv,ts%numt)) ! read data do i=1,ts%numt read(99,*) ts%times(i),(ts%values(j,i),j=1,ts%numv) end do close(99) end subroutine glimmer_read_ts !> interpolate time series by stepping subroutine glimmer_ts_step_array(ts,time,value) use glimmer_log implicit none type(glimmer_tseries) :: ts !< time series data real, intent(in) :: time !< time value to get real, dimension(:) :: value !< interpolated value integer i if (size(value).ne.ts%numv) then call write_log('Error, wrong number of values',GM_FATAL,__FILE__,__LINE__) end if i = get_i(ts,time) if (i.eq.-1) then i = 1 else if (i.eq.ts%numt+1) then i = ts%numt end if value = ts%values(:,i) end subroutine glimmer_ts_step_array !> interpolate time series by stepping subroutine glimmer_ts_step_scalar(ts,time,value) use glimmer_log implicit none type(glimmer_tseries) :: ts !< time series data real, intent(in) :: time !< time value to get real :: value !< interpolated value integer i i = get_i(ts,time) if (i.eq.-1) then i = 1 else if (i.eq.ts%numt+1) then i = ts%numt end if value = ts%values(1,i) end subroutine glimmer_ts_step_scalar !> linear interpolate time series subroutine glimmer_ts_linear_array(ts,time,value) use glimmer_log implicit none type(glimmer_tseries) :: ts !< time series data real, intent(in) :: time !< time value to get real, dimension(:) :: value !< interpolated value integer i real,dimension(size(value)) :: slope if (size(value).ne.ts%numv) then call write_log('Error, wrong number of values',GM_FATAL,__FILE__,__LINE__) end if i = get_i(ts,time) if (i.eq.-1) then value(:) = ts%values(:,1) else if (i.eq.ts%numt+1) then value(:) = ts%values(:,ts%numt) else slope(:) = (ts%values(:,i+1)-ts%values(:,i))/(ts%times(i+1)-ts%times(i)) value(:) = ts%values(:,i) + slope(:)*(time-ts%times(i)) end if end subroutine glimmer_ts_linear_array !> linear interpolate time series subroutine glimmer_ts_linear_scalar(ts,time,value) use glimmer_log implicit none type(glimmer_tseries) :: ts !< time series data real, intent(in) :: time !< time value to get real :: value !< interpolated value integer i real :: slope i = get_i(ts,time) if (i.eq.-1) then value = ts%values(1,1) else if (i.eq.ts%numt+1) then value = ts%values(1,ts%numt) else slope = (ts%values(1,i+1)-ts%values(1,i))/(ts%times(i+1)-ts%times(i)) value = ts%values(1,i) + slope*(time-ts%times(i)) end if end subroutine glimmer_ts_linear_scalar !> get find the index function get_i(ts,time) implicit none type(glimmer_tseries) :: ts !< time series data real, intent(in) :: time !< time value to get integer get_i integer upper,lower ! BC if (time.le.ts%times(1)) then get_i = -1 return end if if (time.ge.ts%times(ts%numt)) then get_i = ts%numt + 1 return end if ! first try if the interpolated value is around the last value ts%current=min(ts%current,ts%numt-1) if (time.ge.ts%times(ts%current) .and. time.lt.ts%times(ts%current+1)) then get_i = ts%current return end if ! this didn't work, let's try the next interval ts%current=ts%current+1 if (time.ge.ts%times(ts%current) .and. time.lt.ts%times(ts%current+1)) then get_i = ts%current return end if ! nope, let's do a Newton search lower = 1 upper = ts%numt do ts%current = lower+int((upper-lower)/2.) if (time.ge.ts%times(ts%current) .and. time.lt.ts%times(ts%current+1)) then get_i = ts%current return end if if (time.gt.ts%times(ts%current)) then lower = ts%current else upper = ts%current end if end do end function get_i end module glimmer_ts