FMS  2024.03
Flexible Modeling System
time_interp_external2.inc
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @ingroup time_interp
20 !> @addtogroup time_interp_external2_mod
21 !> @{
22 
23  !> @brief 2D interpolation for @ref time_interp_external
24  subroutine time_interp_external_2d_(index, time, data_in, interp, verbose,horz_interp, mask_out, &
25  is_in, ie_in, js_in, je_in, window_id)
26 
27  integer, intent(in) :: index
28  type(time_type), intent(in) :: time
29  real(FMS_TI_KIND_), dimension(:,:), intent(inout) :: data_in
30  integer, intent(in), optional :: interp
31  logical, intent(in), optional :: verbose
32  type(horiz_interp_type),intent(in), optional :: horz_interp
33  logical, dimension(:,:), intent(out), optional :: mask_out !< set to true where output data is valid
34  integer, intent(in), optional :: is_in, ie_in, js_in, je_in
35  integer, intent(in), optional :: window_id
36 
37  real(FMS_TI_KIND_), dimension(size(data_in,1), size(data_in,2), 1) :: data_out
38  logical, dimension(size(data_in,1), size(data_in,2), 1) :: mask3d
39 
40  data_out(:,:,1) = data_in(:,:) ! fill initial values for the portions of array that are not touched by 3d routine
41  call time_interp_external(index, time, data_out, interp, verbose, horz_interp, mask3d, &
42  is_in=is_in,ie_in=ie_in,js_in=js_in,je_in=je_in,window_id=window_id)
43  data_in(:,:) = data_out(:,:,1)
44  if (PRESENT(mask_out)) mask_out(:,:) = mask3d(:,:,1)
45 
46  return
47  end subroutine time_interp_external_2d_
48 
49 
50 
51  !> 3D interpolation for @ref time_interp_external
52  !! Provide data from external file interpolated to current model time.
53  !! Data may be local to current processor or global, depending on
54  !! "init_external_field" flags.
55  subroutine time_interp_external_3d_(index, time, time_data, interp,verbose,horz_interp, mask_out, is_in, ie_in, &
56  & js_in, je_in, window_id)
57 
58  integer, intent(in) :: index !< index of external field from previous call
59  !! to init_external_field
60  type(time_type), intent(in) :: time !< target time for data
61  real(FMS_TI_KIND_), dimension(:,:,:), intent(inout) :: time_data !< global or local data array
62  integer, intent(in), optional :: interp
63  logical, intent(in), optional :: verbose !< flag for debugging
64  type(horiz_interp_type), intent(in), optional :: horz_interp
65  logical, dimension(:,:,:), intent(out), optional :: mask_out !< set to true where output data is valid
66  integer, intent(in), optional :: is_in, ie_in, js_in, je_in
67  integer, intent(in), optional :: window_id
68 
69  integer :: nx, ny, nz, interp_method, t1, t2
70  integer :: i1, i2, isc, iec, jsc, jec, mod_time
71  integer :: yy, mm, dd, hh, min, ss
72  character(len=256) :: err_msg
73  character(len=FMS_PATH_LEN) :: filename
74 
75  integer :: isw, iew, jsw, jew, nxw, nyw
76  ! these are boundaries of the updated portion of the "data" argument
77  ! they are calculated using sizes of the "data" and isc,iec,jsc,jsc
78  ! fileds from respective input field, to center the updated portion
79  ! in the output array
80 
81  real(FMS_TI_KIND_) :: w1,w2
82  logical :: verb
83  character(len=16) :: message1, message2
84  integer, parameter :: kindl = fms_ti_kind_
85 
86  nx = size(time_data,1)
87  ny = size(time_data,2)
88  nz = size(time_data,3)
89 
90  interp_method = linear_time_interp
91  if (PRESENT(interp)) interp_method = interp
92  verb=.false.
93  if (PRESENT(verbose)) verb=verbose
94  if (debug_this_module) verb = .true.
95 
96  if (index < 1.or.index > num_fields) &
97  call mpp_error(fatal, &
98  & 'invalid index in call to time_interp_ext -- field was not initialized or failed to initialize')
99 
100  isc=loaded_fields(index)%isc;iec=loaded_fields(index)%iec
101  jsc=loaded_fields(index)%jsc;jec=loaded_fields(index)%jec
102 
103  if( loaded_fields(index)%numwindows == 1 ) then
104  nxw = iec-isc+1
105  nyw = jec-jsc+1
106  else
107  if(.not. present(is_in) .or. .not. present(ie_in) .or. .not. present(js_in) .or. .not. present(je_in))then
108  call mpp_error(fatal, 'time_interp_external: is_in, ie_in, js_in and je_in must be present ' // &
109  'when numwindows > 1, field='//trim(loaded_fields(index)%name))
110  endif
111  nxw = ie_in - is_in + 1
112  nyw = je_in - js_in + 1
113  isc = isc + is_in - 1
114  iec = isc + ie_in - is_in
115  jsc = jsc + js_in - 1
116  jec = jsc + je_in - js_in
117  endif
118 
119  isw = (nx-nxw)/2+1; iew = isw+nxw-1
120  jsw = (ny-nyw)/2+1; jew = jsw+nyw-1
121 
122  if (nx < nxw .or. ny < nyw .or. nz < loaded_fields(index)%siz(3)) then
123  write(message1,'(i6,2i5)') nx,ny,nz
124  call mpp_error(fatal,'field '//trim(loaded_fields(index)%name)// &
125  ' Array size mismatch in time_interp_external. Array "data" is too small. shape(data)=' &
126  //message1)
127  endif
128  if(PRESENT(mask_out)) then
129  if (size(mask_out,1) /= nx .or. size(mask_out,2) /= ny .or. size(mask_out,3) /= nz) then
130  write(message1,'(i6,2i5)') nx,ny,nz
131  write(message2,'(i6,2i5)') size(mask_out,1),size(mask_out,2),size(mask_out,3)
132  call mpp_error(fatal,'field '//trim(loaded_fields(index)%name)// &
133  ' array size mismatch in time_interp_external.'// &
134  ' Shape of array "mask_out" does not match that of array "data".'// &
135  ' shape(data)='//message1//' shape(mask_out)='//message2)
136  endif
137  endif
138 
139  ! only one record in the file => time-independent field
140  if (loaded_fields(index)%siz(4) == 1) then
141  call load_record(loaded_fields(index),1,horz_interp, is_in, ie_in ,js_in, je_in,window_id)
142  i1 = find_buf_index(1,loaded_fields(index)%ibuf)
143  if( loaded_fields(index)%region_type == no_region ) then
144  where(loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1))
145  time_data(isw:iew,jsw:jew,:) = real( loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i1),&
146  fms_ti_kind_)
147  elsewhere
148  ! time_data(isw:iew,jsw:jew,:) = time_interp_missing !field(index)%missing? Balaji
149  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index)%missing, fms_ti_kind_)
150  end where
151  else
152  where(loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1))
153  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i1),&
154  fms_ti_kind_)
155  end where
156  endif
157  if(PRESENT(mask_out)) mask_out(isw:iew,jsw:jew,:) = loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1)
158  ! otherwise do interpolation
159  else
160  ! using time_interp_modulo
161  if(loaded_fields(index)%have_modulo_times) then
162  call time_interp(time,loaded_fields(index)%modulo_time_beg, loaded_fields(index)%modulo_time_end, &
163  loaded_fields(index)%time(:), w2, t1, t2, &
164  loaded_fields(index)%correct_leap_year_inconsistency, err_msg=err_msg)
165  if(err_msg .NE. '') then
166  filename = trim(loaded_fields(index)%fileobj%path)
167  call mpp_error(fatal,"time_interp_external 1: "//trim(err_msg)//&
168  ",file="//trim(filename)//",field="//trim(loaded_fields(index)%name) )
169  endif
170  ! using time_interp_list
171  else
172  if(loaded_fields(index)%modulo_time) then
173  mod_time=1
174  else
175  mod_time=0
176  endif
177  call time_interp(time,loaded_fields(index)%time(:),w2,t1,t2,modtime=mod_time, err_msg=err_msg)
178  if(err_msg .NE. '') then
179  filename = trim(loaded_fields(index)%fileobj%path)
180  call mpp_error(fatal,"time_interp_external 2: "//trim(err_msg)//&
181  ",file="//trim(filename)//",field="//trim(loaded_fields(index)%name) )
182  endif
183  endif
184  w1 = 1.0_kindl -w2
185  if (verb) then
186  call get_date(time,yy,mm,dd,hh,min,ss)
187  write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
188  'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',min,':',ss
189  write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2
190  endif
191 
192  call load_record(loaded_fields(index),t1,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
193  call load_record(loaded_fields(index),t2,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
194  i1 = find_buf_index(t1,loaded_fields(index)%ibuf)
195  i2 = find_buf_index(t2,loaded_fields(index)%ibuf)
196  if(i1<0.or.i2<0) &
197  call mpp_error(fatal,'time_interp_external : records were not loaded correctly in memory')
198 
199  if (verb) then
200  write(outunit,*) 'ibuf= ',loaded_fields(index)%ibuf
201  write(outunit,*) 'i1,i2= ',i1, i2
202  endif
203 
204  if( loaded_fields(index)%region_type == no_region ) then
205  where(loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1) .and. &
206  loaded_fields(index)%mask(isc:iec,jsc:jec,:,i2))
207  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i1), kindl)&
208  * w1 + real(loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i2), kindl) * w2
209  elsewhere
210  ! time_data(isw:iew,jsw:jew,:) = time_interp_missing !loaded_fields(index)%missing? Balaji
211  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index)%missing, kindl)
212  end where
213  else
214  where(loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1) .and. &
215  loaded_fields(index)%mask(isc:iec,jsc:jec,:,i2))
216  time_data(isw:iew,jsw:jew,:) = real( loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i1), kindl)&
217  * w1 + real(loaded_fields(index)%domain_data(isc:iec,jsc:jec,:,i2), kindl) * w2
218  end where
219  endif
220  if(PRESENT(mask_out)) &
221  mask_out(isw:iew,jsw:jew,:) = &
222  loaded_fields(index)%mask(isc:iec,jsc:jec,:,i1).and.&
223  loaded_fields(index)%mask(isc:iec,jsc:jec,:,i2)
224  endif
225 
226  end subroutine time_interp_external_3d_
227 !</SUBROUTINE> NAME="time_interp_external"
228 
229  !> @brief Scalar interpolation for @ref time_interp_external
230  subroutine time_interp_external_0d_(index, time, time_data, verbose)
231 
232  integer, intent(in) :: index
233  type(time_type), intent(in) :: time
234  real(FMS_TI_KIND_), intent(inout) :: time_data
235  logical, intent(in), optional :: verbose
236 
237  integer :: t1, t2
238  integer :: i1, i2, mod_time
239  integer :: yy, mm, dd, hh, min, ss
240  character(len=256) :: err_msg
241  character(len=FMS_PATH_LEN) :: filename
242 
243  real(FMS_TI_KIND_) :: w1,w2
244  logical :: verb
245  integer, parameter :: kindl = fms_ti_kind_
246 
247  verb=.false.
248  if (PRESENT(verbose)) verb=verbose
249  if (debug_this_module) verb = .true.
250 
251  if (index < 1.or.index > num_fields) &
252  call mpp_error(fatal, &
253  & 'invalid index in call to time_interp_ext -- field was not initialized or failed to initialize')
254 
255  if (loaded_fields(index)%siz(4) == 1) then
256  ! only one record in the file => time-independent loaded_fields
257  call load_record_0d(loaded_fields(index),1)
258  i1 = find_buf_index(1,loaded_fields(index)%ibuf)
259  time_data = real(loaded_fields(index)%domain_data(1,1,1,i1), fms_ti_kind_)
260  else
261  if(loaded_fields(index)%have_modulo_times) then
262  call time_interp(time,loaded_fields(index)%modulo_time_beg, loaded_fields(index)%modulo_time_end, &
263  loaded_fields(index)%time(:), w2, t1, t2, &
264  loaded_fields(index)%correct_leap_year_inconsistency, err_msg=err_msg)
265  if(err_msg .NE. '') then
266  filename = trim(loaded_fields(index)%fileobj%path)
267  call mpp_error(fatal,"time_interp_external 3:"//trim(err_msg)//&
268  ",file="//trim(filename)//",field="//trim(loaded_fields(index)%name) )
269  endif
270  else
271  if(loaded_fields(index)%modulo_time) then
272  mod_time=1
273  else
274  mod_time=0
275  endif
276  call time_interp(time,loaded_fields(index)%time(:),w2,t1,t2,modtime=mod_time, err_msg=err_msg)
277  if(err_msg .NE. '') then
278  filename = trim(loaded_fields(index)%fileobj%path)
279  call mpp_error(fatal,"time_interp_external 4:"//trim(err_msg)// &
280  ",file="//trim(filename)//",field="//trim(loaded_fields(index)%name) )
281  endif
282  endif
283  w1 = 1.0_kindl-w2
284  if (verb) then
285  call get_date(time,yy,mm,dd,hh,min,ss)
286  write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
287  'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',min,':',ss
288  write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2
289  endif
290  call load_record_0d(loaded_fields(index),t1)
291  call load_record_0d(loaded_fields(index),t2)
292  i1 = find_buf_index(t1,loaded_fields(index)%ibuf)
293  i2 = find_buf_index(t2,loaded_fields(index)%ibuf)
294 
295  if(i1<0.or.i2<0) &
296  call mpp_error(fatal,'time_interp_external : records were not loaded correctly in memory')
297  time_data = real(loaded_fields(index)%domain_data(1,1,1,i1), fms_ti_kind_)*w1 &
298  & + real(loaded_fields(index)%domain_data(1,1,1,i2), fms_ti_kind_)*w2
299  if (verb) then
300  write(outunit,*) 'ibuf= ',loaded_fields(index)%ibuf
301  write(outunit,*) 'i1,i2= ',i1, i2
302  endif
303  endif
304 
305  end subroutine time_interp_external_0d_
306 
307 ! ============================================================================
subroutine time_interp_external_2d_(index, time, data_in, interp, verbose, horz_interp, mask_out, is_in, ie_in, js_in, je_in, window_id)
2D interpolation for time_interp_external
subroutine time_interp_external_3d_(index, time, time_data, interp, verbose, horz_interp, mask_out, is_in, ie_in, js_in, je_in, window_id)
3D interpolation for time_interp_external Provide data from external file interpolated to current mod...
subroutine time_interp_external_0d_(index, time, time_data, verbose)
Scalar interpolation for time_interp_external.