SOCA
soca_convert_state_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2020-2021 UCAR.
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 ! ------------------------------------------------------------------------------
6 
7 !> state conversion
9 
10 use fckit_exception_module, only: fckit_exception
11 use kinds, only: kind_real
12 
13 ! mom6 / fms modules
14 use fms_io_mod, only: read_data, fms_io_init, fms_io_exit
15 use horiz_interp_mod, only : horiz_interp_new, horiz_interp, horiz_interp_type
16 use mom_domains, only : pass_var, root_pe, sum_across_pes
17 use mom_error_handler, only : is_root_pe
18 use mom_grid, only : ocean_grid_type
19 use mom_horizontal_regridding, only : meshgrid, fill_miss_2d
20 use mom_remapping, only : remapping_cs, initialize_remapping, remapping_core_h
21 use mpp_domains_mod, only : mpp_global_field, mpp_update_domains
22 use mpp_mod, only : mpp_broadcast, mpp_sync, mpp_sync_self
23 
24 ! soca modules
25 use soca_fields_mod, only: soca_field
26 use soca_geom_mod, only: soca_geom
27 
28 implicit none
29 private
30 
31 
32 !> resolution change for fields
33 type, public :: soca_convertstate_type
34  real(kind=kind_real), allocatable, dimension(:,:,:), private :: hocn_src, hocn_des
35 
36 contains
37  !> \copybrief soca_convertstate_setup \see soca_convertstate_setup
38  procedure :: setup => soca_convertstate_setup
39 
40  !> \copybrief soca_convertstate_change_resol \see soca_convertstate_change_resol
41  procedure :: change_resol => soca_convertstate_change_resol
42 
43  !> \copybrief soca_convertstate_change_resol2d \see soca_convertstate_change_resol2d
44  procedure :: change_resol2d => soca_convertstate_change_resol2d
45 
46  !> \copybrief soca_convertstate_delete \see soca_convertstate_delete
47  procedure :: clean => soca_convertstate_delete
49 
50 
51 ! ------------------------------------------------------------------------------
52 contains
53 ! ------------------------------------------------------------------------------
54 
55 
56 ! ------------------------------------------------------------------------------
57 !> initialize convertstate
58 !!
59 !! \relates soca_convert_state_mod::soca_convertstate_type
60 subroutine soca_convertstate_setup(self, src, des, hocn, hocn2)
61  class(soca_convertstate_type), intent(inout) :: self
62  type(soca_geom), intent(inout) :: src !< source geometry
63  type(soca_geom), intent(inout) :: des !< destination geometry
64  type(soca_field), intent(inout) :: hocn !< cell thickenss of source
65  type(soca_field), intent(inout) :: hocn2 !< cell thickness of destination
66 
67  !local
68  integer :: tmp(1)
69 
70  call fms_io_init()
71 
72  call read_data(trim(src%geom_grid_file), 'nzo_zstar', tmp(1), domain=src%Domain%mpp_domain)
73  src%nzo_zstar = tmp(1)
74 
75  call read_data(trim(des%geom_grid_file), 'nzo_zstar', tmp(1), domain=des%Domain%mpp_domain)
76  des%nzo_zstar = tmp(1)
77 
78  if (des%nzo_zstar /= src%nzo_zstar) call fckit_exception%abort(&
79  "target nzo_zstar /= source nzo_zstar! Reset maximum depth in target grid MOM_input file and re-run soca gridgen")
80 
81 
82  if (allocated(src%h_zstar)) deallocate(src%h_zstar)
83  allocate(src%h_zstar(src%isd:src%ied,src%jsd:src%jed,1:src%nzo_zstar))
84  call read_data(trim(src%geom_grid_file), 'h_zstar', src%h_zstar, domain=src%Domain%mpp_domain)
85 
86  if (allocated(des%h_zstar)) deallocate(des%h_zstar)
87  allocate(des%h_zstar(des%isd:des%ied,des%jsd:des%jed,1:des%nzo_zstar))
88  call read_data(trim(des%geom_grid_file), 'h_zstar', des%h_zstar, domain=des%Domain%mpp_domain)
89 
90  call fms_io_exit()
91 
92  allocate(self%hocn_src(src%isd:src%ied,src%jsd:src%jed,1:src%nzo))
93  allocate(self%hocn_des(des%isd:des%ied,des%jsd:des%jed,1:des%nzo))
94 
95  ! set hocn for target grid
96  hocn2%val = des%h
97  self%hocn_src = hocn%val
98  self%hocn_des = hocn2%val
99 
100 end subroutine soca_convertstate_setup
101 
102 
103 ! ------------------------------------------------------------------------------
104 !> destructor
105 !!
106 !! \relates soca_convert_state_mod::soca_convertstate_type
107 subroutine soca_convertstate_delete(self)
108  class(soca_convertstate_type), intent(inout) :: self
109 
110  deallocate(self%hocn_src)
111  deallocate(self%hocn_des)
112 
113 end subroutine soca_convertstate_delete
114 
115 
116 ! ------------------------------------------------------------------------------
117 !> I don't know, someone needs to document this
118 !!
119 !! \relates soca_convert_state_mod::soca_convertstate_type
120 subroutine soca_convertstate_change_resol2d(self, field_src, field_des, geom_src, geom_des)
121  class(soca_convertstate_type), intent(inout) :: self
122  type(soca_field), pointer, intent(inout) :: field_src !< source field
123  type(soca_field), pointer, intent(inout) :: field_des !< destination field
124  type(soca_geom), intent(inout) :: geom_src !< source geometry
125  type(soca_geom), intent(inout) :: geom_des !< destination geometry
126 
127  !local
128  integer :: i, j, k, tmp_nz, nz_
129  integer :: isc1, iec1, jsc1, jec1, isd1, ied1, jsd1, jed1, isg, ieg, jsg, jeg
130  integer :: isc2, iec2, jsc2, jec2, isd2, ied2, jsd2, jed2
131  type(remapping_cs) :: remapCS2
132  type(horiz_interp_type) :: Interp
133  real(kind=kind_real) :: missing = 0.d0
134  real(kind=kind_real) :: z_tot
135  real(kind=kind_real), dimension(geom_src%isg:geom_src%ieg) :: lon_in
136  real(kind=kind_real), dimension(geom_src%jsg:geom_src%jeg) :: lat_in
137  real(kind=kind_real), dimension(geom_des%isd:geom_des%ied,geom_des%jsd:geom_des%jed) :: lon_out, lat_out
138  real(kind=kind_real), dimension(geom_des%isd:geom_des%ied,geom_des%jsd:geom_des%jed) :: mask_
139  real(kind=kind_real), allocatable :: tmp(:,:,:), tmp2(:,:,:), gdata(:,:,:)
140 
141  ! Indices for compute, data, and global domain for source
142  isc1 = geom_src%isc ; iec1 = geom_src%iec ; jsc1 = geom_src%jsc ; jec1 = geom_src%jec
143  isd1 = geom_src%isd ; ied1 = geom_src%ied ; jsd1 = geom_src%jsd ; jed1 = geom_src%jed
144  isg = geom_src%isg ; ieg = geom_src%ieg ; jsg = geom_src%jsg ; jeg = geom_src%jeg
145 
146  ! Indices for compute and data domain for des
147  isc2 = geom_des%isc ; iec2 = geom_des%iec ; jsc2 = geom_des%jsc ; jec2 = geom_des%jec
148  isd2 = geom_des%isd ; ied2 = geom_des%ied ; jsd2 = geom_des%jsd ; jed2 = geom_des%jed
149 
150  lon_in = geom_src%lonh ; lat_in = geom_src%lath
151  if (field_src%name == "uocn" .and. field_des%name == "uocn") lon_in = geom_src%lonq
152  if (field_src%name == "vocn" .and. field_des%name == "vocn") lat_in = geom_src%latq
153 
154  ! Initialize work arrays
155  nz_ = field_src%nz
156  allocate(tmp(isd1:ied1,jsd1:jed1,1:nz_),gdata(isg:ieg,jsg:jeg,1:nz_),tmp2(isd2:ied2,jsd2:jed2,1:nz_))
157  tmp = 0.d0 ; gdata = 0.d0 ; tmp2 = 0.d0;
158  tmp(:,:,1:nz_) = field_src%val(:,:,1:nz_)
159 
160  ! Reconstruct global input field
161  call mpp_update_domains(tmp, geom_src%Domain%mpp_domain)
162  mask_ = field_des%mask
163  call mpp_global_field (geom_src%Domain%mpp_domain, tmp(:,:,1:nz_), gdata(:,:,1:nz_) )
164 
165  ! Interpolate to destination geometry
166  call soca_hinterp(geom_des,field_des%val,gdata,mask_(:,:),nz_,missing,lon_in,lat_in,field_des%lon,field_des%lat)
167 
168  ! Update halos
169  call mpp_update_domains(field_des%val, geom_des%Domain%mpp_domain)
170 
171 end subroutine soca_convertstate_change_resol2d
172 
173 
174 ! ------------------------------------------------------------------------------
175 !> Someone needs to document this
176 !!
177 !! \relates soca_convert_state_mod::soca_convertstate_type
178 subroutine soca_convertstate_change_resol(self, field_src, field_des, geom_src, geom_des)
179  class(soca_convertstate_type), intent(inout) :: self
180  type(soca_field), pointer, intent(inout) :: field_src !< source field
181  type(soca_field), pointer, intent(inout) :: field_des !< destination field
182  type(soca_geom), intent(inout) :: geom_src !< source geometry
183  type(soca_geom), intent(inout) :: geom_des !< destination geometry
184 
185  !local
186  integer :: i, j, k, tmp_nz, nz_
187  integer :: isc1, iec1, jsc1, jec1, isd1, ied1, jsd1, jed1, isg, ieg, jsg, jeg
188  integer :: isc2, iec2, jsc2, jec2, isd2, ied2, jsd2, jed2
189  type(remapping_cs) :: remapCS2
190  type(horiz_interp_type) :: Interp
191  real(kind=kind_real) :: missing = 0.d0
192  real(kind=kind_real) :: pi_180, z_tot
193  real(kind=kind_real), dimension(geom_src%isg:geom_src%ieg) :: lon_in
194  real(kind=kind_real), dimension(geom_src%jsg:geom_src%jeg) :: lat_in
195  real(kind=kind_real), dimension(geom_des%isd:geom_des%ied,geom_des%jsd:geom_des%jed) :: lon_out, lat_out
196  real(kind=kind_real), dimension(geom_des%isd:geom_des%ied,geom_des%jsd:geom_des%jed) :: mask_
197  real(kind=kind_real), allocatable :: tmp(:,:,:), tmp2(:,:,:), gdata(:,:,:)
198  real(kind=kind_real), allocatable :: h1(:), h2(:)
199  real(kind=kind_real), dimension(geom_src%isd:geom_src%ied,geom_src%jsd:geom_src%jed,1:geom_src%nzo_zstar) :: h_new1
200  real(kind=kind_real), dimension(geom_des%isd:geom_des%ied,geom_des%jsd:geom_des%jed,1:geom_des%nzo_zstar) :: h_new2
201 
202  pi_180=atan(1.0d0)/45.0d0
203 
204  ! Indices for compute, data, and global domain for source
205  isc1 = geom_src%isc ; iec1 = geom_src%iec ; jsc1 = geom_src%jsc ; jec1 = geom_src%jec
206  isd1 = geom_src%isd ; ied1 = geom_src%ied ; jsd1 = geom_src%jsd ; jed1 = geom_src%jed
207  isg = geom_src%isg ; ieg = geom_src%ieg ; jsg = geom_src%jsg ; jeg = geom_src%jeg
208 
209  ! Indices for compute and data domain for des
210  isc2 = geom_des%isc ; iec2 = geom_des%iec ; jsc2 = geom_des%jsc ; jec2 = geom_des%jec
211  isd2 = geom_des%isd ; ied2 = geom_des%ied ; jsd2 = geom_des%jsd ; jed2 = geom_des%jed
212 
213  ! Initialize vertical remapping
214  call initialize_remapping(remapcs2,'PPM_IH4')
215 
216  ! Set grid thickness based on zstar level for src & target grid
217  if (field_des%metadata%io_file=="ocn".or.field_des%metadata%io_file=='ice') then
218  mask_ = field_des%mask
219  h_new1(isc1:iec1,jsc1:jec1,1:geom_src%nzo_zstar) = geom_src%h_zstar(isc1:iec1,jsc1:jec1,1:geom_src%nzo_zstar)
220  h_new2(isc2:iec2,jsc2:jec2,1:geom_des%nzo_zstar) = geom_des%h_zstar(isc2:iec2,jsc2:jec2,1:geom_des%nzo_zstar)
221  call mpp_update_domains(mask_, geom_des%Domain%mpp_domain)
222  call mpp_update_domains(h_new1, geom_src%Domain%mpp_domain)
223  call mpp_update_domains(h_new2, geom_des%Domain%mpp_domain)
224  else
225  mask_ = 1.d0
226  end if
227 
228  ! target hocn has been set in setup
229  if (field_des%name == "hocn" ) then
230  return
231  end if
232  lon_in = geom_src%lonh ; lat_in = geom_src%lath
233  if (field_src%name == "uocn" .and. field_des%name == "uocn") lon_in = geom_src%lonq
234  if (field_src%name == "vocn" .and. field_des%name == "vocn") lat_in = geom_src%latq
235 ! call meshgrid(geom_des%lonh(isd2:ied2),geom_des%lath(jsd2:jed2),lon_out,lat_out)
236 ! if (field_des%name == "uocn") call meshgrid(geom_des%lonq(isd2:ied2),geom_des%lath(jsd2:jed2),lon_out,lat_out)
237 ! if (field_des%name == "vocn") call meshgrid(geom_des%lonh(isd2:ied2),geom_des%latq(jsd2:jed2),lon_out,lat_out)
238 
239  ! Converts src grid to zstar coordinate
240  nz_ = geom_src%nzo_zstar
241  if (field_src%nz == 1 .or. field_src%metadata%io_file=="ice") nz_ = field_src%nz
242  allocate(tmp(isd1:ied1,jsd1:jed1,1:nz_),gdata(isg:ieg,jsg:jeg,1:nz_),tmp2(isd2:ied2,jsd2:jed2,1:nz_))
243  allocate(h1(field_src%nz),h2(nz_))
244  tmp = 0.d0 ; gdata = 0.d0 ; tmp2 = 0.d0;
245  if ( field_src%nz > 1 .and. field_src%metadata%io_file/="ice") then
246  do j = jsc1, jec1
247  do i = isc1, iec1
248  tmp_nz = field_src%nz
249  if(field_src%name =="uocn") then
250  if (field_src%mask(i,j)>0.) then
251  h1(1:tmp_nz) = 0.5 * ( self%hocn_src(i,j,1:tmp_nz) + self%hocn_src(i+1,j,1:tmp_nz) )
252  h2(1:nz_) = 0.5 * ( h_new1(i,j,1:nz_) + h_new1(i+1,j,1:nz_) )
253  call remapping_core_h(remapcs2, tmp_nz, h1(1:tmp_nz), field_src%val(i,j,1:tmp_nz), &
254  nz_, h2(1:nz_), tmp(i,j,1:nz_))
255  endif
256  else if(field_src%name =="vocn") then
257  if (field_src%mask(i,j)>0.) then
258  h1(1:tmp_nz) = 0.5 * ( self%hocn_src(i,j,1:tmp_nz) + self%hocn_src(i,j+1,1:tmp_nz) )
259  h2(1:nz_) = 0.5 * ( h_new1(i,j,1:nz_) + h_new1(i,j+1,1:nz_) )
260  call remapping_core_h(remapcs2, tmp_nz, h1(1:tmp_nz), field_src%val(i,j,1:tmp_nz), &
261  nz_, h2(1:nz_), tmp(i,j,1:nz_))
262  endif
263  else
264  if (field_src%mask(i,j) > 0.d0) then
265  call remapping_core_h(remapcs2, tmp_nz, self%hocn_src(i,j,1:tmp_nz), field_src%val(i,j,1:tmp_nz), &
266  nz_, h_new1(i,j,1:nz_), tmp(i,j,1:nz_))
267  endif
268  end if
269  end do !i
270  end do !j
271  else
272  if (field_src%metadata%io_file=="ocn") tmp(:,:,1) = field_src%val(:,:,1) !*field_src%mask(:,:) !2D
273  if (field_src%metadata%io_file=="sfc") tmp(:,:,1) = field_src%val(:,:,1) !2D no mask
274  if (field_src%metadata%io_file=="ice") tmp(:,:,1:nz_) = field_src%val(:,:,1:nz_)
275  end if ! field_src%nz > 1
276  call mpp_update_domains(tmp, geom_src%Domain%mpp_domain)
277 
278  ! Convert src field to target field at zstar coord
279  call mpp_global_field (geom_src%Domain%mpp_domain, tmp(:,:,1:nz_), gdata(:,:,1:nz_) )
280  call soca_hinterp(geom_des,tmp2(:,:,1:nz_),gdata,mask_(:,:),nz_,missing,lon_in,lat_in,field_des%lon,field_des%lat)
281 
282  call mpp_update_domains(tmp2, geom_des%Domain%mpp_domain)
283 
284  ! Final step: vertical remapping to desired vertical coordinate
285  if(allocated(h1)) deallocate(h1)
286  if(allocated(h2)) deallocate(h2)
287  allocate(h1(nz_),h2(field_des%nz))
288  if ( field_des%nz > 1 .and. field_des%metadata%io_file/="ice") then
289  do j = jsc2, jec2
290  do i = isc2, iec2
291  tmp_nz = nz_ !assume geom_src%nzo_zstar == geom%des%nzo_zstar
292  if(field_des%name =="uocn") then
293  if (field_des%mask(i,j)>0.) then
294  h1(1:tmp_nz) = 0.5 * ( h_new2(i,j,1:tmp_nz) + h_new2(i+1,j,1:tmp_nz) )
295  h2(1:field_des%nz) = 0.5 * ( self%hocn_des(i,j,1:field_des%nz) + self%hocn_des(i+1,j,1:field_des%nz) )
296  call remapping_core_h(remapcs2, tmp_nz, h1(1:tmp_nz), tmp2(i,j,1:tmp_nz), &
297  field_des%nz, h2(1:field_des%nz), field_des%val(i,j,1:field_des%nz))
298  end if
299  else if (field_des%name =="vocn") then
300  if (field_des%mask(i,j)>0.) then
301  h1(1:tmp_nz) = 0.5 * ( h_new2(i,j,1:tmp_nz) + h_new2(i,j+1,1:tmp_nz) )
302  h2(1:field_des%nz) = 0.5 * ( self%hocn_des(i,j,1:field_des%nz) + self%hocn_des(i,j+1,1:field_des%nz) )
303  call remapping_core_h(remapcs2, tmp_nz, h1(1:tmp_nz), tmp2(i,j,1:tmp_nz), &
304  field_des%nz, h2(1:field_des%nz), field_des%val(i,j,1:field_des%nz))
305  end if
306  else
307  if (field_des%mask(i,j)>0.) then
308  call remapping_core_h(remapcs2, tmp_nz, h_new2(i,j,1:tmp_nz), tmp2(i,j,1:tmp_nz), &
309  field_des%nz, self%hocn_des(i,j,1:field_des%nz), field_des%val(i,j,1:field_des%nz))
310  end if
311  end if
312  end do !j
313  end do !i
314  else
315  if (field_des%metadata%io_file=="ocn") field_des%val(:,:,1) = tmp2(:,:,1)*field_des%mask(:,:) ! 2D
316  if (field_des%metadata%io_file=="sfc") field_des%val(:,:,1) = tmp2(:,:,1) ! 2D no mask
317  if (field_des%metadata%io_file=="ice") field_des%val(:,:,1:field_des%nz) = tmp2(:,:,1:field_des%nz)
318  end if ! nz > 1
319 
320  call mpp_update_domains(field_des%val, geom_des%Domain%mpp_domain)
321 
322 end subroutine soca_convertstate_change_resol
323 
324 
325 ! ------------------------------------------------------------------------------
326 !> someone needs to document this, there's a lot going on
327 !!
328 !! \relates soca_convertstate_mod::soca_convertstate
329 subroutine soca_hinterp(self,field2,gdata,mask2,nz,missing,lon_in,lat_in,lon_out,lat_out)
330  class(soca_geom), intent(inout) :: self
331  real(kind=kind_real), dimension(self%isd:self%ied,self%jsd:self%jed,1:nz), intent(inout) :: field2
332  real(kind=kind_real), dimension(:,:,:), intent(in) :: gdata
333  real(kind=kind_real), dimension(self%isd:self%ied,self%jsd:self%jed), intent(in) :: mask2
334  integer, intent(in) :: nz
335  real(kind=kind_real), intent(in) :: missing
336  real(kind=kind_real), dimension(:), intent(in) :: lon_in, lat_in
337  real(kind=kind_real), dimension(self%isd:self%ied,self%jsd:self%jed), intent(in) :: lon_out, lat_out
338 
339  !local variables
340  integer :: i, j, k, isg, ieg, jsg, jeg, jeg1
341  integer :: isc2, iec2, jsc2, jec2, npoints
342  real(kind=kind_real) :: roundoff = 1.e-5
343  real(kind=kind_real) :: pi_180
344  type(horiz_interp_type) :: interp
345  type(ocean_grid_type) :: grid
346  real(kind_real), dimension(:), allocatable :: lath_inp
347  real(kind_real), dimension(:,:), allocatable :: lon_inp, lat_inp, tr_inp, mask_in_
348  real(kind_real), dimension(self%isd:self%ied,self%jsd:self%jed) :: tr_out, fill, good, prev, mask_out_
349  real(kind=kind_real) :: max_lat,min_lat, pole, npole, varavg
350  real(kind=kind_real), dimension(:), allocatable :: last_row, lonh, lath
351  logical :: add_np, add_sp
352 
353  pi_180=atan(1.0d0)/45.0d0
354 
355  isg = 1; jsg = 1;
356  ieg = size(gdata,1); jeg = size(gdata,2)
357 
358  ! Indices for compute domain for regional model
359  isc2 = self%isc ; iec2 = self%iec ; jsc2 = self%jsc ; jec2 = self%jec
360 
361  grid%isc = self%isc ; grid%iec = self%iec ; grid%jsc = self%jsc ; grid%jec = self%jec
362  grid%isd = self%isd ; grid%ied = self%ied ; grid%jsd = self%jsd ; grid%jed = self%jed
363  grid%Domain => self%Domain
364 
365  jeg1=jeg
366  max_lat = maxval(lat_in)
367  add_np=.false.
368  if (max_lat < 90.0) then
369  add_np=.true.
370  jeg1=jeg1+1
371  allocate(lath(jsg:jeg1))
372  lath(jsg:jeg)=lat_in(:)
373  lath(jeg1)=90.d0
374  else
375  allocate(lath(jsg:jeg1))
376  lath(:) = lat_in
377  endif
378  min_lat = minval(lat_in)
379  add_sp=.false.
380  if (min_lat > -90.0) then
381  add_sp=.true.
382  jeg1=jeg1+1
383  if (allocated(lath_inp)) deallocate(lath_inp)
384  allocate(lath_inp(jeg1))
385  lath_inp(jsg+1:jeg1)=lath(:)
386  lath_inp(jsg)=-90.d0
387  if (allocated (lath)) deallocate(lath)
388  allocate(lath(jsg:jeg1))
389  lath(:)=lath_inp(:)
390  endif
391 
392  allocate(lonh(isg:ieg))
393  lonh(:) = lon_in(:)
394 
395  allocate(lon_inp(isg:ieg,jsg:jeg1))
396  allocate(lat_inp(isg:ieg,jsg:jeg1))
397  call meshgrid(lonh,lath,lon_inp,lat_inp)
398 
399  allocate(mask_in_(isg:ieg,jsg:jeg1))
400  allocate(tr_inp(isg:ieg,jsg:jeg1)) ; allocate(last_row(isg:ieg))
401  do k = 1, nz
402  ! extrapolate the input data to the north pole using the northerm-most latitude
403  if (is_root_pe()) then
404  if (add_np) then
405  last_row(:)=gdata(:,jeg,k); pole=0.d0; npole=0.d0
406  do i=isg,ieg
407  if (abs(gdata(i,jeg,k)-missing) > abs(roundoff)) then
408  pole = pole+last_row(i)
409  npole = npole+1.d0
410  endif
411  enddo
412  if (npole > 0) then
413  pole=pole/npole
414  else
415  pole=missing
416  endif
417 
418  if (add_sp) then
419  tr_inp(:,jsg) = gdata(:,jsg,k)
420  tr_inp(:,jsg+1:jeg1-1) = gdata(:,:,k)
421  tr_inp(:,jeg1) = pole
422  else
423  tr_inp(:,jsg:jeg) = gdata(:,:,k)
424  tr_inp(:,jeg1) = pole
425  endif !add_sp
426 
427  else
428  if (add_sp) then
429  tr_inp(:,jsg) = gdata(:,jsg,k)
430  tr_inp(:,jsg+1:jeg1) = gdata(:,:,k)
431  else
432  tr_inp(isg:ieg,jsg:jeg) = gdata(isg:ieg,jsg:jeg,k)
433  endif !add_sp
434  endif !add_np
435  end if !root_pe
436 
437  call mpp_sync()
438  call mpp_broadcast(tr_inp, ieg*jeg1, root_pe())
439  call mpp_sync_self()
440 
441  mask_in_ = 1.d0
442  do j=jsg,jeg1 ; do i=isg,ieg
443  if (abs(tr_inp(i,j)-missing) <= abs(roundoff)) then
444  tr_inp(i,j) = missing
445  mask_in_(i,j) = 0.d0;
446  end if
447  enddo ; enddo
448 
449  tr_out(:,:) = 0.d0
450  ! initialize horizontal remapping
451  if (k==1) call horiz_interp_new(interp, lon_inp(:,:)*pi_180, lat_inp(:,:)*pi_180, lon_out(isc2:iec2,jsc2:jec2)*pi_180, &
452  lat_out(isc2:iec2,jsc2:jec2)*pi_180, interp_method='bilinear', src_modulo=.true., mask_in=mask_in_)
453 
454  call horiz_interp(interp, tr_inp, tr_out(isc2:iec2,jsc2:jec2), mask_in=mask_in_, missing_value=missing, missing_permit=3)
455 
456  mask_out_ = 1.d0 ; fill = 0.d0 ; good = 0.d0
457  npoints = 0 ; varavg = 0.d0
458  do j=jsc2,jec2
459  do i=isc2,iec2
460  if (abs(tr_out(i,j)-missing) < abs(roundoff)) mask_out_(i,j)=0.d0
461  if (mask_out_(i,j) < 1.0d0) then
462  tr_out(i,j) = missing
463  else
464  good(i,j) = 1.0d0
465  npoints = npoints + 1
466  varavg = varavg + tr_out(i,j)
467  endif
468  if (mask2(i,j) == 1.d0 .and. mask_out_(i,j) < 1.0d0) fill(i,j) = 1.d0
469  end do !i
470  end do !j
471  call pass_var(fill, self%Domain) ; call pass_var(good, self%Domain)
472  call sum_across_pes(npoints) ; call sum_across_pes(varavg)
473  if (npoints > 0) then
474  varavg = varavg/real(npoints)
475  end if
476 
477  if (k==1) prev(:,:) = tr_out(:,:)
478  call fill_miss_2d(tr_out, good, fill, prev=prev, g=grid, smooth=.true.)
479 
480  !TODO: In case fill_miss_2d failed at surface (k=1), use IDW to fill data pt that is located in ocean mask
481  !Problem: IDW is compiler-dependent
482 
483  field2(:,:,k) = tr_out(:,:)*mask2(:,:)
484  prev(:,:) = field2(:,:,k)
485 
486  end do
487 
488 end subroutine soca_hinterp
489 
490 end module soca_convert_state_mod
Handle fields for the model.
Geometry module.
Holds all data and metadata related to a single field variable.
Geometry data structure.