Skip to content

Commit b8fa4bb

Browse files
committed
Adding VIIRS-M Radiance Data Assimilation in GEOS
1 parent d7d6420 commit b8fa4bb

14 files changed

Lines changed: 1183 additions & 9 deletions

GEOSaana_GridComp/GEOSgsi_Coupler/cplr_nst.F90

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,285 @@ subroutine deter_nst_(dlat_earth,dlon_earth,obstime,zob,tref,dtw,dtc,tz_tr)
283283
end subroutine deter_nst_
284284
!*******************************************************************************************
285285

286+
subroutine deter_nst_viirs_(dlat_earth,dlon_earth,obstime,zob,tref,dtw,dtc,tz_tr)
287+
!$$$ subprogram documentation block
288+
! . . . .
289+
! subprogram: deter_nst_viirs determine NSST variable at observation location over water
290+
! prgmmr: Xu Li org: np2 date: 2011-04-08
291+
! abstract: determines NSST variables over water surface type based on surrounding surface types
292+
!
293+
! program history log:
294+
! 2026-05-22 a.lee Modify deter_nst_viirs_ for viirs (needs further investigation)
295+
!
296+
! input argument list:
297+
! dlat_earth - earth latitude in radians
298+
! dlon_earth - earth longitude in radians
299+
! obstime - observation time relative to analysis time
300+
! zob - obs. depth in the water
301+
!
302+
! output argument list:
303+
! tref - oceanic foundation temperature
304+
! dtw - diurnal warming at depth zob
305+
! dtc - sublayer cooling at depth zob
306+
! tz_tr - d(Tz)/d(Tbar); is DIFFERENT to Xu Li. Xu Li: d(Tz)/d(Tr); Tr: foundation or ref. Temp.
307+
! - in GEOS context it is = d(Tz)/d(Ts)
308+
! attributes:
309+
! language: f90
310+
! machine: ibm RS/6000 SP
311+
!
312+
!$$$
313+
use kinds, only: r_kind,i_kind
314+
use constants, only: zero, one
315+
use mpimod, only: mype
316+
use gridmod, only: nlat,nlon,regional,tll2xy,nlat_sfc,nlon_sfc,rlats_sfc,rlons_sfc
317+
use guess_grids, only: nfldsfc,hrdifsfc
318+
use mpimod, only: mype
319+
use gsi_nstcouplermod, only: tref_full,dt_cool_full,dt_warm_full,z_c_full,z_w_full
320+
use satthin, only: isli_full
321+
322+
use GSI_GridCompMod, only: MU_SKIN=>GEOS_MU_SKIN
323+
324+
! use ESMF, only: ESMF_ConfigGetAttribute
325+
! use m_die, only: die
326+
implicit none
327+
328+
real(r_kind), intent(in ) :: dlat_earth,dlon_earth,obstime,zob
329+
real(r_kind), intent(out) :: tref,dtw,dtc,tz_tr
330+
331+
! local variables
332+
character(len=*), parameter:: myname_='deter_nst_viirs_'
333+
real(r_kind):: dt_cool,z_c,z_w,dt_warm
334+
integer(i_kind):: istyp00,istyp01,istyp10,istyp11
335+
integer(i_kind):: itnst,itnstp
336+
integer(i_kind):: ix,iy,ixp,iyp,j,i,k
337+
real(r_kind):: dx,dy,dx1,dy1,w00,w10,w01,w11,dtnst,dtnstp,wgtmin
338+
real(r_kind):: tref_00,tref_01,tref_10,tref_11,tr_tmp
339+
real(r_kind):: dt_cool_00,dt_cool_01,dt_cool_10,dt_cool_11
340+
real(r_kind):: z_c_00,z_c_01,z_c_10,z_c_11,z_c_tmp
341+
real(r_kind):: dt_warm_00,dt_warm_01,dt_warm_10,dt_warm_11
342+
real(r_kind):: z_w_00,z_w_01,z_w_10,z_w_11,z_w_tmp
343+
344+
real(r_kind):: wgtavg,dlat,dlon
345+
logical outside
346+
347+
348+
! Read in the temperature profile exponent: mu_skin used for skin SST analysis
349+
! ----------------------------------------------------------------------------
350+
! CALL ESMF_ConfigGetAttribute(CF, MU_SKIN, label = 'mu_skin:', default=0.2_r_kind, rc=STATUS)
351+
! if (status/=0) then
352+
! call die ( myname_,': failed to get mu_skin' )
353+
! endif
354+
! if(IamRoot) print *,trim(Iam),': Set MU_SKIN= ', MU_SKIN
355+
356+
! Initialize output.
357+
tref = zero
358+
dtw = zero
359+
dtc = zero
360+
tz_tr = one
361+
362+
363+
if(regional)then
364+
call tll2xy(dlon_earth,dlat_earth,dlon,dlat,outside)
365+
else
366+
dlat=dlat_earth
367+
dlon=dlon_earth
368+
call grdcrd1(dlat,rlats_sfc,nlat_sfc,1)
369+
call grdcrd1(dlon,rlons_sfc,nlon_sfc,1)
370+
end if
371+
372+
iy=int(dlon); ix=int(dlat)
373+
dy =dlon-iy; dx =dlat-ix
374+
dx1 =one-dx; dy1 =one-dy
375+
w00=dx1*dy1; w10=dx*dy1; w01=dx1*dy; w11=one-w00-w10-w01
376+
377+
ix=min(max(1,ix),nlat_sfc); iy=min(max(0,iy),nlon_sfc)
378+
ixp=min(nlat_sfc,ix+1); iyp=iy+1
379+
if(iy==0) iy=nlon_sfc
380+
if(iyp==nlon_sfc+1) iyp=1
381+
382+
! Get time interpolation factors for nst files
383+
if(obstime > hrdifsfc(1) .and. obstime <= hrdifsfc(nfldsfc))then
384+
do j=1,nfldsfc-1
385+
if(obstime > hrdifsfc(j) .and. obstime <= hrdifsfc(j+1))then
386+
itnst=j
387+
itnstp=j+1
388+
dtnst=(hrdifsfc(j+1)-obstime)/(hrdifsfc(j+1)-hrdifsfc(j))
389+
end if
390+
end do
391+
else if(obstime <=hrdifsfc(1))then
392+
itnst=1
393+
itnstp=1
394+
dtnst=one
395+
else
396+
itnst=nfldsfc
397+
itnstp=nfldsfc
398+
dtnst=one
399+
end if
400+
dtnstp=one-dtnst
401+
402+
! Set surface type flag.
403+
404+
istyp00 = isli_full(ix ,iy )
405+
istyp10 = isli_full(ixp,iy )
406+
istyp01 = isli_full(ix ,iyp)
407+
istyp11 = isli_full(ixp,iyp)
408+
!
409+
! Use the time interpolation factors for nst files
410+
!
411+
tref_00 = 0.0_r_kind
412+
tref_01 = 0.0_r_kind
413+
tref_10 = 0.0_r_kind
414+
tref_11 = 0.0_r_kind
415+
416+
if ( tref_full(ix ,iy ,itnst) /= 290.0_r_kind .and. tref_full(ix ,iy ,itnstp) /= 290.0_r_kind .and. &
417+
tref_full(ix ,iyp ,itnst) /= 290.0_r_kind .and. tref_full(ix ,iyp ,itnstp) /= 290.0_r_kind .and. &
418+
tref_full(ixp ,iy ,itnst) /= 290.0_r_kind .and. tref_full(ixp ,iy ,itnstp) /= 290.0_r_kind .and. &
419+
tref_full(ixp ,iyp ,itnst) /= 290.0_r_kind .and. tref_full(ixp ,iyp ,itnstp) /= 290.0_r_kind ) then
420+
421+
tref_00 = tref_full (ix ,iy ,itnst)*dtnst + tref_full (ix ,iy ,itnstp)*dtnstp
422+
tref_01 = tref_full (ix ,iyp,itnst)*dtnst + tref_full (ix ,iyp,itnstp)*dtnstp
423+
tref_10 = tref_full (ixp,iy ,itnst)*dtnst + tref_full (ixp,iy ,itnstp)*dtnstp
424+
tref_11 = tref_full (ixp,iyp,itnst)*dtnst + tref_full (ixp,iyp,itnstp)*dtnstp
425+
endif
426+
427+
dt_cool_00 = dt_cool_full(ix ,iy ,itnst)*dtnst + dt_cool_full(ix ,iy ,itnstp)*dtnstp
428+
dt_cool_01 = dt_cool_full(ix ,iyp,itnst)*dtnst + dt_cool_full(ix ,iyp,itnstp)*dtnstp
429+
dt_cool_10 = dt_cool_full(ixp,iy ,itnst)*dtnst + dt_cool_full(ixp,iy ,itnstp)*dtnstp
430+
dt_cool_11 = dt_cool_full(ixp,iyp,itnst)*dtnst + dt_cool_full(ixp,iyp,itnstp)*dtnstp
431+
432+
z_c_00 = z_c_full (ix ,iy ,itnst)*dtnst + z_c_full (ix ,iy ,itnstp)*dtnstp
433+
z_c_01 = z_c_full (ix ,iyp,itnst)*dtnst + z_c_full (ix ,iyp,itnstp)*dtnstp
434+
z_c_10 = z_c_full (ixp,iy ,itnst)*dtnst + z_c_full (ixp,iy ,itnstp)*dtnstp
435+
z_c_11 = z_c_full (ixp,iyp,itnst)*dtnst + z_c_full (ixp,iyp,itnstp)*dtnstp
436+
437+
438+
dt_warm_00 = dt_warm_full(ix ,iy ,itnst)*dtnst + dt_warm_full(ix ,iy ,itnstp)*dtnstp
439+
dt_warm_01 = dt_warm_full(ix ,iyp,itnst)*dtnst + dt_warm_full(ix ,iyp,itnstp)*dtnstp
440+
dt_warm_10 = dt_warm_full(ixp,iy ,itnst)*dtnst + dt_warm_full(ixp,iy ,itnstp)*dtnstp
441+
dt_warm_11 = dt_warm_full(ixp,iyp,itnst)*dtnst + dt_warm_full(ixp,iyp,itnstp)*dtnstp
442+
443+
z_w_00 = z_w_full (ix ,iy ,itnst)*dtnst + z_w_full (ix ,iy ,itnstp)*dtnstp
444+
z_w_01 = z_w_full (ix ,iyp,itnst)*dtnst + z_w_full (ix ,iyp,itnstp)*dtnstp
445+
z_w_10 = z_w_full (ixp,iy ,itnst)*dtnst + z_w_full (ixp,iy ,itnstp)*dtnstp
446+
z_w_11 = z_w_full (ixp,iyp,itnst)*dtnst + z_w_full (ixp,iyp,itnstp)*dtnstp
447+
448+
! Interpolate nst variables to obs location (water surface only)
449+
450+
wgtavg = zero
451+
tr_tmp = zero
452+
dt_cool = zero
453+
z_c_tmp = zero
454+
dt_warm = zero
455+
z_w_tmp = zero
456+
457+
if (istyp00 == 0)then
458+
wgtavg = wgtavg + w00
459+
tr_tmp = tr_tmp + w00*tref_00
460+
dt_cool = dt_cool + w00*dt_cool_00
461+
z_c_tmp = z_c_tmp + w00*z_c_00
462+
dt_warm = dt_warm + w00*dt_warm_00
463+
z_w_tmp = z_w_tmp + w00*z_w_00
464+
end if
465+
if(istyp01 == 0)then
466+
wgtavg = wgtavg + w01
467+
tr_tmp = tr_tmp + w01*tref_01
468+
dt_cool = dt_cool + w01*dt_cool_01
469+
z_c_tmp = z_c_tmp + w01*z_c_01
470+
dt_warm = dt_warm + w01*dt_warm_01
471+
z_w_tmp = z_w_tmp + w01*z_w_01
472+
end if
473+
if(istyp10 == 0)then
474+
wgtavg = wgtavg + w10
475+
tr_tmp = tr_tmp + w10*tref_10
476+
dt_cool = dt_cool + w10*dt_cool_10
477+
z_c_tmp = z_c_tmp + w10*z_c_10
478+
dt_warm = dt_warm + w10*dt_warm_10
479+
z_w_tmp = z_w_tmp + w10*z_w_10
480+
end if
481+
if(istyp11 == 0)then
482+
wgtavg = wgtavg + w11
483+
tr_tmp = tr_tmp + w11*tref_11
484+
dt_cool = dt_cool + w11*dt_cool_11
485+
z_c_tmp = z_c_tmp + w11*z_c_11
486+
dt_warm = dt_warm + w11*dt_warm_11
487+
z_w_tmp = z_w_tmp + w11*z_w_11
488+
end if
489+
490+
if(wgtavg > zero)then
491+
! tr_tmp = tr_tmp/wgtavg
492+
! tref = tr_tmp
493+
494+
z_w_tmp = z_w_tmp/wgtavg
495+
z_w = z_w_tmp
496+
dt_warm = dt_warm/wgtavg
497+
498+
dt_cool = dt_cool/wgtavg
499+
z_c_tmp = z_c_tmp/wgtavg
500+
z_c = z_c_tmp
501+
502+
if(tref_00 /= 0.0_r_kind .and. &
503+
tref_01 /= 0.0_r_kind .and. &
504+
tref_10 /= 0.0_r_kind .and. &
505+
tref_11 /= 0.0_r_kind )then
506+
tr_tmp = tr_tmp/wgtavg
507+
tref = tr_tmp
508+
endif
509+
! Jacobian calculation: d(T(z))/d(Ts)
510+
511+
tz_tr = one
512+
513+
if ( (zob > z_w) .AND. (zob > z_c) ) then
514+
! should not have obs that is deeper than both z_w & z_c
515+
! once you fix sfcpt(0)- make it agree with frac water & ice in BKG,
516+
! this branch of the if loop should never be exercised.
517+
! For now, set diurnal fields to zero. SA. 02/06/2012
518+
dtc = zero
519+
dtw = zero
520+
tz_tr = zero ! gradient should NOT impact temperature analysis.
521+
! if(mype==0) WRITE(885,771) tref, ix, iy, ixp, iyp
522+
! if(mype==0) WRITE(885,771) zob, z_c, z_w, dt_cool, dt_warm
523+
else
524+
525+
if (zob .le. z_c) then
526+
dtc = (one-zob/z_c) * dt_cool ! linear T(z) profile in cool-layer
527+
dtw = dt_warm ! account for complete warm-layer temp. rise
528+
tz_tr = one
529+
! if(mype==0) WRITE(886,771) zob, z_c, z_w, dt_cool, dt_warm
530+
531+
elseif ( (zob > z_c) .and. (zob <= 0.05)) then ! z_c < zob < 5cm. That is, zob certainly corresponds to satellite measurement (IR, MW)
532+
dtc = zero ! sensor does not feel cool-layer effects.
533+
dtw = dt_warm * (one- ((zob-z_c)/(z_w-z_c))**MU_SKIN) ! ZENG & BELJAARS warm layer T(z) profile
534+
tz_tr = one ! THIS IS AN Approx. for Sattelite (MW) data. Correct way is below. --this MIGHT NEED REVISIT! 10/03/2014.
535+
536+
else ! ((zob > z_c) .AND. (zob .le. z_w))
537+
dtc = zero ! sensor does not feel cool-layer effects.
538+
dtw = dt_warm * (one- ((zob-z_c)/(z_w-z_c))**MU_SKIN) ! ZENG & BELJAARS warm layer T(z) profile
539+
tz_tr = one- ((zob-z_c)/(z_w-z_c))**MU_SKIN ! larger zob => smaller tz_tr for MU_SKIN ~0.2- 0.3. But if MU_SKIN ~1, tz_tr ~1.
540+
! Implies deeper (in water) obs do not change Ts as much. Which makes sense from an ATMOSPHERIC point of view.
541+
! if(mype==0) WRITE(887,771) zob, z_c, z_w, dt_cool, dt_warm
542+
end if
543+
! call cal_tztr_(dt_warm, dt_cool, z_c, z_w, zob, tz_tr)
544+
end if
545+
546+
end if
547+
548+
! z_c >=0 by definition. in GEOS.
549+
550+
! keep Xu Li''s code for future ref.
551+
! dtw = fac_dtl*dt_warm*(one-min(zob,z_w)/z_w)
552+
! if ( z_c > zero ) then
553+
! dtc = fac_tsl*dt_cool*(one-min(zob,z_c)/z_c)
554+
! else
555+
! dtc = zero
556+
! endif
557+
! call cal_tztr_(dt_warm, dt_cool, z_c, z_w, zob, tz_tr)
558+
!--
559+
560+
!771 FORMAT(F10.4, 2x,4I4)
561+
!771 FORMAT(E12.4, 2x, 4E12.4)
562+
end subroutine deter_nst_viirs_
563+
564+
286565
!subroutine cal_tztr_(dt_warm, dt_cool, z_c, z_w, z, tztr)
287566
!
288567
! abstract: calculate d(Tz)/d(Ts) with T-Profile info from NSST Model

