9 use atlas_module,
only: atlas_geometry
10 use fckit_configuration_module,
only: fckit_configuration
13 use mpp_domains_mod,
only : mpp_update_domains, mpp_update_domains_ad
14 use oops_variables_mod,
only: oops_variables
27 type(oops_variables) :: vars
28 real(kind=kind_real),
allocatable :: wgh(:,:,:,:)
29 real(kind=kind_real) :: scale_flow
30 real(kind=kind_real) :: scale_dist
31 real(kind=kind_real) :: niter
34 integer :: isc, iec, jsc, jec
39 integer :: isd, ied, jsd, jed
45 procedure :: setup => soca_horizfilt_setup
48 procedure :: delete => soca_horizfilt_delete
51 procedure :: mult => soca_horizfilt_mult
54 procedure :: multad => soca_horizfilt_multad
67 subroutine soca_horizfilt_setup(self, f_conf, geom, traj, vars)
69 type(fckit_configuration),
intent(in) :: f_conf
72 type(oops_variables),
intent(in) :: vars
76 integer :: i, j, ii, jj
77 real(kind=kind_real) :: dist(-1:1,-1:1), sum_w, r_dist, r_flow
78 type(atlas_geometry) :: ageometry
84 if (.not. f_conf%get(
"scale_dist", self%scale_dist)) self%scale_dist = -1
85 if (.not. f_conf%get(
"scale_flow", self%scale_flow)) self%scale_flow = -1
86 call f_conf%get_or_die(
"niter", self%niter)
91 self%scale_dist = self%scale_dist / sqrt(self%niter)
92 self%scale_flow = self%scale_flow / sqrt(self%niter)
95 self%isd = geom%isd ; self%ied = geom%ied ; self%jsd = geom%jsd; self%jed = geom%jed
96 self%isc = geom%isc ; self%iec = geom%iec ; self%jsc = geom%jsc; self%jec = geom%jec
99 allocate(self%wgh(self%isd:self%ied,self%jsd:self%jed,-1:1,-1:1))
102 ageometry = atlas_geometry(
"Earth")
105 self%wgh = 0.0_kind_real
108 do j = self%jsc, self%jec
109 do i = self%isc, self%iec
113 if(self%scale_dist > 0)
then
114 r_dist = ageometry%distance(geom%lon(i,j), geom%lat(i,j), geom%lon(i+ii,j+jj), geom%lat(i+ii,j+jj) )
115 r_dist = exp(-0.5 * (r_dist/self%scale_dist) ** 2)
119 if(self%scale_flow > 0)
then
120 call traj%get(
"ssh", ssh)
121 r_flow = abs(ssh%val(i,j,1) - ssh%val(i+ii,j+jj,1))
122 r_flow = exp(-0.5 * ((r_flow / self%scale_flow) ** 2))
126 dist(ii,jj) = geom%mask2d(i+ii,j+jj) * r_dist * r_flow
132 if (sum_w>0.0_kind_real)
then
133 self%wgh(i,j,:,:) = dist / sum_w
139 end subroutine soca_horizfilt_setup
146 subroutine soca_horizfilt_delete(self)
151 end subroutine soca_horizfilt_delete
158 subroutine soca_horizfilt_mult(self, dxin, dxout, geom)
167 real(kind=kind_real),
allocatable,
dimension(:,:) :: dxi, dxo
169 allocate(dxi(self%isd:self%ied,self%jsd:self%jed))
170 allocate(dxo(self%isd:self%ied,self%jsd:self%jed))
172 do ivar = 1, self%vars%nvars()
173 call dxin%get(trim(self%vars%variable(ivar)), field_i)
174 call dxout%get(trim(self%vars%variable(ivar)), field_o)
176 dxi = field_i%val(:,:,k)
177 call soca_filt2d(self, dxi, dxo, geom)
178 field_o%val(:,:,k) = dxo
183 end subroutine soca_horizfilt_mult
190 subroutine soca_horizfilt_multad(self, dxin, dxout, geom)
198 real(kind=kind_real),
allocatable,
dimension(:,:) :: dxi, dxo
200 allocate(dxi(self%isd:self%ied,self%jsd:self%jed))
201 allocate(dxo(self%isd:self%ied,self%jsd:self%jed))
203 do ivar = 1, self%vars%nvars()
204 call dxin%get(trim(self%vars%variable(ivar)), field_i)
205 call dxout%get(trim(self%vars%variable(ivar)), field_o)
207 dxi = field_i%val(:,:,k)
208 call soca_filt2d_ad(self, dxi, dxo, geom)
209 field_o%val(:,:,k) = dxo
214 end subroutine soca_horizfilt_multad
222 subroutine soca_filt2d(self, dxin, dxout, geom)
224 real(kind=kind_real),
allocatable,
intent(in) :: dxin(:,:)
225 real(kind=kind_real),
allocatable,
intent(inout) :: dxout(:,:)
229 real(kind=kind_real),
allocatable :: dxtmp(:,:)
232 allocate(dxtmp(self%isd:self%ied,self%jsd:self%jed))
233 dxtmp = 0.0_kind_real
234 dxtmp(self%isc:self%iec,self%jsc:self%jec) = dxin(self%isc:self%iec,self%jsc:self%jec)
237 call mpp_update_domains(dxtmp, geom%Domain%mpp_domain, complete=.true.)
240 dxout = 0.0_kind_real
241 do j = self%jsc, self%jec
242 do i = self%isc, self%iec
243 if (geom%mask2d(i,j)==1)
then
245 self%wgh(i,j,-1,1)*dxtmp(i-1,j+1) + &
246 self%wgh(i,j,0,1)*dxtmp(i,j+1) + &
247 self%wgh(i,j,1,1)*dxtmp(i+1,j+1) + &
248 self%wgh(i,j,-1,0)*dxtmp(i-1,j) + &
249 self%wgh(i,j,0,0)*dxtmp(i,j) + &
250 self%wgh(i,j,1,0)*dxtmp(i+1,j) + &
251 self%wgh(i,j,-1,-1)*dxtmp(i-1,j-1) + &
252 self%wgh(i,j,0,-1)*dxtmp(i,j-1) + &
253 self%wgh(i,j,1,-1)*dxtmp(i+1,j-1)
259 call mpp_update_domains(dxout, geom%Domain%mpp_domain, complete=.true.)
263 end subroutine soca_filt2d
271 subroutine soca_filt2d_ad(self, dxin, dxout, geom)
273 real(kind=kind_real),
allocatable,
intent(in) :: dxin(:,:)
274 real(kind=kind_real),
allocatable,
intent(inout) :: dxout(:,:)
278 real(kind=kind_real),
allocatable :: dxtmp(:,:)
281 allocate(dxtmp(self%isd:self%ied,self%jsd:self%jed))
282 dxtmp = 0.0_kind_real
283 dxtmp(self%isc:self%iec,self%jsc:self%jec) = dxin(self%isc:self%iec,self%jsc:self%jec)
285 dxout = 0.0_kind_real
287 do j = self%jec, self%jsc, -1
288 do i = self%iec, self%isc, -1
289 if (geom%mask2d(i,j)==1)
then
290 dxout(i-1,j+1) = dxout(i-1,j+1) + self%wgh(i,j,-1, 1)*dxtmp(i,j)
291 dxout(i,j+1) = dxout(i,j+1) + self%wgh(i,j, 0, 1)*dxtmp(i,j)
292 dxout(i+1,j+1) = dxout(i+1,j+1) + self%wgh(i,j, 1, 1)*dxtmp(i,j)
293 dxout(i-1,j) = dxout(i-1,j) + self%wgh(i,j,-1, 0)*dxtmp(i,j)
294 dxout(i,j) = dxout(i,j) + self%wgh(i,j, 0, 0)*dxtmp(i,j)
295 dxout(i+1,j) = dxout(i+1,j) + self%wgh(i,j, 1, 0)*dxtmp(i,j)
296 dxout(i-1,j-1) = dxout(i-1,j-1) + self%wgh(i,j,-1,-1)*dxtmp(i,j)
297 dxout(i,j-1) = dxout(i,j-1) + self%wgh(i,j, 0,-1)*dxtmp(i,j)
298 dxout(i+1,j-1) = dxout(i+1,j-1) + self%wgh(i,j, 1,-1)*dxtmp(i,j)
304 call mpp_update_domains_ad(dxout, geom%Domain%mpp_domain, complete=.true.)
308 end subroutine soca_filt2d_ad
Handle fields for the model.
Holds all data and metadata related to a single field variable.
Variable transform: horizontal filtering.