-
Notifications
You must be signed in to change notification settings - Fork 0
Home
For global hybrid-EnVar with cwoption=3, the lifecycle of qr is:
qrbecomes a 3-D control variable only if it is present incvars3d.-
Global background-error setup gives
qra neutral amplitudecorz=1and q-like length scales (hwll,vz) scaled by 0.5 when individual cloud species are used undercwoption=3. prewgt.f90builds the initialdssvforqrfromdsv * corz * as3d, which for this case is effectivelydsv * 1 * as3d.compute_qvar3d.f90then makesdssv(qr)state-dependent by multiplying it by0.05 * max(qr,1e-10)above 15 hPa, and zeroing it below that pressure threshold.bkgvar.f90later applies that finaldssv(qr)directly to theqrcontrol field during the background-error transform.- Hybrid-EnVar does not appear to give
qra special ensemble/control-space treatment here; it is carried like any other active 3-D control variable, provided it exists incvars3d.
Below is the full trace.
Note: GitHub code-search results are capped and may be incomplete. To inspect more matches in GitHub UI, use:
https://github.com/search?q=repo%3ANOAA-EMC%2FGSI+qr+cwoption%3D%3D3&type=code
qr is not hardwired as always active. It is active if it appears in the configured 3-D control-variable list cvars3d. In several places, GSI checks this with getindex(cvars3d,'qr'). For example, the regional code explicitly does this:
nrf3_ql =getindex(cvars3d,'ql')
nrf3_qi =getindex(cvars3d,'qi')
nrf3_qr =getindex(cvars3d,'qr')
nrf3_qs =getindex(cvars3d,'qs')
nrf3_qg =getindex(cvars3d,'qg')For global all-sky handling, compute_qvar3d does not hardcode qr; instead it loops through cvars3d and matches names against cloud_names_fwd. So qr participates when:
-
icloud_cvis true, -
cwoption==3, -
cwis not the active cloud control variable (nrf3_cw<=0path), - and
qris one of the forward cloud names incloud_names_fwd.
In the global stats reader m_berror_stats.f90, when cwoption==1 .or. cwoption==3, and there is no total cloud-water control variable cw but there are individual cloud variables (n_clouds_fwd>0), each matching cloud variable such as qr is assigned:
corz(:,:,ivar)=1hwll(:,:,ivar)=0.5*hwll(:,:,iq)vz(:,:,ivar)=0.5*vz(:,:,iq)
where iq is the index of q. That is the key global setup for qr.
if (n_clouds_fwd>0 .and. icw<=0) then
do n=1,size(cvars3d)
do ic=1,n_clouds_fwd
if(trim(cvars3d(n))==trim(cloud_names_fwd(ic))) then
ivar=n
do k=1,nsig
do i=1,nlat
corz(i,k,ivar)=one
end do
end do
hwll(:,:,ivar)=0.5_r_kind*hwll(:,:,iq)
vz (:,:,ivar)=0.5_r_kind*vz (:,:,iq)
exit
end if
end do
end do
end ifSo for global qr with cwoption=3, corz is deliberately neutralized to 1. The variance amplitude is not coming from a qr-specific climatological corz pattern; instead, the later state-dependent scaling in compute_qvar3d carries the important amplitude dependence.
In global prewgt.f90, the generic 3-D background-error amplitude is built as:
dssv(j,i,k,n)=dsv(i,k)*corz(jx,k,n)*as3d(n)for all ordinary 3-D variables not handled specially as SF/VP/T/O3.
else
do k=1,nsig
do i=1,lon2
dssv(j,i,k,n)=dsv(i,k)*corz(jx,k,n)*as3d(n)
end do
end do
end ifSince global m_berror_stats.f90 already set corz(qr)=1 for this case, the initial qr amplitude is effectively:
dssv_init(qr) = dsv * as3d(qr)
with the vertical structure dsv itself determined from the cloud-adjusted vz field. Because vz(qr)=0.5*vz(q), qr inherits q-like but shorter vertical correlation scales. Likewise hwll(qr)=0.5*hwll(q) sets shorter horizontal scales for the later filter setup.
This is the step tied to your original line. compute_qvar3d is called from prewgt.f90 after the base dssv is built. The call site comment says it is a “Special case of dssv for qoption=2 and cw”, but the code path also handles individual hydrometeors when cwoption==3.
For the individual hydrometeor path:
- if pressure is below 15 hPa:
dssv(...)=0 - else:
-
cwtmp = ges_var(i,j,k)i.e. forqr,cwtmp = ges_qr(i,j,k) - floor it at
1e-10 dn1 = 0.05 * cwtmpdssv = dn1 * dssv
-
That is exactly the qr rule once ges_var is associated with qr.
else
if (cwoption/=3) return
do n=1,size(cvars3d)
do ic=1,n_clouds_fwd
if(trim(cvars3d(n))==trim(cloud_names_fwd(ic))) then
nrf3_var=n
call gsi_bundlegetpointer (gsi_metguess_bundle(ntguessig), &
trim(cloud_names_fwd(ic)),ges_var,istatus)
if (istatus/=0) return
do k = 1,nsig
do j = 1,lon2
do i = 1,lat2
if (ges_prsl(i,j,k,ntguessig)<15.0_r_kind) then
dssv(i,j,k,nrf3_var)=zero
else
cwtmp=ges_var(i,j,k)
if (ges_var(i,j,k)<1.0e-10_r_kind) cwtmp=1.0e-10_r_kind
dn1=0.05_r_kind*cwtmp
dssv(i,j,k,nrf3_var)=dn1*dssv(i,j,k,nrf3_var)So for qr specifically:
dssv_final(qr) =
0, if p < 15 hPa
(0.05 * max(qr_guess,1e-10)) *
dsv * corz * as3d, otherwise
and because global setup made corz(qr)=1:
dssv_final(qr) =
(0.05 * max(qr_guess,1e-10)) * dsv * as3d(qr)
above 15 hPa.
Interpretation of dn1=0.05*cwtmp:
- it makes the background-error standard deviation for
qrproportional to the current guessed rainwater mixing ratio; - when
qris tiny, the factor is tiny but bounded below by the1e-10floor before scaling; - thus
qrincrements are strongly suppressed where no rainwater exists in the guess.
compute_qvar3d gets ges_var from gsi_metguess_bundle(ntguessig) using the cloud variable name, so for qr it reads the current guess rainwater field from the metguess bundle.
More broadly, the codebase has multiple places where qr is read into bundles. For example, the FV3/GFS-side I/O accesses qr bundle pointers, which is consistent with qr being available as a metguess field when configured.
Once dssv is finalized, bkgvar.f90 applies it by multiplying the corresponding 3-D control field by dssv(j,i,k,n). This is the actual variance/preconditioning transform step.
do n=1,cvec%n3d
call gsi_bundlegetpointer ( cvec,cvec%r3(n)%shortname,ptr3d,istatus )
do k=1,nsig
do i=1,lon2
do j=1,lat2
ptr3d(j,i,k) =ptr3d(j,i,k)*dssv(j,i,k,n)
end do
enddo
enddo
end doSo the lifecycle is:
- stats setup defines
corz,hwll,vz -
prewgtturns them intodssv_init -
compute_qvar3dturns that into state-dependentdssv_final(qr) -
bkgvarusesdssv_final(qr)to scale theqrcontrol variable in the transform
For your question, the crucial distinction is:
-
Global:
qrundercwoption=3gets neutralcorz=1and q-derived scales inm_berror_stats.f90, thencompute_qvar3dapplies the state-dependent0.05*qrfactor. -
Regional: there is additional special logic in
prewgt_reg.f90andm_berror_stats_reg.f90, including radar/cloud-temperature-dependent variance paths and explicit cloud variable indices. Regional can also usecorz_cldanddsv_cldbranches that do not exist in the same way in the global path.
So the global hybrid-EnVar qr path is simpler:
- no special temperature-dependent
corz_cldmachinery; - baseline amplitude neutralized via
corz=1; - state dependence comes primarily from
compute_qvar3d.
From the code I checked, not in the core variance-transform path. Hybrid-EnVar consistency checks exist generally, e.g. l_hyb_ens with TLNMC options in gsimod.F90, but I do not see a separate qr-specific hybrid weighting rule in the path we traced. qr appears to participate like any active 3-D control variable once it is in cvars3d.
There are ensemble-I/O paths that know about qr, especially for radar or cloud-aware applications, which means the ensemble side can carry qr when configured. But that is different from the static B-error / dssv lifecycle, where qr is not singled out by hybrid logic in the files examined.
For an active qr control variable in the global path in "prewgt_reg.f90"
(https://github.com/NOAA-EMC/GSI/blob/develop/src/gsi/prewgt_reg.f90#L486-L558):
corz(qr) = 1
hwll(qr) = 0.5 * hwll(q)
vz(qr) = 0.5 * vz(q)
dssv_init(qr) = dsv(vz(qr)) * as3d(qr)
dssv_final(qr) = 0 if p < 15 hPa
= 0.05 * max(qr_guess,1e-10) *
dsv(vz(qr)) * as3d(qr) otherwise
and then bkgvar multiplies the qr control field by this dssv_final(qr).
If you want, I can next trace the exact call chain that makes qr appear in cloud_names_fwd and cvars3d for the global all-sky setup.