SOCA
soca_vertconv_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2017-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 !> variable transform: vertical convolution
8 
9 use fckit_configuration_module, only: fckit_configuration
10 use kinds, only: kind_real
11 use tools_func, only: fit_func
12 use type_mpl, only: mpl_type
13 use type_probe, only: probe
14 
15 ! soca modules
16 use soca_fields_mod, only: soca_field
17 use soca_geom_mod, only: soca_geom
19 use soca_state_mod, only: soca_state
20 
21 implicit none
22 private
23 
24 !> Variable transform for vertical convolution
25 !!
26 !! \note this only operates on tocn and socn
27 type, public :: soca_vertconv
28  real(kind=kind_real) :: lz_min !> Vertical decorrelation minimum [m]
29  real(kind=kind_real) :: lz_mld !> if /= 0, Use MLD to calculate Lz
30  real(kind=kind_real) :: lz_mld_max !> if calculating Lz from MLD, max value to use
31  real(kind=kind_real) :: scale_layer_thick !> Set the minimum decorrelation scale
32  !> as a multiple of the layer thickness
33  type(soca_state), pointer :: bkg !> Background
34  type(soca_geom), pointer :: geom !> Geometry
35  integer :: isc, iec, jsc, jec !> Compute domain
36 
37 contains
38  !> \copybrief soca_conv_setup \see soca_conv_setup
39  procedure :: setup => soca_conv_setup
40 
41  !> \copybrief soca_conv_mult \see soca_conv_mult
42  procedure :: mult => soca_conv_mult
43 
44  !> \copybrief soca_conv_mult_ad \see soca_conv_mult_ad
45  procedure :: mult_ad => soca_conv_mult_ad
46 
47 end type soca_vertconv
48 
49 
50 ! ------------------------------------------------------------------------------
51 contains
52 ! ------------------------------------------------------------------------------
53 
54 ! ------------------------------------------------------------------------------
55 !> Setup for the vertical convolution
56 !!
57 !! \todo: Investigate computing and storing weights in vertconc data structure
58 !! \relates soca_vertconv_mod::soca_vertconv
59 subroutine soca_conv_setup (self, bkg, geom, f_conf)
60  class(soca_vertconv), intent(inout) :: self
61  type(soca_state), target, intent(in) :: bkg !< T/S background
62  type(fckit_configuration), intent(in) :: f_conf !< yaml configuration
63  type(soca_geom), target, intent(in) :: geom !< input geometry
64 
65  ! Get configuration for vertical convolution
66  call f_conf%get_or_die("Lz_min", self%lz_min )
67  call f_conf%get_or_die("Lz_mld", self%lz_mld )
68  if ( self%lz_mld /= 0) &
69  call f_conf%get_or_die("Lz_mld_max", self%lz_mld_max )
70  call f_conf%get_or_die("scale_layer_thick", self%scale_layer_thick )
71 
72  ! Associate background and geometry
73  self%bkg => bkg
74  self%geom => geom
75 
76  ! Indices for compute domain (no halo)
77  self%isc=geom%isc; self%iec=geom%iec
78  self%jsc=geom%jsc; self%jec=geom%jec
79 
80 end subroutine soca_conv_setup
81 
82 
83 ! ------------------------------------------------------------------------------
84 !> Calculate vertical correlation lengths for a given column
85 !!
86 !! \relates soca_vertconv_mod::soca_vertconv
87 subroutine soca_calc_lz(self, i, j, lz)
88  class(soca_vertconv), intent(in) :: self
89  integer, intent(in) :: i !< i index of grid point
90  integer, intent(in) :: j !< j index of grid point
91  real(kind=kind_real), intent(inout) :: lz(:) !< output correlation legnths
92 
93  real(kind=kind_real) :: mld, z
94  integer :: k
95  type(soca_field), pointer :: hocn, mld_fld, layer_depth
96 
97  ! minium scale is based on layer thickness
98  call self%bkg%get("hocn", hocn)
99  call self%bkg%get("mld", mld_fld)
100  call self%bkg%get("layer_depth", layer_depth)
101  lz = self%lz_min
102  lz = max(lz, self%scale_layer_thick*abs(hocn%val(i,j,:)))
103 
104  ! if the upper Lz should be calculated from the MLD
105  ! interpolate values from top to bottom of ML
106  if ( self%lz_mld /= 0 ) then
107  mld = mld_fld%val(i,j, 1)
108  mld = min( mld, self%lz_mld_max)
109  mld = max( mld, self%lz_min)
110  do k=1, size(lz)
111  z = layer_depth%val(i,j, k)
112  if (z >= mld) exit ! end of ML, exit loop
113  lz(k) = max(lz(k), lz(k) + (mld - lz(k)) * (1.0 - z/mld))
114  end do
115  end if
116 
117 end subroutine soca_calc_lz
118 
119 
120 ! ------------------------------------------------------------------------------
121 !> Apply forward convolution
122 !!
123 !! \relates soca_vertconv_mod::soca_vertconv
124 subroutine soca_conv_mult (self, convdx, dx)
125  class(soca_vertconv), intent(inout) :: self
126  type(soca_increment), intent(in) :: dx !< input increment to convolve
127  type(soca_increment),intent(inout) :: convdx !< output increment
128 
129  real(kind=kind_real), allocatable :: z(:), lz(:)
130  real(kind=kind_real) :: dist2, coef
131  integer :: nl, j, k, id, jd, n
132  type(mpl_type) :: mpl
133 
134  type(soca_field), pointer :: field_dx, field_convdx, layer_depth
135 
136  call probe%get_instance('soca')
137 
138  call self%bkg%get("layer_depth", layer_depth)
139  nl = layer_depth%nz
140 
141  allocate(z(nl), lz(nl))
142 
143  do n=1,size(dx%fields)
144  ! TODO remove these hardcoded values, use the yaml file
145  select case(dx%fields(n)%name)
146  case ("tocn", "socn")
147  call dx%get(dx%fields(n)%name, field_dx)
148  call convdx%get(dx%fields(n)%name, field_convdx)
149  do id = self%isc, self%iec
150  do jd = self%jsc, self%jec
151  ! skip land
152  if (self%geom%mask2d(id,jd) /= 1) cycle
153 
154  ! get correlation lengths
155  call soca_calc_lz(self, id, jd, lz)
156 
157  ! perform convolution
158  z(:) = layer_depth%val(id,jd,:)
159  do j = 1, nl
160  field_convdx%val(id,jd,j) = 0.0d0
161  do k = 1,nl
162  dist2 = abs(z(j)-z(k))
163  coef = fit_func(mpl, dist2/lz(k))
164  field_convdx%val(id,jd,j) = field_convdx%val(id,jd,j) &
165  &+ field_dx%val(id,jd,k)*coef
166  end do
167  end do
168  end do
169  end do
170  end select
171  end do
172  deallocate(z, lz)
173 end subroutine soca_conv_mult
174 
175 
176 ! ------------------------------------------------------------------------------
177 !> Apply backward convolution
178 !!
179 !! \relates soca_vertconv_mod::soca_vertconv
180 subroutine soca_conv_mult_ad (self, convdx, dx)
181  class(soca_vertconv), intent(inout) :: self
182  type(soca_increment),intent(inout) :: dx !< output increment
183  type(soca_increment), intent(in) :: convdx !< input increment
184 
185  real(kind=kind_real), allocatable :: z(:), lz(:)
186  real(kind=kind_real) :: dist2, coef
187  integer :: nl, j, k, id, jd, n
188  type(mpl_type) :: mpl
189  type(soca_field), pointer :: field_dx, field_convdx, layer_depth
190 
191  call probe%get_instance('soca')
192 
193  call self%bkg%get("layer_depth", layer_depth)
194  nl = layer_depth%nz
195  allocate(z(nl), lz(nl))
196 
197  do n=1,size(dx%fields)
198  select case(dx%fields(n)%name)
199  ! TODO remove these hardcoded values, use the yaml file
200  case ("tocn", "socn")
201  call dx%get(dx%fields(n)%name, field_dx)
202  call convdx%get(dx%fields(n)%name, field_convdx)
203  do id = self%isc, self%iec
204  do jd = self%jsc, self%jec
205  ! skip land
206  if (self%geom%mask2d(id,jd) /= 1) cycle
207 
208  ! get correlation lengths
209  call soca_calc_lz(self, id, jd, lz)
210 
211  ! perform convolution
212  z(:) = layer_depth%val(id,jd,:)
213  field_dx%val(id,jd,:) = 0.0d0
214  do j = nl, 1, -1
215  do k = nl, 1, -1
216  dist2 = abs(z(j)-z(k))
217  coef = fit_func(mpl, dist2/lz(k))
218  field_dx%val(id,jd,k) = field_dx%val(id,jd,k) + coef*field_convdx%val(id,jd,j)
219  end do
220  end do
221  end do
222  end do
223  end select
224  end do
225  deallocate(z, lz)
226 
227 end subroutine soca_conv_mult_ad
228 
229 end module soca_vertconv_mod
Handle fields for the model.
Geometry module.
Increment fields.
State fields.
variable transform: vertical convolution
Holds all data and metadata related to a single field variable.
Geometry data structure.
Variable transform for vertical convolution.