FMS  2024.03
Flexible Modeling System
time_interp_external2_bridge.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_bridge
24  subroutine time_interp_external_bridge_2d_(index1, index2, 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) :: index1 !< index of first external field
28  integer, intent(in) :: index2 !< index of second external field
29  type(time_type), intent(in) :: time !< target time for data
30  real(FMS_TI_KIND_), dimension(:,:), intent(inout) :: data_in !< global or local data array
31  integer, intent(in), optional :: interp !< hardcoded to linear
32  logical, intent(in), optional :: verbose !< flag for debugging
33  type(horiz_interp_type),intent(in), optional :: horz_interp !< horizontal interpolation type
34  logical, dimension(:,:), intent(out), optional :: mask_out !< set to true where output data is valid
35  integer, intent(in), optional :: is_in, ie_in, js_in, je_in !< horizontal indices for load_record
36  integer, intent(in), optional :: window_id !< harcoded to 1 in load_record
37 
38  real(FMS_TI_KIND_), dimension(size(data_in,1), size(data_in,2), 1) :: data_out !< 3d version of data_in
39  logical, dimension(size(data_in,1), size(data_in,2), 1) :: mask3d !< 3d version of mask_out
40 
41  data_out(:,:,1) = data_in(:,:) ! fill initial values for the portions of array that are not touched by 3d routine
42  call time_interp_external_bridge(index1, index2, time, data_out, interp, verbose, horz_interp, mask3d, &
43  is_in=is_in,ie_in=ie_in,js_in=js_in,je_in=je_in,window_id=window_id)
44  data_in(:,:) = data_out(:,:,1)
45  if (PRESENT(mask_out)) mask_out(:,:) = mask3d(:,:,1)
46 
47  return
48  end subroutine time_interp_external_bridge_2d_
49 
50  !> 3D interpolation for @ref time_interp_external
51  !! Provide data from external file interpolated to current model time.
52  !! Data may be local to current processor or global, depending on
53  !! "init_external_field" flags.
54  subroutine time_interp_external_bridge_3d_(index1, index2, time, time_data, interp,verbose,horz_interp, mask_out, &
55  & is_in, ie_in, js_in, je_in, window_id)
56 
57  integer, intent(in) :: index1 !< index of first external field
58  integer, intent(in) :: index2 !< index of second external field
59  type(time_type), intent(in) :: time !< target time for data
60  real(FMS_TI_KIND_), dimension(:,:,:), intent(inout) :: time_data !< global or local data array
61  integer, intent(in), optional :: interp !< hardcoded to linear
62  logical, intent(in), optional :: verbose !< flag for debugging
63  type(horiz_interp_type), intent(in), optional :: horz_interp !< horizontal interpolation type
64  logical, dimension(:,:,:), intent(out), optional :: mask_out !< set to true where output data is valid
65  integer, intent(in), optional :: is_in, ie_in !< x horizontal indices for load_record
66  integer, intent(in), optional :: js_in, je_in !< y horizontal indices for load_record
67  integer, intent(in), optional :: window_id !< harcoded to 1 in load_record
68 
69  type(time_type) :: time1 !< time type associated with index1 of external field
70  type(time_type) :: time2 !< time type associated with index2 of external field
71  integer :: dims1(4) !< dimensions XYZT of index1
72  integer :: dims2(4) !< dimensions XYZT of index2
73  integer :: nx, ny, nz !< size in X,Y,Z of array
74  integer :: interp_method !< hardcoded to linear in time
75  integer :: t1, t2 !< temporary to store time index
76  integer :: i1, i2 !< temporary to store time index
77  integer :: isc, iec, jsc, jec !< start/end arrays in X,Y
78  integer :: isc1, iec1, jsc1, jec1 !< start/end arrays in X,Y for field1
79  integer :: isc2, iec2, jsc2, jec2 !< start/end arrays in X,Y for field2
80  integer :: yy, mm, dd, hh, minu, ss !< year, month, day, hour, minute, second for date
81 
82  integer :: isw, iew, jsw, jew, nxw, nyw !< these are boundaries of the updated portion of the "data" argument
83  !! they are calculated using sizes of the "data" and isc,iec,jsc,jsc
84  !! fileds from respective input field, to center the updated portion
85  !! in the output array
86 
87  real(FMS_TI_KIND_) :: w1 !< interp weight for index1
88  real(FMS_TI_KIND_) :: w2 !< interp weight for index2
89  logical :: verb !< verbose
90  character(len=16) :: message1 !< temp string
91  character(len=16) :: message2 !< temp string
92  integer, parameter :: kindl = fms_ti_kind_
93 
94  nx = size(time_data,1)
95  ny = size(time_data,2)
96  nz = size(time_data,3)
97 
98  interp_method = linear_time_interp
99  if (PRESENT(interp)) interp_method = interp
100  verb=.false.
101  if (PRESENT(verbose)) verb=verbose
102  if (debug_this_module) verb = .true.
103 
104  if (index1 < 1 .or. index1 > num_fields) &
105  call mpp_error(fatal,'invalid index1 in call to time_interp_external_bridge:' // &
106  '-- field was not initialized or failed to initialize')
107  if (index2 < 1 .or. index2 > num_fields) &
108  call mpp_error(fatal,'invalid index2 in call to time_interp_external_bridge:' // &
109  ' -- field was not initialized or failed to initialize')
110 
111  isc1=loaded_fields(index1)%isc;iec1=loaded_fields(index1)%iec
112  jsc1=loaded_fields(index1)%jsc;jec1=loaded_fields(index1)%jec
113  isc2=loaded_fields(index2)%isc;iec2=loaded_fields(index2)%iec
114  jsc2=loaded_fields(index2)%jsc;jec2=loaded_fields(index2)%jec
115 
116  if ((isc1 /= isc2) .or. (iec1 /= iec2) .or. (jsc1 /= jsc2) .or. (jec1 /= jec2)) then
117  call mpp_error(fatal, 'time_interp_external_bridge: dimensions must be the same in both index1 and index2 ')
118  endif
119 
120  isc=isc1 ; iec=iec1 ; jsc=jsc1 ; jec=jec1
121 
122  if (trim(loaded_fields(index2)%name) /= trim(loaded_fields(index1)%name)) then
123  call mpp_error(fatal, 'time_interp_external_bridge: cannot bridge between different fields.' // &
124  'field1='//trim(loaded_fields(index1)%name)//' field2='//trim(loaded_fields(index2)%name))
125  endif
126 
127  if ((loaded_fields(index1)%numwindows == 1) .and. (loaded_fields(index2)%numwindows == 1)) then
128  nxw = iec-isc+1
129  nyw = jec-jsc+1
130  else
131  if(.not. present(is_in) .or. .not. present(ie_in) .or. .not. present(js_in) .or. .not. present(je_in))then
132  call mpp_error(fatal, 'time_interp_external: is_in, ie_in, js_in and je_in must be present ' // &
133  'when numwindows > 1, field='//trim(loaded_fields(index1)%name))
134  endif
135  nxw = ie_in - is_in + 1
136  nyw = je_in - js_in + 1
137  isc = isc + is_in - 1
138  iec = isc + ie_in - is_in
139  jsc = jsc + js_in - 1
140  jec = jsc + je_in - js_in
141  endif
142 
143  isw = (nx-nxw)/2+1; iew = isw+nxw-1
144  jsw = (ny-nyw)/2+1; jew = jsw+nyw-1
145 
146  if (nx < nxw .or. ny < nyw .or. nz < loaded_fields(index1)%siz(3)) then
147  write(message1,'(i6,2i5)') nx,ny,nz
148  call mpp_error(fatal,'field '//trim(loaded_fields(index1)%name)// &
149  ' Array size mismatch in time_interp_external_bridge.'// &
150  ' Array "data" is too small. shape(time_data)='//message1)
151  endif
152  if (nx < nxw .or. ny < nyw .or. nz < loaded_fields(index2)%siz(3)) then
153  write(message1,'(i6,2i5)') nx,ny,nz
154  call mpp_error(fatal,'field '//trim(loaded_fields(index2)%name)// &
155  ' Array size mismatch in time_interp_external_bridge.'// &
156  ' Array "data" is too small. shape(time_data)='//message1)
157  endif
158 
159  if(PRESENT(mask_out)) then
160  if (size(mask_out,1) /= nx .or. size(mask_out,2) /= ny .or. size(mask_out,3) /= nz) then
161  write(message1,'(i6,2i5)') nx,ny,nz
162  write(message2,'(i6,2i5)') size(mask_out,1),size(mask_out,2),size(mask_out,3)
163  call mpp_error(fatal,'field '//trim(loaded_fields(index1)%name)// &
164  ' array size mismatch in time_interp_external_bridge.'// &
165  ' Shape of array "mask_out" does not match that of array "data".'// &
166  ' shape(time_data)='//message1//' shape(mask_out)='//message2)
167  endif
168  endif
169 
170  if ((loaded_fields(index1)%have_modulo_times) .or. (loaded_fields(index2)%have_modulo_times)) then
171  call mpp_error(fatal, 'time_interp_external_bridge: field '//trim(loaded_fields(index1)%name)// &
172  ' array cannot have modulo time')
173  endif
174  if ((loaded_fields(index1)%modulo_time) .or. (loaded_fields(index2)%modulo_time)) then
175  call mpp_error(fatal, 'time_interp_external_bridge: field '//trim(loaded_fields(index1)%name)// &
176  ' array cannot have modulo time')
177  endif
178 
179  dims1 = get_external_field_size(index1)
180  dims2 = get_external_field_size(index2)
181 
182  t1 = dims1(4)
183  t2 = 1
184 
185  time1 = loaded_fields(index1)%time(t1)
186  time2 = loaded_fields(index2)%time(t2)
187  w2= (time - time1) // (time2 - time1)
188  w1 = 1.0_kindl-w2
189 
190  if (verb) then
191  call get_date(time,yy,mm,dd,hh,minu,ss)
192  write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
193  'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',minu,':',ss
194  write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2
195  endif
196 
197  call load_record(loaded_fields(index1),t1,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
198  call load_record(loaded_fields(index2),t2,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
199  i1 = find_buf_index(t1,loaded_fields(index1)%ibuf)
200  i2 = find_buf_index(t2,loaded_fields(index2)%ibuf)
201  if(i1<0.or.i2<0) &
202  call mpp_error(fatal,'time_interp_external_bridge : records were not loaded correctly in memory')
203 
204  if (verb) then
205  write(outunit,*) 'ibuf= ',loaded_fields(index2)%ibuf
206  write(outunit,*) 'i1,i2= ',i1, i2
207  endif
208 
209  if((loaded_fields(index1)%region_type == no_region) .and. (loaded_fields(index2)%region_type == no_region) ) then
210  where(loaded_fields(index1)%mask(isc:iec,jsc:jec,:,i1).and.loaded_fields(index2)%mask(isc:iec,jsc:jec,:,i2))
211  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index1)%domain_data(isc:iec,jsc:jec,:,i1), kindl)*w1 + &
212  real(loaded_fields(index2)%domain_data(isc:iec,jsc:jec,:,i2), kindl)*w2
213  elsewhere
214  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index1)%missing, kindl)
215  end where
216  else
217  where(loaded_fields(index1)%mask(isc:iec,jsc:jec,:,i1).and.loaded_fields(index2)%mask(isc:iec,jsc:jec,:,i2))
218  time_data(isw:iew,jsw:jew,:) = real(loaded_fields(index1)%domain_data(isc:iec,jsc:jec,:,i1), kindl)*w1 + &
219  real(loaded_fields(index2)%domain_data(isc:iec,jsc:jec,:,i2), kindl)*w2
220  end where
221  endif
222 
223  if(PRESENT(mask_out)) &
224  mask_out(isw:iew,jsw:jew,:) = &
225  loaded_fields(index1)%mask(isc:iec,jsc:jec,:,i1).and.&
226  loaded_fields(index2)%mask(isc:iec,jsc:jec,:,i2)
227 
228  end subroutine time_interp_external_bridge_3d_
229 
230  subroutine time_interp_external_bridge_0d_(index1, index2, time, time_data, verbose)
231 
232  integer, intent(in) :: index1 !< index of first external field
233  integer, intent(in) :: index2 !< index of second external field
234  type(time_type), intent(in) :: time !< target time for data
235  real(FMS_TI_KIND_), intent(inout) :: time_data !< global or local data array
236  logical, intent(in), optional :: verbose !< flag for debugging
237 
238  integer :: t1, t2 !< temporary to store time index
239  integer :: i1, i2 !< temporary to store time index
240  integer :: yy, mm, dd, hh, minu, ss !< year, month, day, hour, minute, second for date
241  type(time_type) :: time1 !< time type associated with index1 of external field
242  type(time_type) :: time2 !< time type associated with index2 of external field
243  integer :: dims1(4) !< dimensions XYZT of index1
244  integer :: dims2(4) !< dimensions XYZT of index2
245 
246  real(FMS_TI_KIND_) :: w1 !< interp weight for index1
247  real(FMS_TI_KIND_) :: w2 !< interp weight for index2
248  logical :: verb !< verbose
249  integer, parameter :: kindl = fms_ti_kind_
250 
251  verb=.false.
252  if (PRESENT(verbose)) verb=verbose
253  if (debug_this_module) verb = .true.
254 
255  if (index1 < 0 .or. index1 > num_fields) &
256  call mpp_error(fatal,'invalid index1 in call to time_interp_ext' // &
257  ' -- field was not initialized or failed to initialize')
258  if (index2 < 0 .or. index2 > num_fields) &
259  call mpp_error(fatal,'invalid index2 in call to time_interp_ext' // &
260  ' -- field was not initialized or failed to initialize')
261 
262  if ((loaded_fields(index1)%have_modulo_times) .or. (loaded_fields(index2)%have_modulo_times)) then
263  call mpp_error(fatal, 'time_interp_external_bridge: field '//trim(loaded_fields(index1)%name)// &
264  ' array cannot have modulo time')
265  endif
266  if ((loaded_fields(index1)%modulo_time) .or. (loaded_fields(index2)%modulo_time)) then
267  call mpp_error(fatal, 'time_interp_external_bridge: field '//trim(loaded_fields(index1)%name)// &
268  ' array cannot have modulo time')
269  endif
270 
271  dims1 = get_external_field_size(index1)
272  dims2 = get_external_field_size(index2)
273 
274  t1 = dims1(4)
275  t2 = 1
276 
277  time1 = loaded_fields(index1)%time(t1)
278  time2 = loaded_fields(index2)%time(t2)
279  w2= (time - time1) // (time2 - time1)
280  w1 = 1.0_kindl-w2
281 
282  if (verb) then
283  call get_date(time,yy,mm,dd,hh,minu,ss)
284  write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
285  'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',minu,':',ss
286  write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2
287  endif
288  call load_record_0d(loaded_fields(index2),t1)
289  call load_record_0d(loaded_fields(index2),t2)
290  i1 = find_buf_index(t1,loaded_fields(index2)%ibuf)
291  i2 = find_buf_index(t2,loaded_fields(index2)%ibuf)
292 
293  if(i1<0.or.i2<0) &
294  call mpp_error(fatal,'time_interp_external : records were not loaded correctly in memory')
295  time_data = real(loaded_fields(index2)%domain_data(1,1,1,i1), fms_ti_kind_)*w1 &
296  + real(loaded_fields(index2)%domain_data(1,1,1,i2), fms_ti_kind_)*w2
297  if (verb) then
298  write(outunit,*) 'ibuf= ',loaded_fields(index2)%ibuf
299  write(outunit,*) 'i1,i2= ',i1, i2
300  endif
301 
302  end subroutine time_interp_external_bridge_0d_
303 
304 
305 ! ============================================================================
subroutine time_interp_external_bridge_3d_(index1, index2, 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_bridge_0d_(index1, index2, time, time_data, verbose)
subroutine time_interp_external_bridge_2d_(index1, index2, 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_bridge