MONC
interpolation.F90
Go to the documentation of this file.
1 
5 
6  implicit none
7 
8 contains
9 
15  subroutine piecewise_linear_1d(zvals, vals, zgrid, field)
16 
17  real(kind=default_precision), intent(in) :: zvals(:), vals(:)
18  real(kind=default_precision), intent(inout) :: zgrid(:)
19  real(kind=default_precision), intent(inout) :: field(:)
20 
21  real(kind=default_precision) :: initgd_lem(size(zvals)+1)
22  real(kind=default_precision) :: zngd_lem(size(zvals)+1)
23  real(kind=default_precision) :: field_lem(size(field))
24 
25  real(kind=default_precision) :: verylow, veryhigh
26 
27  integer :: nn,k ! loop counters
28  integer :: nnodes ! number of input values
29 
30  nnodes=size(zvals)
31 
32 
33  ! Code replicated from the LEM. This duplicates the interpolation of the
34  ! LEM exactly
35  verylow = -1.0e5
36 
37  initgd_lem(1) = vals(1)
38  zngd_lem(1) = verylow
39  DO nn=2,nnodes+1
40  initgd_lem(nn) = vals(nn-1)
41  zngd_lem(nn) = zvals(nn-1)
42  ENDDO
43 
44  do nn=1,nnodes
45  DO k=1,size(field)
46  IF( zngd_lem(nn).LE.zgrid(k) .AND. zgrid(k).LT.zngd_lem(nn+1)) then
47  field(k) = initgd_lem(nn) + ( initgd_lem(nn+1) - initgd_lem(nn))*(zgrid(k)- zngd_lem(nn))/ &
48  (zngd_lem(nn+1) - zngd_lem(nn))
49  end IF
50  end DO
51  end do
52 
53  ! Add check in for when zgrid(k_top) equals zngd_lem(nn+1), which is the case for subsidence
54  if (zgrid(size(field)) == zngd_lem(nnodes+1)) Then
55  field(size(field)) = initgd_lem(nnodes+1)
56  endif
57 
58  end subroutine piecewise_linear_1d
59 
65  subroutine interpolate_point_linear_1d(zvals, vals, z, f, extrapolate)
66 
67  real(kind=default_precision), intent(in) :: zvals(:), vals(:)
68  real(kind=default_precision), intent(in) :: z
69  real(kind=default_precision), intent(out) :: f
70  character(*), intent(in), optional :: extrapolate
71 
72  integer :: nn ! loop counter
73  integer :: nnodes ! number of input values
74 
75  integer, parameter :: MAXCHARS=20
76  character(MAXCHARS) :: ext_type
77 
78  nnodes=size(zvals)
79  ! suggested fix from JME
80  do
81  if (nnodes == 1) exit
82  if (zvals(nnodes-1) < zvals(nnodes)) exit
83  nnodes = nnodes - 1
84  enddo
85  !
86  ext_type='linear'
87  if (present(extrapolate))ext_type=trim(extrapolate)
88 
89  if (z < zvals(1))then
90  nn=1
91  select case (trim(ext_type))
92  case ('linear')
93  f = vals(nn) + (vals(nn+1) - vals(nn))/(zvals(nn+1) - zvals(nn)) &
94  *(z - zvals(nn))
95  case ('constant')
96  f = vals(nn)
97  end select
98  return
99  end if
100 
101  if (present(extrapolate))ext_type=trim(extrapolate)
102 
103  if (z >= zvals(nnodes))then
104  nn=nnodes
105  select case (trim(ext_type))
106  case ('linear')
107  f = vals(nn) + (vals(nn-1) - vals(nn))/(zvals(nn-1) - zvals(nn)) &
108  *(z - zvals(nn))
109  case ('constant')
110  f = vals(nn)
111  end select
112  return
113  end if
114 
115  do nn=1,nnodes-1
116  if (zvals(nn) <= z .and. z < zvals(nn+1))then
117  f = vals(nn) + (vals(nn+1) - vals(nn))/(zvals(nn+1) - zvals(nn)) &
118  *(z - zvals(nn))
119  exit
120  end if
121  end do
122 
123  end subroutine interpolate_point_linear_1d
124 
130  subroutine piecewise_linear_2d(zvals, time_vals, vals, z, field)
131 
132  ! Assumes input variables (vals) are 2-D, with dims (z, time)
133 
134  real(kind=default_precision), intent(in) :: zvals(:), time_vals(:)
135  real(kind=default_precision), intent(in) :: vals(:,:)
136  real(kind=default_precision), intent(in) :: z(:)
137  real(kind=default_precision), intent(out) :: field(:,:)
138 
139  real(kind=default_precision) :: scale_tmp
140 
141  integer :: nn, k_monc, k_force ! loop counter
142  integer :: nz_force, nt_force, nz_monc, nt_monc ! time and height array sizes for forcing and monc grids
143  integer :: nnodes ! number of input values
144 
145  nz_force = size(zvals)
146  nt_force = size(time_vals)
147  nz_monc = size(z)
148  nt_monc = size(time_vals) ! time is intepolated in the timestep callback
149 
150  if ( zvals(1) .GT. zvals(nz_force) ) then ! pressure
151  call log_master_log(log_error, "Input forcing uses pressure, this has not been coded"// &
152  " - please modify your forcing file to using height coordinates or modify the" // &
153  " interpolation routine in model_core to work with pressure coords - STOP")
154  else
155  do k_monc=2,nz_monc
156  do k_force=1,nz_force-1
157  if( z(k_monc) >= zvals(k_force) .AND. z(k_monc) < zvals(k_force+1) ) then
158  scale_tmp = ( z(k_monc) - zvals(k_force) ) / &
159  ( zvals(k_force+1) - zvals(k_force) )
160  do nn=1, nt_force
161  field(k_monc,nn) = vals(k_force,nn) + &
162  ( vals(k_force+1,nn) - vals(k_force,nn) ) &
163  * scale_tmp
164  enddo
165  endif
166  enddo
167  enddo
168  ! now examine the cases below and above forlevs(1) and forlevs(ktmfor
169  ! uses the local vertical gradient in the forcing to determine the
170  ! new values
171  do k_monc=2,nz_monc
172  if ( z(k_monc) >= zvals(nt_force) ) then
173  scale_tmp = ( z(k_monc) - zvals(nz_force) ) &
174  / ( zvals(nz_force) - zvals(nz_force-1) )
175  do nn=1,nt_force
176  field(k_monc,nn) = vals(nz_force,nn) + &
177  ( vals(nz_force,nn) - vals(nz_force-1,nn) ) &
178  * scale_tmp
179  enddo
180  elseif ( z(k_monc) < zvals(1) )THEN
181  scale_tmp = ( z(k_monc) - zvals(1) ) &
182  / ( zvals(1) - zvals(2) )
183  do nn=1,nt_force
184  field(k_monc,nn) = vals(1,nn) + &
185  ( vals(1,nn) - vals(2,nn) ) &
186  * scale_tmp
187  enddo
188  endif
189  enddo
190  !
191  endif ! pressure or height
192 
193  end subroutine piecewise_linear_2d
194 
195  subroutine interpolate_point_linear_2d(zvals, vals, z, f, extrapolate)
196 
197  ! 2-d because the "vals" array is 2d, probably height and time
198 
199  real(kind=default_precision), intent(in) :: zvals(:), vals(:,:)
200  real(kind=default_precision), intent(in) :: z
201  real(kind=default_precision), intent(out) :: f(:) ! height
202  character(*), intent(in), optional :: extrapolate
203 
204  integer :: nn ! loop counter
205  integer :: nnodes ! number of input values
206 
207  integer, parameter :: MAXCHARS=20
208  character(MAXCHARS) :: ext_type
209 
210  nnodes=size(zvals)
211  ! suggested fix from JME
212  do
213  if (nnodes == 1) exit
214  if (zvals(nnodes-1) < zvals(nnodes)) exit
215  nnodes = nnodes - 1
216  enddo
217  !
218  ext_type='linear'
219  if (present(extrapolate))ext_type=trim(extrapolate)
220 
221  ! test where model time is outside the bounds of the input forcing times
222 
223  ! 1) less than the lowest time level in forcing times
224  if (z < zvals(1))then
225  nn=1
226  f(:) = vals(:,nn)
227  return
228  end if
229 
230  !if (present(extrapolate))ext_type=trim(extrapolate)
231 
232  ! 2) greater than the last time level in the forcing times, make forcing constant
233  if (z >= zvals(nnodes))then
234  nn=nnodes
235  f(:) = vals(:,nn)
236  return
237  end if
238 
239  ! Time is within the bounds of the forcing input time
240 
241  do nn = 1, nnodes-1
242  if (zvals(nn) <= z .and. z < zvals(nn+1)) then
243  select case (trim(ext_type))
244  case ('linear')
245  f(:) = vals(:,nn) + (vals(:,nn+1) - vals(:,nn))/(zvals(nn+1) - zvals(nn)) &
246  *(z - zvals(nn))
247  case ('constant')
248  f(:) = vals(:,nn)
249  end select
250  exit
251  endif
252  enddo
253 
254 
255  end subroutine interpolate_point_linear_2d
256 
257 end module interpolation_mod
logging_mod::log_error
integer, parameter, public log_error
Only log ERROR messages.
Definition: logging.F90:11
interpolation_mod::piecewise_linear_1d
subroutine piecewise_linear_1d(zvals, vals, zgrid, field)
Does a simple 1d piecewise linear interpolation.
Definition: interpolation.F90:16
interpolation_mod::interpolate_point_linear_2d
subroutine interpolate_point_linear_2d(zvals, vals, z, f, extrapolate)
Definition: interpolation.F90:196
interpolation_mod::interpolate_point_linear_1d
subroutine interpolate_point_linear_1d(zvals, vals, z, f, extrapolate)
Does a simple 1d linear interpolation to a point.
Definition: interpolation.F90:66
logging_mod::log_log
subroutine, public log_log(level, message, str)
Logs a message at the specified level. If the level is above the current level then the message is ig...
Definition: logging.F90:75
logging_mod::log_get_logging_level
integer function, public log_get_logging_level()
Retrieves the current logging level.
Definition: logging.F90:122
logging_mod::log_debug
integer, parameter, public log_debug
Log DEBUG, INFO, WARNING and ERROR messages.
Definition: logging.F90:14
interpolation_mod::piecewise_linear_2d
subroutine piecewise_linear_2d(zvals, time_vals, vals, z, field)
Does a simple 1d linear interpolation to a point.
Definition: interpolation.F90:131
logging_mod
Logging utility.
Definition: logging.F90:2
datadefn_mod
Contains common definitions for the data and datatypes used by MONC.
Definition: datadefn.F90:2
logging_mod::log_master_log
subroutine, public log_master_log(level, message)
Will log just from the master process.
Definition: logging.F90:47
interpolation_mod
Definition: interpolation.F90:2
datadefn_mod::default_precision
integer, parameter, public default_precision
MPI communication type which we use for the prognostic and calculation data.
Definition: datadefn.F90:17