GEOSaana_GridComp/GSI_GridComp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ set (SRCS_SOLVER
467467
read_anowbufr.f90
468468
read_atms.f90
469469
read_avhrr.f90
470+
read_viirs.f90
470471
read_avhrr_navy.f90
471472
read_bufrtovs.f90
472473
read_tgas.f90
@@ -661,6 +662,7 @@ set (OBJS_OPENBUFR
661662
read_atms.f90
662663
read_avhrr.f90
663664
read_avhrr_navy.f90
665+
read_viirs.f90
664666
read_bufrtovs.f90
665667
read_cris.f90
666668
read_fl_hdob.f90

GEOSaana_GridComp/GSI_GridComp/etc/gmao_global_satinfo.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4490,3 +4490,13 @@
44904490
abi_g18 14 -1 2.000 0.000 2.500 10.000 0.000 -2 -1 -1
44914491
abi_g18 15 -1 2.000 0.000 2.500 10.000 0.000 -2 -1 -1
44924492
abi_g18 16 -1 2.000 0.000 2.500 10.000 0.000 -2 -1 -1
4493+
viirs-m_npp 12 1 0.760 0.000 1.000 10.000 0.000 1 -1 -1
4494+
viirs-m_npp 13 -1 0.800 0.000 1.000 10.000 0.000 -1 -1 -1
4495+
viirs-m_npp 14 -1 0.800 0.000 1.000 10.000 0.000 -1 -1 -1
4496+
viirs-m_npp 15 1 0.580 0.000 1.000 10.000 0.000 1 -1 -1
4497+
viirs-m_npp 16 1 0.720 0.000 1.000 10.000 0.000 1 -1 -1
4498+
viirs-m_j1 12 1 0.760 0.000 1.000 10.000 0.000 1 -1 -1
4499+
viirs-m_j1 13 -1 0.800 0.000 1.000 10.000 0.000 -1 -1 -1
4500+
viirs-m_j1 14 -1 0.800 0.000 1.000 10.000 0.000 -1 -1 -1
4501+
viirs-m_j1 15 1 0.580 0.000 1.000 10.000 0.000 1 -1 -1
4502+
viirs-m_j1 16 1 0.720 0.000 1.000 10.000 0.000 1 -1 -1

GEOSaana_GridComp/GSI_GridComp/etc/gsi.rc.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ OBS_INPUT::
209209
amsr2bufr amsr2 gcom-w1 amsr2_gcom-w1 0.0 1 0 gmao_amsr2_bufr
210210
abibufr abi g16 abi_g16 0.0 1 0 ncep_goescsr_bufr
211211
abibufr abi g18 abi_g18 0.0 1 0 ncep_goescsr_bufr
212+
sstvcwbufr viirs-m npp viirs-m_npp 0.0 1 0 ncep_sstvcw_bufr
213+
sstvcwbufr viirs-m j1 viirs-m_j1 0.0 1 0 ncep_sstvcw_bufr
212214
! The following needs to be set for oneob-test:
213215
! prepqc dummy dummy dummy 1.0 1 0 test
214216
::

GEOSaana_GridComp/GSI_GridComp/etc/gsidiags.rc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ ssu_tirosn
143143
tmi_trmm
144144
abi_g16
145145
abi_g18
146+
viirs-m_npp
147+
viirs-m_j1
146148
::
147149

148150
ozlist::

GEOSaana_GridComp/GSI_GridComp/gsi_nstcouplermod.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
! 2012-03-05 SA- _full fields: tref, dt_cool, dt_warm, z_c, z_w, ... are declared here INSTEAD of satthin
1515
! 2015-05-01 Li- Change the nst fields to be single precision
1616
! 2017-09-14 LI- Change the default value to be 1 for fac_dtl & fac_tsl
17+
! 2026-05-22 a.lee Change gsi_nstcoupler_deter for viirs (needs further investigation)
1718
!
1819
!EOP
1920
!-------------------------------------------------------------------------
@@ -110,6 +111,16 @@ subroutine deter_nst_(dlat_earth,dlon_earth,obstime,zob,tref,dtw,dtc,tz_tr)
110111
real(r_kind), intent(out) :: tref,dtw,dtc,tz_tr
111112
end subroutine deter_nst_
112113
end interface
114+
115+
interface gsi_nstcoupler_deter_viirs
116+
subroutine deter_nst_viirs_(dlat_earth,dlon_earth,obstime,zob,tref,dtw,dtc,tz_tr)
117+
use kinds, only: r_kind
118+
implicit none
119+
120+
real(r_kind), intent(in ) :: dlat_earth,dlon_earth,obstime,zob
121+
real(r_kind), intent(out) :: tref,dtw,dtc,tz_tr
122+
end subroutine deter_nst_viirs_
123+
end interface
113124
!-------------------
114125

115126
contains

GEOSaana_GridComp/GSI_GridComp/gsi_obOperTypeManager.F90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ function dtype2index_(dtype) result(index_)
348348
!
349349
case("avhrr_navy"); index_= iobOper_rad
350350
case("avhrr" ); index_= iobOper_rad
351+
case("viirs-m" ); index_= iobOper_rad
351352

352353
case("tcp" ,"[tcpoper]" ); index_= iobOper_tcp
353354

0 commit comments

Comments
 (0)