-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updates for handling CrIS SWIR data #587
Changes from 15 commits
d94604a
c8013a1
60ebc53
21eb45d
488cf6e
8478f9d
7dc9f4e
4d4d7d2
40aad5c
759f80f
cac4bc3
ff91f56
a88ff51
10fe207
08af125
2a4c143
0131a0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,6 +76,7 @@ module qcmod | |
! for all variables | ||
! 2019-03-27 h. liu - add ABI QC | ||
! 2019-06-10 h. liu - add Geostationary satellites CSR data QC to replace qc_abi,qc_seviri | ||
! 2019-07-20 ejones - mods to qc_irsnd for CrIS, add sun glint QC flag for CrIS | ||
! 2019-09-29 X.Su - add troflg and lat_c for hilbert curve tunning | ||
! 2019-04-19 eliu - add QC flag for cold-air outbreak | ||
! 2021-04-29 Jung/Collard - Fix numerics for emissivity check | ||
|
@@ -305,6 +306,9 @@ module qcmod | |
integer(i_kind),parameter:: ifail_satzen_qc=52 | ||
! Reject because of surface emissivity/temperature influence in subroutine qc_irsnd | ||
integer(i_kind),parameter:: ifail_sfcir_qc=53 | ||
! Reject because of sun glint in subroutine qc_irsnd | ||
integer(i_kind),parameter:: ifail_glint_irqc=54 | ||
|
||
|
||
! QC_AMSUA | ||
! Reject because factch6 > limit in subroutine qc_amsua | ||
|
@@ -2065,10 +2069,10 @@ subroutine qc_saphir(nchanl,sfchgt,luse,sea, & | |
return | ||
end subroutine qc_saphir | ||
|
||
subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | ||
cris, hirs, zsges,cenlat,frac_sea,pangs,trop5,zasat,tzbgr,tsavg5,tbc,tb_obs,tbcnob,tnoise, & | ||
wavenumber,ptau5,prsltmp,tvp,temp,wmix,emissivity_k,ts, & | ||
id_qc,aivals,errf,varinv,varinv_use,cld,cldp,kmax,zero_irjaco3_pole) | ||
subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | ||
cris,hirs,zsges,cenlat,frac_sea,pangs,trop5,zasat,solazi,satazi,tzbgr,tsavg5, & | ||
tbc,tb_obs,tbcnob,tnoise,wavenumber,ptau5,prsltmp,tvp,temp,wmix,emissivity_k,ts, & | ||
id_qc,aivals,errf,varinv,varinv_use,cld,cldp,kmax,zero_irjaco3_pole,cris_sw) | ||
! id_qc,aivals,errf,varinv,varinv_use,cld,cldp,kmax,zero_irjaco3_pole,radmod) ! all-sky | ||
|
||
!$$$ subprogram documentation block | ||
|
@@ -2084,8 +2088,10 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
! 2010-08-10 derber transfered from setuprad | ||
! 2011-08-20 zhu add cloud qc for passive channels based on the cloud | ||
! level determined by channels with irad_use=1 and 0 | ||
! 2015-03-26 mkim add extra qc for sfc sensitive channels | ||
! 2015-03-26 mkim add extra qc for sfc sensitive channels | ||
! These qc are optional.(On/off by depending on the number in satinfo table) | ||
! 2019-07-20 ejones Add sun glint check for CrIS SW obs | ||
! 2019-07-24 ejones Add cris_sw logic so observations aren't counted twice in aivals stats | ||
! | ||
! input argument list: | ||
! nchanl - number of channels per obs | ||
|
@@ -2102,9 +2108,11 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
! zsges - elevation of guess | ||
! cenlat - latitude of observation | ||
! frac_sea - fraction of grid box covered with water | ||
! pangs - solar zenith angle | ||
! pangs - solar zenith angle (deg) | ||
! trop5 - tropopause pressure | ||
! zasat - satellite zenith angle | ||
! zasat - satellite zenith angle (rad) | ||
! solazi - solar azimuth angle (deg) | ||
! satazi - satellite azimuth angle (deg) | ||
! tzbgr - Tz over water | ||
! tsavg5 - surface skin temperature | ||
! tbc - simulated - observed BT with bias correction | ||
|
@@ -2123,6 +2131,7 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
! errf - criteria of gross error | ||
! varinv - observation weight (modified obs var error inverse) | ||
! varinv_use - observation weight used(modified obs var error inverse) | ||
! cris_sw - logical for cris sw case | ||
! | ||
! output argument list: | ||
! id_qc - qc index - see qcmod definition | ||
|
@@ -2146,14 +2155,15 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
|
||
! Declare passed variables | ||
|
||
logical, intent(in ) :: sea,land,ice,snow,luse,goessndr, cris, hirs | ||
logical, intent(inout) :: zero_irjaco3_pole | ||
logical, intent(in ) :: sea,land,ice,snow,luse,goessndr,cris,hirs | ||
logical, intent(inout) :: zero_irjaco3_pole,cris_sw | ||
integer(i_kind), intent(in ) :: nsig,nchanl,ndat,is | ||
integer(i_kind),dimension(nchanl), intent(in ) :: ich | ||
integer(i_kind),dimension(nchanl), intent(inout) :: id_qc | ||
integer(i_kind),dimension(nchanl), intent(in ) :: kmax | ||
real(r_kind), intent(in ) :: zsges,cenlat,frac_sea,pangs,trop5 | ||
real(r_kind), intent(in ) :: tzbgr,tsavg5,zasat | ||
real(r_kind), intent(in ) :: solazi,satazi | ||
real(r_kind), intent( out) :: cld,cldp | ||
real(r_kind),dimension(40,ndat), intent(inout) :: aivals | ||
real(r_kind),dimension(nchanl), intent(in ) :: tbc,emissivity_k,ts,wavenumber,tb_obs,tbcnob | ||
|
@@ -2168,6 +2178,7 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
|
||
|
||
real(r_kind) :: demisf,dtempf,efact,dtbf,term,cenlatx,sfchgtfact | ||
real(r_kind) :: pangs_rad,solazi_rad,satazi_rad,relazi_rad,glint_rad,glint | ||
real(r_kind) :: sum,sum2,sum3,cloudp,tmp,dts,delta | ||
real(r_kind),dimension(nchanl) :: dtb | ||
integer(i_kind) :: i,j,k,kk,lcloud,m | ||
|
@@ -2181,10 +2192,31 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
! solar zenith angle tiny_r_kind | ||
irday = 1 | ||
if (pangs <= 89.0_r_kind .and. frac_sea > zero) then | ||
if(.not. cris_sw) then | ||
! QC2 in statsrad | ||
if(luse)aivals(9,is) = aivals(9,is) + one | ||
if(luse)aivals(9,is) = aivals(9,is) + one | ||
endif | ||
do i=1,nchanl | ||
if(wavenumber(i) > r2000)then | ||
! check for sun glint for CrIS at wavenumbers shortward of 2386.88 | ||
if(cris)then | ||
if(wavenumber(i) > 2386.88)then | ||
! calculate sun glint | ||
! pangs, solazi, satazi need conversion to radians | ||
! zasat passed from reader in radians, take abs avalue | ||
pangs_rad=pangs*deg2rad | ||
solazi_rad=solazi*deg2rad | ||
satazi_rad=satazi*deg2rad | ||
relazi_rad=(180.0+solazi-satazi)*deg2rad | ||
glint_rad=acos(cos(abs(zasat))*cos(pangs_rad)+sin(abs(zasat))*sin(pangs_rad)*cos(relazi_rad)) | ||
glint=glint_rad*rad2deg | ||
! QC low peaking CrIS SW obs with sun glint less than or equal to 15deg | ||
if (glint <= 15.0) then | ||
varinv(i)=zero | ||
varinv_use(i)=zero | ||
if(id_qc(i) == igood_qc)id_qc(i)=ifail_glint_irqc | ||
endif | ||
endif | ||
else if(wavenumber(i) > r2000)then | ||
if(wavenumber(i) > r2400)then | ||
varinv(i)=zero | ||
varinv_use(i)=zero | ||
|
@@ -2223,7 +2255,7 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
if (qc_noirjaco3_pole .and. (abs(cenlat)>r60)) zero_irjaco3_pole=.true. | ||
|
||
! If GOES and lza > 60. do not use | ||
if( goessndr .and. zasat*rad2deg > r60) then | ||
if( goessndr .and. zasat*rad2deg > r60 .and. (.not. cris_sw)) then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would cris_sw be true for GOES? Or do you want to generalise this for all IR instruments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cris_sw shouldn't be true for GOES; this is a redundant check because I'm paranoid. It can be removed if preferred. |
||
! QC5 in statsrad | ||
if(luse)aivals(12,is) = aivals(12,is) + one | ||
do i=1,nchanl | ||
|
@@ -2237,7 +2269,9 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
sfchgtfact=one | ||
if (zsges > r2000) then | ||
! QC1 in statsrad | ||
if(luse)aivals(8,is) = aivals(8,is) + one | ||
if (.not. cris_sw) then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does the SW changes affect the QC decisions over high topography? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't; this is included so obs aren't counted more than once, since qc_irsnd is called twice in setuprad (calling qc_irsnd twice pertains to the LW vs SW cloud detection... see cloud detection comment) |
||
if(luse)aivals(8,is) = aivals(8,is) + one | ||
endif | ||
sfchgtfact = (r2000/zsges)**4 | ||
endif | ||
|
||
|
@@ -2309,7 +2343,15 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
j=ich(i) | ||
if (passive_bc .and. iuse_rad(j)==-1) then | ||
if (lcloud .ge. kmax(i)) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
if(.not.cris) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
else if(cris) then | ||
if(.not. cris_sw .and. wavenumber(i) < 2000.0) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
else if(cris_sw .and. wavenumber(i) >= 2000.0) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
end if | ||
end if | ||
varinv(i) = zero | ||
if(id_qc(i) == igood_qc)id_qc(i)=ifail_cloud_qc | ||
cycle | ||
|
@@ -2321,7 +2363,15 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
|
||
if ( ptau5(lcloud,i) > 0.02_r_kind) then | ||
! QC4 in statsrad | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
if(.not.cris) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
else if(cris) then | ||
if(.not. cris_sw .and. wavenumber(i) < 2000.0) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
else if(cris_sw .and. wavenumber(i) >= 2000.0) then | ||
if(luse)aivals(11,is) = aivals(11,is) + one | ||
end if | ||
end if | ||
varinv(i) = zero | ||
if(id_qc(i) == igood_qc)id_qc(i)=ifail_cloud_qc | ||
end if | ||
|
@@ -2350,7 +2400,18 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
delta=max(r0_05*tnoise(i),r0_02) | ||
if(abs(dts*ts(i)) > delta)then | ||
! QC3 in statsrad | ||
if(luse .and. varinv(i) > zero) aivals(10,is) = aivals(10,is) + one | ||
if(.not.cris) then | ||
if(luse .and. varinv(i) > zero) & | ||
aivals(10,is) = aivals(10,is) + one | ||
else if(cris) then | ||
if(.not. cris_sw .and. wavenumber(i) < 2000.0) then | ||
if(luse .and. varinv(i) > zero) & | ||
aivals(10,is) = aivals(10,is) + one | ||
else if(cris_sw .and. wavenumber(i) >= 2000.0) then | ||
if(luse .and. varinv(i) > zero) & | ||
aivals(10,is) = aivals(10,is) + one | ||
end if | ||
end if | ||
varinv(i) = zero | ||
if(id_qc(i) == igood_qc)id_qc(i)=ifail_sfcir_qc | ||
end if | ||
|
@@ -2365,7 +2426,11 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
do i=1,nchanl | ||
if (ts(i) > 0.2_r_kind) then | ||
! QC3 in statsrad | ||
if(luse .and. varinv(i) > zero) aivals(10,is) = aivals(10,is) + one | ||
if(.not. cris_sw .and. wavenumber(i) < 2000.0) then | ||
if(luse .and. varinv(i) > zero) aivals(10,is) = aivals(10,is) + one | ||
else if(cris_sw .and. wavenumber(i) >= 2000.0) then | ||
if(luse .and. varinv(i) > zero) aivals(10,is) = aivals(10,is) + one | ||
end if | ||
varinv(i) = zero | ||
if(id_qc(i) == igood_qc)id_qc(i)=ifail_sfcir_qc | ||
end if | ||
|
@@ -2393,7 +2458,15 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
if ( abs(dtz) > tzchks ) then | ||
varinv(i) = zero | ||
if ( id_qc(i) == igood_qc ) id_qc(i) = ifail_tzr_qc | ||
if(luse)aivals(13,is) = aivals(13,is) + one | ||
if(.not.cris) then | ||
if(luse)aivals(13,is) = aivals(13,is) + one | ||
else if(cris) then | ||
if(.not. cris_sw .and. wavenumber(i) < 2000.0) then | ||
if(luse) aivals(13,is) = aivals(13,is) + one | ||
else if(cris_sw .and. wavenumber(i) >= 2000.0) then | ||
if(luse) aivals(13,is) = aivals(13,is) + one | ||
end if | ||
endif | ||
endif | ||
endif | ||
enddo | ||
|
@@ -2402,7 +2475,9 @@ subroutine qc_irsnd(nchanl,is,ndat,nsig,ich,sea,land,ice,snow,luse,goessndr, & | |
|
||
cenlatx=abs(cenlat)*r0_04 | ||
if (cenlatx < one) then | ||
if(luse)aivals(6,is) = aivals(6,is) + one | ||
if(.not. cris_sw) then | ||
if(luse)aivals(6,is) = aivals(6,is) + one | ||
endif | ||
efact = half*(cenlatx+one) | ||
do i=1,nchanl | ||
if(varinv(i) > tiny_r_kind) errf(i)=efact*errf(i) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for this if (cris) logic? Wouldn't the sun-glint test be applicable to all ir sounders?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be. We were focused only on looking at and making modifications for CrIS SW, hence the if (cris) logic. I can modify the code to make this generic for all SW, if that's preferred.