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.