SOCA
soca_bkgerrgodas_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: background error
8 
9 use fckit_configuration_module, only: fckit_configuration
10 use tools_const, only : pi
11 use kinds, only: kind_real
12 
13 ! soca modules
16 use soca_geom_mod, only: soca_geom
19 use soca_state_mod, only: soca_state
20 use soca_utils, only: soca_diff
21 
22 implicit none
23 private
24 
25 
26 !> Variable transform for background error (D), GODAS version
27 type, public :: soca_bkgerrgodas
28  type(soca_state), pointer :: bkg
29  type(soca_fields) :: std_bkgerr
30 
31  ! private members
32  type(soca_geom), pointer, private :: geom
33  type(soca_bkgerr_bounds_type) :: bounds !< Bounds for bkgerrgodas
34  real(kind=kind_real), private :: t_dz !< For rescaling of the vertical gradient
35  real(kind=kind_real), private :: t_efold !< E-folding scale for surf based T min
36  real(kind=kind_real), private :: ssh_phi_ex !< latitude scale of ssh error
37 
38 contains
39 
40  !> \copybrief soca_bkgerrgodas_setup \see soca_bkgerrgodas_setup
41  procedure :: setup => soca_bkgerrgodas_setup
42 
43  !> \copybrief soca_bkgerrgodas_mult \see soca_bkgerrgodas_mult
44  procedure :: mult => soca_bkgerrgodas_mult
45 
46 end type soca_bkgerrgodas
47 
48 
49 ! ------------------------------------------------------------------------------
50 contains
51 ! ------------------------------------------------------------------------------
52 
53 ! ------------------------------------------------------------------------------
54 !> Setup the static background error
55 !!
56 !! \relates soca_bkgerrgodas_mod::soca_bkgerrgodas
57 subroutine soca_bkgerrgodas_setup(self, f_conf, bkg, geom)
58  class(soca_bkgerrgodas), intent(inout) :: self
59  type(fckit_configuration), intent(in) :: f_conf !< configuration
60  type(soca_state), target, intent(in) :: bkg !< background state
61  type(soca_geom), target, intent(in) :: geom !< model geometry
62 
63  type(soca_field), pointer :: field, field_bkg
64  integer :: i
65  character(len=800) :: fname = 'soca_bkgerrgodas.nc'
66 
67  ! Allocate memory for bkgerrgodasor
68  call self%std_bkgerr%copy(bkg)
69  !call create_copy(self%std_bkgerr, bkg)
70 
71  ! Get bounds from configuration
72  call self%bounds%read(f_conf)
73 
74  ! get parameters not already included in self%bounds
75  call f_conf%get_or_die("t_dz", self%t_dz)
76  call f_conf%get_or_die("t_efold", self%t_efold)
77  call f_conf%get_or_die("ssh_phi_ex", self%ssh_phi_ex)
78 
79  ! Associate background and geometry
80  self%bkg => bkg
81  self%geom => geom
82 
83  ! Set all fields to zero
84  call self%std_bkgerr%zeros()
85 
86  ! Std of bkg error for T/S/SSH based on background.
87  ! S and SSH error are only for the unbalanced portion of S/SSH
88  call soca_bkgerrgodas_tocn(self)
89  call soca_bkgerrgodas_socn(self)
90  call soca_bkgerrgodas_ssh(self)
91 
92  ! Invent background error for ocnsfc, wav and ocn_bgc fields: set
93  ! it to 10% or 20% of the background for now ...
94  do i=1,size(self%std_bkgerr%fields)
95  field => self%std_bkgerr%fields(i)
96  select case(field%name)
97  case ('sw','lw','lhf','shf','us','swh')
98  call bkg%get(field%name, field_bkg)
99  field%val = abs(field_bkg%val)
100  field%val = 0.1_kind_real * field%val
101  case ('chl','biop')
102  call bkg%get(field%name, field_bkg)
103  field%val = abs(field_bkg%val) * 0.2_kind_real
104  end select
105  end do
106 
107  ! Apply config bounds to background error
108  call self%bounds%apply(self%std_bkgerr)
109 
110  ! Save
111  call self%std_bkgerr%write_file(fname)
112 
113 end subroutine soca_bkgerrgodas_setup
114 
115 
116 ! ------------------------------------------------------------------------------
117 !> Apply background error: dxm = D dxa
118 !!
119 !! \relates soca_bkgerrgodas_mod::soca_bkgerrgodas
120 subroutine soca_bkgerrgodas_mult(self, dxa, dxm)
121  class(soca_bkgerrgodas), intent(in) :: self
122  type(soca_increment), intent(in) :: dxa !< input increment
123  type(soca_increment), intent(inout) :: dxm !< output increment
124 
125  type(soca_field), pointer :: field_m, field_e, field_a
126  integer :: isc, iec, jsc, jec, i, j, n
127 
128  ! make sure fields are the right shape
129  call dxa%check_congruent(dxm)
130  call dxa%check_subset(self%std_bkgerr)
131 
132  ! Indices for compute domain (no halo)
133  isc = self%geom%isc ; iec = self%geom%iec
134  jsc = self%geom%jsc ; jec = self%geom%jec
135 
136  do n=1,size(dxa%fields)
137  field_a => dxa%fields(n)
138  call self%std_bkgerr%get(field_a%name, field_e)
139  call dxm%get(field_a%name, field_m)
140  do i = isc, iec
141  do j = jsc, jec
142  if (self%geom%mask2d(i,j).eq.1) then
143  field_m%val(i,j,:) = field_e%val(i,j,:) * field_a%val(i,j,:)
144  end if
145  end do
146  end do
147  end do
148 end subroutine soca_bkgerrgodas_mult
149 
150 
151 ! ------------------------------------------------------------------------------
152 !> Derive T background error from vertial gradient of temperature
153 !!
154 !! \relates soca_bkgerrgodas_mod::soca_bkgerrgodas
155 subroutine soca_bkgerrgodas_tocn(self)
156  class(soca_bkgerrgodas), intent(inout) :: self
157 
158  real(kind=kind_real), allocatable :: sig1(:), sig2(:)
159  type(soca_domain_indices) :: domain
160  integer :: i, j, k
161  integer :: iter, niter = 1
162  type(soca_omb_stats) :: sst
163  type(soca_field), pointer :: tocn_b, tocn_e, hocn, layer_depth
164 
165  ! Get compute domain indices
166  domain%is = self%geom%isc ; domain%ie = self%geom%iec
167  domain%js = self%geom%jsc ; domain%je = self%geom%jec
168 
169  ! Get local compute domain indices
170  domain%isl = self%geom%iscl ; domain%iel = self%geom%iecl
171  domain%jsl = self%geom%jscl ; domain%jel = self%geom%jecl
172 
173  ! Allocate temporary arrays
174  allocate(sig1(self%geom%nzo), sig2(self%geom%nzo))
175 
176  ! Initialize sst background error to previously computed std of omb's
177  ! Currently hard-coded to read GODAS file
178  call sst%init(domain)
179  call sst%bin(self%geom%lon, self%geom%lat)
180 
181  call self%bkg%get("tocn", tocn_b)
182  call self%std_bkgerr%get("tocn", tocn_e)
183  call self%bkg%get("hocn", hocn)
184  call self%bkg%get("layer_depth",layer_depth)
185 
186  ! Loop over compute domain
187  do i = domain%is, domain%ie
188  do j = domain%js, domain%je
189  if (self%geom%mask2d(i,j).eq.1) then
190 
191  ! Step 1: sigb from dT/dz
192  call soca_diff(sig1(:), tocn_b%val(i,j,:), hocn%val(i,j,:))
193  sig1(:) = self%t_dz * abs(sig1) ! Rescale background error
194 
195  ! Step 2: sigb based on efolding scale
196  sig2(:) = self%bounds%t_min + (sst%bgerr_model(i,j)-self%bounds%t_min)*&
197  &exp((layer_depth%val(i,j,1)-layer_depth%val(i,j,:))&
198  &/self%t_efold)
199 
200  ! Step 3: sigb = max(sig1, sig2)
201  do k = 1, self%geom%nzo
202  tocn_e%val(i,j,k) = min( max(sig1(k), sig2(k)), &
203  & self%bounds%t_max)
204  end do
205 
206  ! Step 4: Vertical smoothing
207  do iter = 1, niter
208  do k = 2, self%geom%nzo-1
209  tocn_e%val(i,j,k) = &
210  &( tocn_e%val(i,j,k-1)*hocn%val(i,j,k-1) +&
211  & tocn_e%val(i,j,k)*hocn%val(i,j,k) +&
212  & tocn_e%val(i,j,k+1)*hocn%val(i,j,k+1) )/&
213  & (sum(hocn%val(i,j,k-1:k+1)))
214  end do
215  end do
216 
217  end if
218  end do
219  end do
220 
221  ! Release memory
222  call sst%exit()
223  deallocate(sig1, sig2)
224 
225 end subroutine soca_bkgerrgodas_tocn
226 
227 
228 ! ------------------------------------------------------------------------------
229 !> Derive unbalanced SSH background error, based on latitude
230 !!
231 !! \relates soca_bkgerrgodas_mod::soca_bkgerrgodas
232 subroutine soca_bkgerrgodas_ssh(self)
233  class(soca_bkgerrgodas), intent(inout) :: self
234  type(soca_domain_indices), target :: domain
235  integer :: i, j
236  type(soca_field), pointer :: ssh
237 
238  ! Get compute domain indices
239  domain%is = self%geom%isc ; domain%ie = self%geom%iec
240  domain%js = self%geom%jsc ; domain%je = self%geom%jec
241 
242  call self%std_bkgerr%get("ssh", ssh)
243 
244  ! Loop over compute domain
245  do i = domain%is, domain%ie
246  do j = domain%js, domain%je
247  if (self%geom%mask2d(i,j) .ne. 1) cycle
248 
249  if ( abs(self%geom%lat(i,j)) >= self%ssh_phi_ex) then
250  ! if in extratropics, set to max value
251  ssh%val(i,j,:) = self%bounds%ssh_max
252  else
253  ! otherwise, taper to min value (0.0) toward equator
254  ssh%val(i,j,:) = self%bounds%ssh_min + 0.5 * &
255  (self%bounds%ssh_max - self%bounds%ssh_min) * &
256  (1 - cos(pi * self%geom%lat(i,j) / self%ssh_phi_ex))
257  end if
258  end do
259  end do
260 end subroutine soca_bkgerrgodas_ssh
261 
262 
263 ! ------------------------------------------------------------------------------
264 !> Derive unbalanced S background error, based on MLD
265 !!
266 !! \relates soca_bkgerrgodas_mod::soca_bkgerrgodas
267 subroutine soca_bkgerrgodas_socn(self)
268  class(soca_bkgerrgodas), intent(inout) :: self
269  !
270  type(soca_domain_indices), target :: domain
271  type(soca_field), pointer :: field, mld, layer_depth
272  integer :: i, j, k
273  real(kind=kind_real) :: r
274 
275 
276  ! Get compute domain indices
277  domain%is = self%geom%isc ; domain%ie = self%geom%iec
278  domain%js = self%geom%jsc ; domain%je = self%geom%jec
279  !
280  ! Get local compute domain indices
281  domain%isl = self%geom%iscl ; domain%iel = self%geom%iecl
282  domain%jsl = self%geom%jscl ; domain%jel = self%geom%jecl
283 
284  ! TODO read in a precomputed surface S background error
285 
286  ! Loop over compute domain
287  call self%std_bkgerr%get("socn", field)
288  call self%bkg%get("mld", mld)
289  call self%bkg%get("layer_depth", layer_depth)
290 
291  do i = domain%is, domain%ie
292  do j = domain%js, domain%je
293  if (self%geom%mask2d(i,j) /= 1) cycle
294 
295  do k = 1, self%geom%nzo
296  if ( layer_depth%val(i,j,k) <= mld%val(i,j,1)) then
297  ! if in the mixed layer, set to the maximum value
298  field%val(i,j,k) = self%bounds%s_max
299  else
300  ! otherwise, taper to the minium value below MLD
301  r = 0.1 + 0.45 * (1-tanh( 2 * log( &
302  & layer_depth%val(i,j,k) / mld%val(i,j,1) )))
303  field%val(i,j,k) = max(self%bounds%s_min, r*self%bounds%s_max)
304  end if
305  end do
306  end do
307  end do
308 end subroutine soca_bkgerrgodas_socn
309 
310 end module soca_bkgerrgodas_mod
variable transform: background error
bakground error bounds
Handle fields for the model.
Geometry module.
Increment fields.
surface background error used by soca_bkgerrgodas_mod
State fields.
various utility functions
Definition: soca_utils.F90:7
subroutine, public soca_diff(dvdz, v, h)
Definition: soca_utils.F90:96
Variable transform for background error (D), GODAS version.
Holds all data and metadata related to a single field variable.
A collection of soca_field types representing a collective state or increment.
Geometry data structure.
domain indices used by soca_omb_stats
interpolate surface background error file to grid