@@ -283,6 +283,285 @@ subroutine deter_nst_(dlat_earth,dlon_earth,obstime,zob,tref,dtw,dtc,tz_tr)
283283end 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
0 commit comments