21 real(kind=kind_real) :: sigma
22 real(kind=kind_real) :: vert_corr
23 real(kind=kind_real),
allocatable :: sqrt_merid(:,:)
24 real(kind=kind_real),
allocatable :: sqrt_inv_merid(:,:)
25 real(kind=kind_real),
allocatable :: sqrt_zonal(:)
28 #define LISTED_TYPE qg_3d_covar_config 31 #include "oops/util/linkedList_i.f" 40 #include "oops/util/linkedList_c.f" 59 use fckit_log_module,
only : fckit_log
62 type(c_ptr),
intent(in) :: c_model
63 type(qg_geom),
intent(in) :: geom
64 type(qg_3d_covar_config),
intent(inout) :: config
67 real(kind=kind_real),
allocatable :: trigs(:), struct_fn(:), evals(:), &
68 work(:), evects(:,:), revals(:)
69 character(len=160) :: record
71 real(kind=kind_real) :: corr_length_scale, dy, z, dx, condition_number, threshold
72 integer :: i, j, k, info
76 config%sigma = config_get_real(c_model,
"standard_deviation")
77 config%vert_corr = config_get_real(c_model,
"vertical_correlation")
78 corr_length_scale = config_get_real(c_model,
"horizontal_length_scale")
79 condition_number = config_get_real(c_model,
"maximum_condition_number")
84 if (mod(config%nx,2)/=0)
then 85 write(record,*)
"c_qg_3d_covar_setup: number of zonal gridpoints nx=",config%nx
86 call fckit_log%error(record)
87 call abor1_ftn(
"c_qg_3d_covar_setup: odd number of zonal grid points")
92 allocate(evects(config%ny,config%ny))
95 z = (sqrt(0.5_kind_real)*dy/corr_length_scale)*
real(i-1,kind_real)
96 evects(i,1) = exp(-z*z)
101 evects(i,j) = evects(i-j+1,1)
107 allocate(evals(config%ny))
108 allocate(work((config%ny+3)*config%ny))
110 call dsyev (
'V',
'L',config%ny,evects,config%ny,evals,work,
size(work),info)
113 write(record,*)
"c_qg_3d_covar_setup: DSYEV returns info=",info
114 call fckit_log%error(record)
115 call abor1_ftn (
"c_qg_3d_covar_setup: DSYEV failed to sqrt matrix")
123 allocate(revals(config%ny))
125 threshold = maxval(evals(:))/condition_number
128 evals(j) = sqrt(
max(threshold,evals(j)))
129 revals(j) = 1.0_kind_real/evals(j)
132 allocate(config%sqrt_merid(config%ny,config%ny))
133 allocate(config%sqrt_inv_merid(config%ny,config%ny))
137 config%sqrt_merid(i,j) = 0.0_kind_real
138 config%sqrt_inv_merid(i,j) = 0.0_kind_real
141 config%sqrt_merid(i,j) = config%sqrt_merid(i,j) &
142 & + evects(i,k)*evects(j,k)*evals(k)
143 config%sqrt_inv_merid(i,j) = config%sqrt_inv_merid(i,j) &
144 & + evects(i,k)*evects(j,k)*revals(k)
156 allocate(struct_fn(config%nx))
158 z = (sqrt(0.5_kind_real)*dx/corr_length_scale) &
159 & *
real(min(j-1,1+config%nx-j),kind_real)
160 struct_fn(j) = exp(-z*z)
163 allocate(work(config%nx+2))
165 call fft_fwd(config%nx,struct_fn,work)
166 work(:) = work(:) /
real(config%nx, kind_real)
172 allocate(config%sqrt_zonal(0:config%nx/2))
174 threshold = 0.0_kind_real
176 threshold =
max(threshold,work(1+2*i))
178 threshold = threshold/condition_number
181 config%sqrt_zonal(i) = sqrt(
max(threshold,
real(config%nx,kind_real)*work(1+2*i)))
184 deallocate(struct_fn)
196 type(qg_3d_covar_config) :: self
198 deallocate(self%sqrt_zonal)
199 deallocate(self%sqrt_merid)
200 deallocate(self%sqrt_inv_merid)
215 integer(c_int),
intent(in) :: kx
216 integer(c_int),
intent(in) :: ky
217 real(c_double),
intent(inout) :: xctl(kx,ky,2)
218 type(qg_field),
intent(in) :: xincr
219 type(qg_3d_covar_config),
intent(in) :: config
221 real(kind=kind_real) :: zfour(kx+2), work(ky)
222 integer :: i, j, k, iri, m
223 real(kind=kind_real) :: zc, zero, one
227 zc = 1.0_kind_real/config%sigma
231 xctl(i,j,k) = zc * xincr%x(i,j,k)
240 call fft_fwd(kx,xctl(:,j,k),zfour)
243 zfour(2*m+iri) = zfour(2*m+iri) / config%sqrt_zonal(m)
246 call fft_inv(kx,zfour,xctl(:,j,k))
256 call dsymv(
'L',ky,one,config%sqrt_inv_merid,ky,xctl(i,1,k),kx,zero,work,1)
258 xctl(i,j,k) = work(j)
265 zc = 1.0_kind_real / sqrt(1.0_kind_real-config%vert_corr*config%vert_corr)
268 xctl(i,j,2) = zc * (xctl(i,j,2) - config%vert_corr * xctl(i,j,1))
285 integer(c_int),
intent(in) :: kx
286 integer(c_int),
intent(in) :: ky
287 type(qg_field),
intent(inout) :: xincr
288 real(c_double),
intent(in) :: xctl(kx,ky,2)
289 type(qg_3d_covar_config),
intent(in) :: config
291 real(kind=kind_real),
allocatable :: xout(:,:,:)
292 real(kind=kind_real) :: zfour(kx+2), work(ky)
293 integer :: i, j, k, iri, m
294 real(kind=kind_real) :: zc, zero, one
299 allocate(xout(kx,ky,2))
301 zc = sqrt(1.0_kind_real-config%vert_corr*config%vert_corr)
304 xout(i,j,1) = xctl(i,j,1) -config%vert_corr * xctl(i,j,2) &
305 & *(1.0_kind_real/zc)
306 xout(i,j,2) = xctl(i,j,2)*(1.0_kind_real/zc)
316 call dsymv(
'L',ky,one,config%sqrt_inv_merid,ky,xout(i,1,k), &
319 xout(i,j,k) = work(j)
328 call fft_fwd(kx,xout(:,j,k),zfour)
331 zfour(2*m+iri) = zfour(2*m+iri) / config%sqrt_zonal(m)
334 call fft_inv(kx,zfour,xout(:,j,k))
343 xincr%x(i,j,k) = xincr%x(i,j,k) + xout(i,j,k) &
344 & *(1.0_kind_real/config%sigma)
364 integer(c_int),
intent(in) :: kx
365 integer(c_int),
intent(in) :: ky
366 type(qg_field),
intent(inout) :: xincr
367 real(c_double),
intent(in) :: xctl(kx,ky,2)
368 type(qg_3d_covar_config),
intent(in) :: config
370 integer :: i, j, k, iri, m
371 real(kind=kind_real) :: zc, zero, one
372 real(kind=kind_real) :: zfour(kx+2), work(ky)
376 zc = sqrt(1.0_kind_real-config%vert_corr*config%vert_corr)
379 xincr%x(i,j,1) = xctl(i,j,1)
380 xincr%x(i,j,2) = config%vert_corr * xctl(i,j,1) + zc * xctl(i,j,2)
390 call dsymv(
'L',ky,one,config%sqrt_merid,ky,xincr%x(i,1,k),kx,zero,work,1)
392 xincr%x(i,j,k) = work(j)
401 call fft_fwd(kx,xincr%x(:,j,k),zfour)
404 zfour(2*m+iri) = zfour(2*m+iri) * config%sqrt_zonal(m)
407 call fft_inv(kx,zfour,xincr%x(:,j,k))
416 xincr%x(i,j,k) = xincr%x(i,j,k) * config%sigma
434 integer(c_int),
intent(in) :: kx
435 integer(c_int),
intent(in) :: ky
436 real(c_double),
intent(inout) :: xctl(kx,ky,2)
437 type(qg_field),
intent(in) :: xincr
438 type(qg_3d_covar_config),
intent(in) :: config
440 real(kind=kind_real),
allocatable :: xout(:,:,:)
441 integer :: i, j, k, iri, m
442 real(kind=kind_real) :: zc, zero, one
443 real(kind=kind_real) :: zgrid(kx), zfour(kx+2), work(ky)
447 allocate(xout(kx,ky,2))
451 zgrid(:) = xincr%x(:,j,k) * config%sigma
455 zfour(2*m+iri) = zfour(2*m+iri) * config%sqrt_zonal(m)
458 call fft_inv(kx,zfour,xout(:,j,k))
468 call dsymv(
'L',ky,one,config%sqrt_merid,ky,xout(i,1,k),kx,zero,work,1)
470 xout(i,j,k) = work(j)
477 zc = sqrt(1.0_kind_real-config%vert_corr*config%vert_corr)
480 xctl(i,j,1) = xctl(i,j,1) + xout(i,j,1) &
481 & +config%vert_corr * xout(i,j,2)
482 xctl(i,j,2) = xctl(i,j,2) + xout(i,j,2) * zc
real(kind=kind_real), parameter domain_meridional
meridional model domain (m)
subroutine, public fft_inv(kk, pf, pg)
subroutine qg_3d_covar_sqrt_inv_mult(kx, ky, xctl, xincr, config)
Multiply streamfunction by inverse(sqrt(C)), where C is 3d covariance matrix.
Structure holding configuration variables for the 3d error covariance matrices of the QG analysis...
subroutine qg_3d_covar_delete(self)
Delete for the QG model's 3d error covariance matrices.
Constants for the QG model.
Fortran module for Eigen FFTs.
Fortran module handling geometry for the QG model.
subroutine qg_3d_covar_setup(c_model, geom, config)
Linked list implementation.
subroutine qg_3d_covar_sqrt_mult(kx, ky, xincr, xctl, config)
Multiply streamfunction by sqrt(C), where C is a 3d covariance matrix.
type(registry_t) qg_3d_cov_registry
Linked list interface - defines registry_t type.
subroutine qg_3d_covar_sqrt_inv_mult_ad(kx, ky, xctl, xincr, config)
Multiply streamfunction by inverse(sqrt(C)) - Adjoint.
Fortran derived type to hold configuration data for the QG background/model covariance.
Handle fields for the QG model.
subroutine, public fft_fwd(kk, pg, pf)
real(kind=kind_real), parameter domain_zonal
model domain (m) in zonal direction
subroutine qg_3d_covar_sqrt_mult_ad(kx, ky, xincr, xctl, config)
Multiply streamfunction by sqrt(C) - Adjoint.