PageRenderTime 74ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/wrfv2_fire/phys/module_fddaobs_rtfdda.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 2978 lines | 1716 code | 378 blank | 884 comment | 137 complexity | 951b09af3ef210354f9fd397a7ef6ab5 MD5 | raw file
Possible License(s): AGPL-1.0
  1. !WRF:MODEL_LAYER:PHYSICS
  2. !
  3. MODULE module_fddaobs_rtfdda
  4. ! This obs-nudging FDDA module (RTFDDA) is developed by the
  5. ! NCAR/RAL/NSAP (National Security Application Programs), under the
  6. ! sponsorship of ATEC (Army Test and Evaluation Commands). ATEC is
  7. ! acknowledged for releasing this capability for WRF community
  8. ! research applications.
  9. !
  10. ! The NCAR/RAL RTFDDA module was adapted, and significantly modified
  11. ! from the obs-nudging module in the standard MM5V3.1 which was originally
  12. ! developed by PSU (Stauffer and Seaman, 1994).
  13. !
  14. ! Yubao Liu (NCAR/RAL): lead developer of the RTFDDA module
  15. ! Al Bourgeois (NCAR/RAL): lead engineer implementing RTFDDA into WRF-ARW
  16. ! Nov. 2006
  17. !
  18. ! References:
  19. !
  20. ! Liu, Y., A. Bourgeois, T. Warner, S. Swerdlin and J. Hacker, 2005: An
  21. ! implementation of obs-nudging-based FDDA into WRF for supporting
  22. ! ATEC test operations. 2005 WRF user workshop. Paper 10.7.
  23. !
  24. ! Liu, Y., A. Bourgeois, T. Warner, S. Swerdlin and W. Yu, 2006: An update
  25. ! on "obs-nudging"-based FDDA for WRF-ARW: Verification using OSSE
  26. ! and performance of real-time forecasts. 2006 WRF user workshop. Paper 4.7.
  27. !
  28. ! Stauffer, D.R., and N.L. Seaman, 1994: Multi-scale four-dimensional data
  29. ! assimilation. J. Appl. Meteor., 33, 416-434.
  30. !
  31. ! http://www.rap.ucar.edu/projects/armyrange/references.html
  32. !
  33. ! Modification History:
  34. ! 03212007 Modified fddaobs_init to compute Lambert cone factor. -Al Bourgeois
  35. CONTAINS
  36. !------------------------------------------------------------------------------
  37. SUBROUTINE fddaobs_init(nudge_opt, maxdom, inest, parid, &
  38. idynin, dtramp, fdaend, restart, &
  39. twindo_cg, twindo, itimestep, &
  40. no_pbl_nudge_uv, &
  41. no_pbl_nudge_t, &
  42. no_pbl_nudge_q, &
  43. sfc_scheme_horiz, sfc_scheme_vert, &
  44. maxsnd_gap, &
  45. sfcfact, sfcfacr, dpsmx, &
  46. nudge_wind, nudge_temp, nudge_mois, &
  47. nudgezfullr1_uv, nudgezrampr1_uv, &
  48. nudgezfullr2_uv, nudgezrampr2_uv, &
  49. nudgezfullr4_uv, nudgezrampr4_uv, &
  50. nudgezfullr1_t, nudgezrampr1_t, &
  51. nudgezfullr2_t, nudgezrampr2_t, &
  52. nudgezfullr4_t, nudgezrampr4_t, &
  53. nudgezfullr1_q, nudgezrampr1_q, &
  54. nudgezfullr2_q, nudgezrampr2_q, &
  55. nudgezfullr4_q, nudgezrampr4_q, &
  56. nudgezfullmin, nudgezrampmin, nudgezmax, &
  57. xlat, xlong, &
  58. start_year, start_month, start_day, &
  59. start_hour, start_minute, start_second, &
  60. p00, t00, tlp, &
  61. znu, p_top, &
  62. #if ( EM_CORE == 1 )
  63. fdob, &
  64. #endif
  65. iprt, &
  66. ids,ide, jds,jde, kds,kde, &
  67. ims,ime, jms,jme, kms,kme, &
  68. its,ite, jts,jte, kts,kte)
  69. !-----------------------------------------------------------------------
  70. ! This routine does initialization for real time fdda obs-nudging.
  71. !
  72. !-----------------------------------------------------------------------
  73. USE module_model_constants, ONLY : g, r_d
  74. USE module_domain
  75. USE module_dm, ONLY : wrf_dm_min_real
  76. !-----------------------------------------------------------------------
  77. IMPLICIT NONE
  78. !-----------------------------------------------------------------------
  79. !=======================================================================
  80. ! Definitions
  81. !-----------
  82. INTEGER, intent(in) :: maxdom
  83. INTEGER, intent(in) :: nudge_opt(maxdom)
  84. INTEGER, intent(in) :: ids,ide, jds,jde, kds,kde, &
  85. ims,ime, jms,jme, kms,kme, &
  86. its,ite, jts,jte, kts,kte
  87. INTEGER, intent(in) :: inest
  88. INTEGER, intent(in) :: parid(maxdom)
  89. INTEGER, intent(in) :: idynin ! flag for dynamic initialization
  90. REAL, intent(in) :: dtramp ! time period for idynin ramping (min)
  91. REAL, intent(in) :: fdaend(maxdom) ! nudging end time for domain (min)
  92. LOGICAL, intent(in) :: restart
  93. REAL, intent(in) :: twindo_cg ! time window on coarse grid
  94. REAL, intent(in) :: twindo
  95. INTEGER, intent(in) :: itimestep
  96. INTEGER , INTENT(IN) :: no_pbl_nudge_uv(maxdom) ! flags for no wind nudging in pbl
  97. INTEGER , INTENT(IN) :: no_pbl_nudge_t(maxdom) ! flags for no temperature nudging in pbl
  98. INTEGER , INTENT(IN) :: no_pbl_nudge_q(maxdom) ! flags for no moisture nudging in pbl
  99. INTEGER , INTENT(IN) :: sfc_scheme_horiz ! horizontal spreading scheme for surf obs (wrf or orig mm5)
  100. INTEGER , INTENT(IN) :: sfc_scheme_vert ! vertical spreading scheme for surf obs (orig or regime vif)
  101. REAL , INTENT(IN) :: maxsnd_gap ! max allowed pressure gap in soundings, for interp (centibars)
  102. REAL, intent(in) :: sfcfact ! scale factor applied to time window for surface obs
  103. REAL, intent(in) :: sfcfacr ! scale fac applied to horiz rad of infl for sfc obs
  104. REAL, intent(in) :: dpsmx ! max press change allowed within hor rad of infl
  105. INTEGER , INTENT(IN) :: nudge_wind(maxdom) ! wind-nudging flag
  106. INTEGER , INTENT(IN) :: nudge_temp(maxdom) ! temperature-nudging flag
  107. INTEGER , INTENT(IN) :: nudge_mois(maxdom) ! moisture-nudging flag
  108. REAL, INTENT(IN) :: nudgezfullr1_uv ! vert infl fcn, regime=1 full-wt hght, winds
  109. REAL, INTENT(IN) :: nudgezrampr1_uv ! vert infl fcn, regime=1 ramp down hght, winds
  110. REAL, INTENT(IN) :: nudgezfullr2_uv ! vert infl fcn, regime=2 full-wt hght, winds
  111. REAL, INTENT(IN) :: nudgezrampr2_uv ! vert infl fcn, regime=2 ramp down hght, winds
  112. REAL, INTENT(IN) :: nudgezfullr4_uv ! vert infl fcn, regime=4 full-wt hght, winds
  113. REAL, INTENT(IN) :: nudgezrampr4_uv ! vert infl fcn, regime=4 ramp down hght, winds
  114. REAL, INTENT(IN) :: nudgezfullr1_t ! vert infl fcn, regime=1 full-wt hght, temp
  115. REAL, INTENT(IN) :: nudgezrampr1_t ! vert infl fcn, regime=1 ramp down hght, temp
  116. REAL, INTENT(IN) :: nudgezfullr2_t ! vert infl fcn, regime=2 full-wt hght, temp
  117. REAL, INTENT(IN) :: nudgezrampr2_t ! vert infl fcn, regime=2 ramp down hght, temp
  118. REAL, INTENT(IN) :: nudgezfullr4_t ! vert infl fcn, regime=4 full-wt hght, temp
  119. REAL, INTENT(IN) :: nudgezrampr4_t ! vert infl fcn, regime=4 ramp down hght, temp
  120. REAL, INTENT(IN) :: nudgezfullr1_q ! vert infl fcn, regime=1 full-wt hght, mois
  121. REAL, INTENT(IN) :: nudgezrampr1_q ! vert infl fcn, regime=1 ramp down hght, mois
  122. REAL, INTENT(IN) :: nudgezfullr2_q ! vert infl fcn, regime=2 full-wt hght, mois
  123. REAL, INTENT(IN) :: nudgezrampr2_q ! vert infl fcn, regime=2 ramp down hght, mois
  124. REAL, INTENT(IN) :: nudgezfullr4_q ! vert infl fcn, regime=4 full-wt hght, mois
  125. REAL, INTENT(IN) :: nudgezrampr4_q ! vert infl fcn, regime=4 ramp down hght, mois
  126. REAL, INTENT(IN) :: nudgezfullmin ! min dpth thru which vert infl fcn remains 1.0 (m)
  127. REAL, INTENT(IN) :: nudgezrampmin ! min dpth thru which vif decreases 1.0 to 0.0 (m)
  128. REAL, INTENT(IN) :: nudgezmax ! max dpth in which vif is nonzero (m)
  129. REAL, INTENT(IN) :: xlat ( ims:ime, jms:jme ) ! latitudes on mass-point grid
  130. REAL, INTENT(IN) :: xlong( ims:ime, jms:jme ) ! longitudes on mass-point grid
  131. INTEGER, intent(in) :: start_year ! Model start year
  132. INTEGER, intent(in) :: start_month ! Model start month
  133. INTEGER, intent(in) :: start_day ! Model start day
  134. INTEGER, intent(in) :: start_hour ! Model start hour
  135. INTEGER, intent(in) :: start_minute ! Model start minute
  136. INTEGER, intent(in) :: start_second ! Model start second
  137. REAL, INTENT(IN) :: p00 ! base state pressure
  138. REAL, INTENT(IN) :: t00 ! base state temperature
  139. REAL, INTENT(IN) :: tlp ! base state lapse rate
  140. REAL, INTENT(IN) :: p_top ! pressure at top of model
  141. REAL, INTENT(IN) :: znu( kms:kme ) ! eta values on half (mass) levels
  142. #if ( EM_CORE == 1 )
  143. TYPE(fdob_type), intent(inout) :: fdob
  144. #endif
  145. LOGICAL, intent(in) :: iprt ! Flag enabling printing warning messages
  146. ! Local variables
  147. logical :: nudge_flag ! nudging flag for this nest
  148. integer :: ktau ! current timestep
  149. integer :: nest ! loop counter
  150. integer :: idom ! domain id
  151. integer :: parent ! parent domain
  152. real :: conv ! 180/pi
  153. real :: tl1 ! Lambert standard parallel 1
  154. real :: tl2 ! Lambert standard parallel 2
  155. real :: xn1
  156. real :: known_lat ! Latitude of domain point (i,j)=(1,1)
  157. real :: known_lon ! Longitude of domain point (i,j)=(1,1)
  158. character(len=200) :: msg ! Argument to wrf_message
  159. real :: z_at_p( kms:kme ) ! height at p levels
  160. integer :: i,j,k ! loop counters
  161. #if ( EM_CORE == 1 )
  162. ! Check to see if the nudging flag has been set. If not,
  163. ! simply RETURN.
  164. nudge_flag = (nudge_opt(inest) .eq. 1)
  165. if (.not. nudge_flag) return
  166. call wrf_message("")
  167. write(msg,fmt='(a,i2)') ' OBSERVATION NUDGING IS ACTIVATED FOR MESH ',inest
  168. call wrf_message(msg)
  169. ktau = itimestep
  170. if(restart) then
  171. fdob%ktaur = ktau
  172. else
  173. fdob%ktaur = 0
  174. endif
  175. ! Create character string containing model starting-date
  176. CALL date_string(start_year, start_month, start_day, start_hour, &
  177. start_minute, start_second, fdob%sdate)
  178. ! Set flag for nudging on pressure (not sigma) surfaces.
  179. fdob%iwtsig = 0
  180. !**************************************************************************
  181. ! *** Initialize datend for dynamic initialization (ajb added 08132008) ***
  182. !**************************************************************************
  183. ! Set ending nudging date (used with dynamic ramp-down) to zero.
  184. fdob%datend = 0.
  185. fdob%ieodi = 0
  186. ! Check for dynamic initialization flag
  187. if(idynin.eq.1)then
  188. ! Set datend to time in minutes after which data are assumed to have ended.
  189. if(dtramp.gt.0.)then
  190. fdob%datend = fdaend(inest) - dtramp
  191. else
  192. fdob%datend = fdaend(inest)
  193. endif
  194. if(iprt) then
  195. call wrf_message("")
  196. write(msg,fmt='(a,i3,a)') &
  197. ' *** DYNAMIC-INITIALIZATION OPTION FOR INEST = ', inest, ' ***'
  198. call wrf_message(msg)
  199. write(msg,*) ' FDAEND,DATEND,DTRAMP: ',fdaend(inest),fdob%datend,dtramp
  200. call wrf_message(msg)
  201. call wrf_message("")
  202. endif
  203. endif
  204. ! *** end dynamic initialization section ***
  205. !**************************************************************************
  206. ! Store flags for surface obs spreading schemes
  207. if(sfc_scheme_horiz.eq.1) then
  208. call wrf_message('MM5 scheme selected for horizontal spreading of surface obs')
  209. elseif (sfc_scheme_horiz.eq.0) then
  210. call wrf_message('WRF scheme selected for horizontal spreading of surface obs')
  211. else
  212. write(msg,fmt='(a,i3)') 'Unknown h-spreading scheme for surface obs: ',sfc_scheme_horiz
  213. call wrf_message(msg)
  214. call wrf_message("Valid selections: 0=WRF scheme, 1=Original MM5 scheme")
  215. call wrf_error_fatal ( 'fddaobs_init: module_fddaobs_rtfdda STOP' )
  216. endif
  217. if(sfc_scheme_vert.eq.1) then
  218. call wrf_message('Original simple scheme selected for vertical spreading of surface obs')
  219. elseif (sfc_scheme_vert.eq.0) then
  220. call wrf_message("Regime-based VIF scheme selected for vertical spreading of surface obs")
  221. else
  222. write(msg,fmt='(a,i3)') 'Unknown v-spreading scheme for surface obs: ',sfc_scheme_vert
  223. call wrf_message(msg)
  224. call wrf_message("Valid selections: 0=Regime-based VIF scheme, 1=Original simple scheme")
  225. call wrf_error_fatal ( 'fddaobs_init: module_fddaobs_rtfdda STOP' )
  226. endif
  227. fdob%sfc_scheme_horiz = sfc_scheme_horiz
  228. fdob%sfc_scheme_vert = sfc_scheme_vert
  229. ! Store temporal and spatial scales
  230. fdob%sfcfact = sfcfact
  231. fdob%sfcfacr = sfcfacr
  232. ! Set time window.
  233. fdob%window = twindo
  234. call wrf_message("")
  235. write(msg,fmt='(a,i3)') '*** TIME WINDOW SETTINGS FOR NEST ',inest
  236. call wrf_message(msg)
  237. write(msg,fmt='(a,f6.3,2(a,f5.3))') ' TWINDO (hrs) = ',twindo, &
  238. ' SFCFACT = ',sfcfact,' SFCFACR = ',sfcfacr
  239. call wrf_message(msg)
  240. call wrf_message("")
  241. if(inest.eq.1) then
  242. if(twindo .eq. 0.) then
  243. if(iprt) then
  244. call wrf_message("")
  245. write(msg,*) '*** WARNING: TWINDO=0 on the coarse domain.'
  246. call wrf_message(msg)
  247. write(msg,*) '*** Did you forget to set twindo in the fdda namelist?'
  248. call wrf_message(msg)
  249. call wrf_message("")
  250. endif
  251. endif
  252. else ! nest
  253. if(twindo .eq. 0.) then
  254. fdob%window = twindo_cg
  255. if(iprt) then
  256. call wrf_message("")
  257. write(msg,fmt='(a,i2)') 'WARNING: TWINDO=0. for nest ',inest
  258. call wrf_message(msg)
  259. write(msg,fmt='(a,f12.5,a)') 'Default to coarse-grid value of ', twindo_cg,' hrs'
  260. call wrf_message(msg)
  261. call wrf_message("")
  262. endif
  263. endif
  264. endif
  265. ! Initialize flags.
  266. fdob%domain_tot=0
  267. do nest=1,maxdom
  268. fdob%domain_tot = fdob%domain_tot + nudge_opt(nest)
  269. end do
  270. ! Calculate and store dcon from dpsmx
  271. if(dpsmx.gt.0.) then
  272. fdob%dpsmx = dpsmx
  273. fdob%dcon = 1.0/fdob%dpsmx
  274. else
  275. call wrf_error_fatal('fddaobs_init: Namelist variable dpsmx must be greater than zero!')
  276. endif
  277. ! Calculate and store base-state heights at half (mass) levels.
  278. CALL get_base_state_height_column( p_top, p00, t00, tlp, g, r_d, znu, &
  279. fdob%base_state, kts, kte, kds,kde, kms,kme )
  280. ! Initialize flags for nudging within PBL.
  281. fdob%nudge_uv_pbl = .true.
  282. fdob%nudge_t_pbl = .true.
  283. fdob%nudge_q_pbl = .true.
  284. if(no_pbl_nudge_uv(inest) .eq. 1) fdob%nudge_uv_pbl = .false.
  285. if(no_pbl_nudge_t(inest) .eq. 1) fdob%nudge_t_pbl = .false.
  286. if(no_pbl_nudge_q(inest) .eq. 1) fdob%nudge_q_pbl = .false.
  287. if(no_pbl_nudge_uv(inest) .eq. 1) then
  288. fdob%nudge_uv_pbl = .false.
  289. write(msg,*) ' --> Obs nudging for U/V is turned off in PBL'
  290. call wrf_message(msg)
  291. endif
  292. if(no_pbl_nudge_t(inest) .eq. 1) then
  293. fdob%nudge_t_pbl = .false.
  294. write(msg,*) ' --> Obs nudging for T is turned off in PBL'
  295. call wrf_message(msg)
  296. endif
  297. if(no_pbl_nudge_q(inest) .eq. 1) then
  298. fdob%nudge_q_pbl = .false.
  299. write(msg,*) ' --> Obs nudging for Q is turned off in PBL'
  300. call wrf_message(msg)
  301. endif
  302. ! Store max allowed pressure gap for interpolating between soundings
  303. fdob%max_sndng_gap = maxsnd_gap
  304. write(msg,fmt='(a,f6.1)') &
  305. '*** MAX PRESSURE GAP (cb) for interpolation between soundings = ',maxsnd_gap
  306. call wrf_message(msg)
  307. call wrf_message("")
  308. ! Initialize vertical influence fcn for LML obs
  309. if(sfc_scheme_vert.eq.0) then
  310. fdob%vif_uv(1) = nudgezfullr1_uv
  311. fdob%vif_uv(2) = nudgezrampr1_uv
  312. fdob%vif_uv(3) = nudgezfullr2_uv
  313. fdob%vif_uv(4) = nudgezrampr2_uv
  314. fdob%vif_uv(5) = nudgezfullr4_uv
  315. fdob%vif_uv(6) = nudgezrampr4_uv
  316. fdob%vif_t (1) = nudgezfullr1_t
  317. fdob%vif_t (2) = nudgezrampr1_t
  318. fdob%vif_t (3) = nudgezfullr2_t
  319. fdob%vif_t (4) = nudgezrampr2_t
  320. fdob%vif_t (5) = nudgezfullr4_t
  321. fdob%vif_t (6) = nudgezrampr4_t
  322. fdob%vif_q (1) = nudgezfullr1_q
  323. fdob%vif_q (2) = nudgezrampr1_q
  324. fdob%vif_q (3) = nudgezfullr2_q
  325. fdob%vif_q (4) = nudgezrampr2_q
  326. fdob%vif_q (5) = nudgezfullr4_q
  327. fdob%vif_q (6) = nudgezrampr4_q
  328. ! Sanity checks
  329. if(nudgezmax.le.0.) then
  330. write(msg,*) 'STOP! OBS NAMELIST INPUT obs_nudgezmax MUST BE GREATER THAN ZERO.'
  331. call wrf_message(msg)
  332. write(msg,*) 'THE NAMELIST VALUE IS',nudgezmax
  333. call wrf_message(msg)
  334. call wrf_error_fatal ( 'fddaobs_init: STOP on bad obs_nudgemax value' )
  335. endif
  336. if(nudgezfullmin.lt.0.) then
  337. write(msg,*) 'STOP! OBS NAMELIST INPUT obs_nudgezfullmin MUST BE NONNEGATIVE.'
  338. call wrf_message(msg)
  339. write(msg,*) 'THE NAMELIST VALUE IS',nudgezfullmin
  340. call wrf_message(msg)
  341. call wrf_error_fatal ( 'fddaobs_init: STOP on bad obs_nudgefullmin value' )
  342. endif
  343. if(nudgezrampmin.lt.0.) then
  344. write(msg,*) 'STOP! OBS NAMELIST INPUT obs_nudgezrampmin MUST BE NONNEGATIVE.'
  345. call wrf_message(msg)
  346. write(msg,*) 'THE NAMELIST VALUE IS',nudgezrampmin
  347. call wrf_message(msg)
  348. call wrf_error_fatal ( 'fddaobs_init: STOP on bad obs_nudgerampmin value' )
  349. endif
  350. if(nudgezmax.lt.nudgezfullmin+nudgezrampmin) then
  351. write(msg,*) 'STOP! INCONSISTENT OBS NAMELIST INPUTS.'
  352. call wrf_message(msg)
  353. write(msg,fmt='(3(a,f12.3))') 'obs_nudgezmax = ',nudgezmax, &
  354. ' obs_nudgezfullmin = ',nudgezfullmin, &
  355. ' obs_nudgezrampmin = ',nudgezrampmin
  356. call wrf_message(msg)
  357. write(msg,*) 'REQUIRE NUDGEZMAX >= NUDGEZFULLMIN + NUDGEZRAMPMIN'
  358. call wrf_message(msg)
  359. call wrf_error_fatal ( 'fddaobs_init: STOP on inconsistent namelist values' )
  360. endif
  361. fdob%vif_fullmin = nudgezfullmin
  362. fdob%vif_rampmin = nudgezrampmin
  363. fdob%vif_max = nudgezmax
  364. ! Check to make sure that if nudgzfullmin > 0, then it must be at least as large as the
  365. ! first model half-level will be anywhere in the domain at any time within the simulation.
  366. ! We use 1.1 times the base-state value fdob%base_state(1) for this purpose.
  367. if(nudgezfullmin.gt.0.0) then
  368. if(nudgezfullmin .lt. 1.1*fdob%base_state(1)) then
  369. fdob%vif_fullmin = 1.1*fdob%base_state(1)
  370. endif
  371. endif
  372. ! Print vertical weight info only if wind, temperature, or moisture nudging is requested.
  373. if( (nudge_wind(inest).eq.1) .or. (nudge_temp(inest).eq.1) &
  374. .or. (nudge_mois(inest).eq.1) ) then
  375. call wrf_message("")
  376. write(msg,fmt='(a,i2,a)') ' *** SETUP DESCRIPTION FOR SURFACE OBS NUDGING ON MESH ',inest,' :'
  377. call wrf_message(msg)
  378. call wrf_message("")
  379. write(msg,fmt='(a,i5,a)') ' NUDGEZMAX: The maximum height at which nudging will be'// &
  380. ' applied from surface obs is ', nint(nudgezmax),' m AGL.'
  381. call wrf_message(msg)
  382. call wrf_message("")
  383. write(msg,fmt='(a,i3,a)') ' NUDGEZFULLMIN: The minimum height of full nudging weight'// &
  384. ' for surface obs is ', nint(fdob%vif_fullmin),' m.'
  385. call wrf_message(msg)
  386. if(nudgezfullmin.lt.fdob%vif_fullmin) then
  387. write(msg,fmt='(a,i3,a)') ' ***WARNING***: NUDGEZFULLMIN has been increased from'// &
  388. ' the user-input value of ',nint(nudgezfullmin),' m.'
  389. call wrf_message(msg)
  390. write(msg,fmt='(a,i3,a)') ' to ensure that at least the bottom model level is'// &
  391. ' included in full nudging.'
  392. call wrf_message(msg)
  393. endif
  394. call wrf_message("")
  395. write(msg,fmt='(a,i3,a)') ' NUDGEZRAMPMIN: The minimum height to ramp from full to no'// &
  396. ' nudging for surface obs is ', nint(nudgezrampmin),' m.'
  397. call wrf_message(msg)
  398. call wrf_message("")
  399. endif !endif either wind, temperature, or moisture nudging is requested
  400. ! Print vif settings
  401. if(nudge_wind(inest) .eq. 1) then
  402. call print_vif_var('wind', fdob%vif_uv, nudgezfullmin, nudgezrampmin)
  403. call wrf_message("")
  404. endif
  405. if(nudge_temp(inest) .eq. 1) then
  406. call print_vif_var('temp', fdob%vif_t, nudgezfullmin, nudgezrampmin)
  407. call wrf_message("")
  408. endif
  409. if(nudge_mois(inest) .eq. 1) then
  410. call print_vif_var('mois', fdob%vif_q, nudgezfullmin, nudgezrampmin)
  411. call wrf_message("")
  412. endif
  413. if( (nudge_wind(inest).eq.1) .or. (nudge_temp(inest).eq.1) &
  414. .or. (nudge_mois(inest).eq.1) ) then
  415. write(msg,fmt='(a,i2)') ' *** END SETUP DESCRIPTION FOR SURFACE OBS NUDGING ON MESH ',inest
  416. call wrf_message(msg)
  417. call wrf_message("")
  418. endif
  419. endif !endif(sfc_scheme_vert.EQ.0)
  420. ! Set parameters.
  421. fdob%pfree = 50.0
  422. fdob%rinfmn = 1.0
  423. fdob%rinfmx = 2.0
  424. ! Get known lat and lon and store these on all processors in fdob structure, for
  425. ! later use in projection x-formation to map (lat,lon) to (x,y) for each obs.
  426. IF (its .eq. 1 .AND. jts .eq. 1) then
  427. known_lat = xlat(1,1)
  428. known_lon = xlong(1,1)
  429. ELSE
  430. known_lat = 9999.
  431. known_lon = 9999.
  432. END IF
  433. fdob%known_lat = wrf_dm_min_real(known_lat)
  434. fdob%known_lon = wrf_dm_min_real(known_lon)
  435. ! Calculate the nest levels, levidn. Note that each nest
  436. ! must know the nest levels levidn(maxdom) of each domain.
  437. do nest=1,maxdom
  438. ! Initialize nest level for each domain.
  439. if (nest .eq. 1) then
  440. fdob%levidn(nest) = 0 ! Mother domain has nest level 0
  441. else
  442. fdob%levidn(nest) = 1 ! All other domains start with 1
  443. endif
  444. idom = nest
  445. 100 parent = parid(idom) ! Go up the parent tree
  446. if (parent .gt. 1) then ! If not up to mother domain
  447. fdob%levidn(nest) = fdob%levidn(nest) + 1
  448. idom = parent
  449. goto 100
  450. endif
  451. enddo
  452. ! fdob%LML_OBS_HT1_LEV = kte
  453. ! HT1: do k = kte, kts, -1
  454. ! if( LML_HT1 .gt. z_at_p(k) ) then
  455. ! fdob%LML_OBS_HT1_LEV = k
  456. ! EXIT HT1
  457. ! endif
  458. ! enddo HT1
  459. ! fdob%LML_OBS_HT2_LEV = kte
  460. ! HT2: do k = kte, kts, -1
  461. ! if( LML_HT2 .gt. z_at_p(k) ) then
  462. ! fdob%LML_OBS_HT2_LEV = k
  463. ! EXIT HT2
  464. ! endif
  465. ! enddo HT2
  466. RETURN
  467. #endif
  468. END SUBROUTINE fddaobs_init
  469. #if ( EM_CORE == 1 )
  470. !-----------------------------------------------------------------------
  471. SUBROUTINE errob(inest, ub, vb, tb, t0, qvb, pbase, pp, rovcp, &
  472. z, &
  473. uratx, vratx, tratx, kpbl, &
  474. nndgv, nerrf, niobf, maxdom, &
  475. levidn, parid, nstat, nstaw, &
  476. iswind, istemp, ismois, ispstr, &
  477. timeob, rio, rjo, rko, &
  478. varobs, errf, ktau, xtime, &
  479. iratio, npfi, &
  480. prt_max, prt_freq, iprt, &
  481. obs_prt, stnid_prt, lat_prt, lon_prt, &
  482. mlat_prt, mlon_prt, &
  483. ids,ide, jds,jde, kds,kde, &
  484. ims,ime, jms,jme, kms,kme, &
  485. its,ite, jts,jte, kts,kte )
  486. !-----------------------------------------------------------------------
  487. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  488. USE module_dm, ONLY : get_full_obs_vector, wrf_dm_sum_real
  489. #else
  490. USE module_dm, ONLY : wrf_dm_sum_real
  491. #endif
  492. USE module_model_constants, ONLY : rcp
  493. !-----------------------------------------------------------------------
  494. IMPLICIT NONE
  495. !-----------------------------------------------------------------------
  496. !
  497. ! PURPOSE: THIS SUBROUTINE CALCULATES THE DIFFERENCE BETWEEN THE
  498. ! OBSERVED VALUES AND THE FORECAST VALUES AT THE OBSERVATION
  499. ! POINTS. THE OBSERVED VALUES CLOSEST TO THE CURRENT
  500. ! FORECAST TIME (XTIME) WERE DETERMINED IN SUBROUTINE
  501. ! IN4DOB AND STORED IN ARRAY VAROBS. THE DIFFERENCES
  502. ! CALCULATED BY SUBROUTINE ERROB WILL BE STORED IN ARRAY
  503. ! ERRF FOR THE NSTA OBSERVATION LOCATIONS. MISSING
  504. ! OBSERVATIONS ARE DENOTED BY THE DUMMY VALUE 99999.
  505. !
  506. ! HISTORY: Original author: MM5 version???
  507. ! 02/04/2004 - Creation of WRF version. Al Bourgeois
  508. ! 08/28/2006 - Conversion from F77 to F90 Al Bourgeois
  509. !------------------------------------------------------------------------------
  510. ! THE STORAGE ORDER IN ERRF IS AS FOLLOWS:
  511. ! IVAR VARIABLE TYPE(TAU-1)
  512. ! ---- --------------------
  513. ! 1 U error at obs loc
  514. ! 2 V error at obs loc
  515. ! 3 T error at obs loc
  516. ! 4 Q error at obs loc
  517. ! 5 Vertical layer index for PBL top at IOB, JOB
  518. ! 6 Model surface press at obs loc (T-points)
  519. ! 7 Model surface press at obs loc (U-points)
  520. ! 8 Model surface press at obs loc (V-points)
  521. ! 9 RKO at U-points
  522. !-----------------------------------------------------------------------
  523. !
  524. ! Description of input arguments.
  525. !
  526. !-----------------------------------------------------------------------
  527. INTEGER, INTENT(IN) :: inest ! Domain index.
  528. INTEGER, INTENT(IN) :: nndgv ! Number of nudge variables.
  529. INTEGER, INTENT(IN) :: nerrf ! Number of error fields.
  530. INTEGER, INTENT(IN) :: niobf ! Number of observations.
  531. INTEGER, INTENT(IN) :: maxdom ! Maximum number of domains.
  532. INTEGER, INTENT(IN) :: levidn(maxdom) ! Level of nest.
  533. INTEGER, INTENT(IN) :: parid(maxdom) ! Id of parent grid.
  534. INTEGER, INTENT(IN) :: ktau ! Model time step index
  535. REAL, INTENT(IN) :: xtime ! Forecast time in minutes
  536. INTEGER, INTENT(IN) :: iratio ! Nest to parent gridsize ratio.
  537. INTEGER, INTENT(IN) :: npfi ! Coarse-grid diagnostics freq.
  538. INTEGER, INTENT(IN) :: prt_max ! Max number of obs to print.
  539. INTEGER, INTENT(IN) :: prt_freq ! Frequency of obs to print.
  540. LOGICAL, INTENT(IN) :: iprt ! Print flag
  541. INTEGER, INTENT(IN) :: obs_prt(prt_max) ! Print obs indices
  542. INTEGER, INTENT(IN) :: stnid_prt(40,prt_max) ! Print obs station ids
  543. REAL, INTENT(IN) :: lat_prt(prt_max) ! Print obs latitude
  544. REAL, INTENT(IN) :: lon_prt(prt_max) ! Print obs longitude
  545. REAL, INTENT(IN) :: mlat_prt(prt_max) ! Print model lat at obs loc
  546. REAL, INTENT(IN) :: mlon_prt(prt_max) ! Print model lon at obs loc
  547. INTEGER, INTENT(IN) :: nstat ! # stations held for use
  548. INTEGER, INTENT(IN) :: nstaw ! # stations in current window
  549. INTEGER, intent(in) :: iswind
  550. INTEGER, intent(in) :: istemp
  551. INTEGER, intent(in) :: ismois
  552. INTEGER, intent(in) :: ispstr
  553. INTEGER, INTENT(IN) :: ids,ide, jds,jde, kds,kde ! domain dims.
  554. INTEGER, INTENT(IN) :: ims,ime, jms,jme, kms,kme ! memory dims.
  555. INTEGER, INTENT(IN) :: its,ite, jts,jte, kts,kte ! tile dims.
  556. REAL, INTENT(IN) :: ub( ims:ime, kms:kme, jms:jme )
  557. REAL, INTENT(IN) :: vb( ims:ime, kms:kme, jms:jme )
  558. REAL, INTENT(IN) :: tb( ims:ime, kms:kme, jms:jme )
  559. REAL, INTENT(IN) :: t0
  560. REAL, INTENT(IN) :: qvb( ims:ime, kms:kme, jms:jme )
  561. REAL, INTENT(IN) :: pbase( ims:ime, kms:kme, jms:jme )
  562. REAL, INTENT(IN) :: pp( ims:ime, kms:kme, jms:jme ) ! Press. perturbation (Pa)
  563. REAL, INTENT(IN) :: rovcp
  564. REAL, INTENT(IN) :: z( ims:ime, kms:kme, jms:jme ) ! Ht above sl on half-levels
  565. REAL, INTENT(IN) :: uratx( ims:ime, jms:jme ) ! U to U10 ratio on mass points.
  566. REAL, INTENT(IN) :: vratx( ims:ime, jms:jme ) ! V to V10 ratio on mass points.
  567. REAL, INTENT(IN) :: tratx( ims:ime, jms:jme ) ! T to TH2 ratio on mass points.
  568. INTEGER,INTENT(IN) :: kpbl( ims:ime, jms:jme ) ! Vertical layer index for PBL top
  569. REAL, INTENT(IN) :: timeob(niobf) ! Obs time (hrs)
  570. REAL, INTENT(IN) :: rio(niobf) ! Obs west-east coordinate (non-stag grid).
  571. REAL, INTENT(IN) :: rjo(niobf) ! Obs south-north coordinate (non-stag grid).
  572. REAL, INTENT(INOUT) :: rko(niobf) ! Obs bottom-top coordinate
  573. REAL, INTENT(INOUT) :: varobs(nndgv, niobf)
  574. REAL, INTENT(INOUT) :: errf(nerrf, niobf)
  575. ! Local variables
  576. INTEGER :: iobmg(niobf) ! Obs i-coord on mass grid
  577. INTEGER :: jobmg(niobf) ! Obs j-coord on mass grid
  578. INTEGER :: ia(niobf)
  579. INTEGER :: ib(niobf)
  580. INTEGER :: ic(niobf)
  581. REAL :: pbbo(kds:kde) ! column base pressure (cb) at obs loc.
  582. REAL :: ppbo(kds:kde) ! column pressure perturbation (cb) at obs loc.
  583. REAL :: ra(niobf)
  584. REAL :: rb(niobf)
  585. REAL :: rc(niobf)
  586. REAL :: dxobmg(niobf) ! Interp. fraction (x dir) referenced to mass-grid
  587. REAL :: dyobmg(niobf) ! Interp. fraction (y dir) referenced to mass-grid
  588. INTEGER MM(MAXDOM)
  589. INTEGER NNL
  590. real :: uratio( ims:ime, jms:jme ) ! U to U10 ratio on momentum points.
  591. real :: vratio( ims:ime, jms:jme ) ! V to V10 ratio on momentum points.
  592. real :: pug1,pug2,pvg1,pvg2
  593. character(len=200) :: msg ! Argument to wrf_message
  594. ! Define staggers for U, V, and T grids, referenced from non-staggered grid.
  595. real, parameter :: gridx_t = 0.5 ! Mass-point x stagger
  596. real, parameter :: gridy_t = 0.5 ! Mass-point y stagger
  597. real, parameter :: gridx_u = 0.0 ! U-point x stagger
  598. real, parameter :: gridy_u = 0.5 ! U-point y stagger
  599. real, parameter :: gridx_v = 0.5 ! V-point x stagger
  600. real, parameter :: gridy_v = 0.0 ! V-point y stagger
  601. real :: dummy = 99999.
  602. real :: pbhi, pphi
  603. real :: obs_pottemp ! Potential temperature at observation
  604. !*** DECLARATIONS FOR IMPLICIT NONE
  605. integer nsta,ivar,n,ityp
  606. integer iob,job,kob,iob_ms,job_ms
  607. integer k,kbot,nml,nlb,nle
  608. integer iobm,jobm,iobp,jobp,kobp,inpf,i,j
  609. integer i_start,i_end,j_start,j_end ! loop ranges for uratio,vratio calc.
  610. integer k_start,k_end
  611. integer ips ! For printing obs information
  612. integer pnx ! obs index for printout
  613. real gridx,gridy,dxob,dyob,dzob,dxob_ms,dyob_ms
  614. real pob
  615. real hob
  616. real uratiob,vratiob,tratiob,tratxob,fnpf
  617. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  618. LOGICAL MP_LOCAL_DUMMASK(NIOBF) ! Mask for work to be done on this processor
  619. LOGICAL MP_LOCAL_UOBMASK(NIOBF) ! Dot-point mask
  620. LOGICAL MP_LOCAL_VOBMASK(NIOBF) ! Dot-point mask
  621. LOGICAL MP_LOCAL_COBMASK(NIOBF) ! Cross-point mask
  622. #endif
  623. ! LOGICAL, EXTERNAL :: TILE_MASK
  624. NSTA=NSTAT
  625. ! FIRST, DETERMINE THE GRID TYPE CORRECTION FOR U-momentum, V-momentum,
  626. ! AND MASS POINTS, AND WHEN INEST=2, CONVERT THE STORED COARSE MESH INDICES
  627. ! TO THE FINE MESH INDEX EQUIVALENTS
  628. ! ITYP=1 FOR U-POINTS, ITYP=2 for V-POINTS, and ITYP=3 FOR MASS POINTS
  629. if (iprt) then
  630. write(msg,fmt='(a,i5,a,i2,a,i5,a)') '++++++CALL ERROB AT KTAU = ', &
  631. KTAU,' AND INEST = ',INEST,': NSTA = ',NSTAW,' ++++++'
  632. call wrf_message(msg)
  633. endif
  634. ERRF = 0.0 ! Zero out errf array
  635. ! Set up loop bounds for this grid's boundary conditions
  636. i_start = max( its-1,ids )
  637. i_end = min( ite+1,ide-1 )
  638. j_start = max( jts-1,jds )
  639. j_end = min( jte+1,jde-1 )
  640. k_start = kts
  641. k_end = min( kte, kde-1 )
  642. DO ITYP=1,3 ! Big loop: ityp=1 for U, ityp=2 for V, ityp=3 for T,Q,SP
  643. ! Set grid stagger
  644. IF(ITYP.EQ.1) THEN ! U-POINT CASE
  645. GRIDX = gridx_u
  646. GRIDY = gridy_u
  647. ELSE IF(ITYP.EQ.2) THEN ! V-POINT CASE
  648. GRIDX = gridx_v
  649. GRIDY = gridy_v
  650. ELSE ! MASS-POINT CASE
  651. GRIDX = gridx_t
  652. GRIDY = gridy_t
  653. ENDIF
  654. ! Compute URATIO and VRATIO fields on momentum (u,v) points.
  655. IF(ityp.eq.1)THEN
  656. call upoint(i_start,i_end, j_start,j_end, ids,ide, ims,ime, jms,jme, uratx, uratio)
  657. ELSE IF (ityp.eq.2) THEN
  658. call vpoint(i_start,i_end, j_start,j_end, jds,jde, ims,ime, jms,jme, vratx, vratio)
  659. ENDIF
  660. IF(INEST.EQ.1) THEN ! COARSE MESH CASE...
  661. DO N=1,NSTA
  662. RA(N)=RIO(N)-GRIDX
  663. RB(N)=RJO(N)-GRIDY
  664. IA(N)=RA(N)
  665. IB(N)=RB(N)
  666. IOB=MAX0(1,IA(N))
  667. IOB=MIN0(IOB,ide-1)
  668. JOB=MAX0(1,IB(N))
  669. JOB=MIN0(JOB,jde-1)
  670. DXOB=RA(N)-FLOAT(IA(N))
  671. DYOB=RB(N)-FLOAT(IB(N))
  672. ! Save mass-point arrays for computing rko for all var types
  673. if(ityp.eq.1) then
  674. iobmg(n) = MIN0(MAX0(1,int(RIO(n)-gridx_t)),ide-1)
  675. jobmg(n) = MIN0(MAX0(1,int(RJO(n)-gridy_t)),jde-1)
  676. dxobmg(n) = RIO(N)-gridx_t-FLOAT(int(RIO(N)-gridx_t))
  677. dyobmg(n) = RJO(N)-gridy_t-FLOAT(int(RJO(N)-gridy_t))
  678. endif
  679. iob_ms = iobmg(n)
  680. job_ms = jobmg(n)
  681. dxob_ms = dxobmg(n)
  682. dyob_ms = dyobmg(n)
  683. ! ajb 20090423: BUGFIX TO OBS_IN_HEIGHT OPTION
  684. ! This is tricky: Initialize pob to zero in all procs. Only one proc actually
  685. ! calculates pob. If this is an obs to be converted from height-to-pressure, then
  686. ! by definition, varobs(5,n) will initially have the missing value -888888. After
  687. ! the pob calculation, pob will be zero in all procs except the one that calculated
  688. ! it, and so pob is dm_summed over all procs and stored into varobs(5,n). So on
  689. ! subsequent passes, the dm_sum will not occur because varobs(5,n) will not have a
  690. ! missing value. If this is not an obs-in-height,
  691. pob = 0.0
  692. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  693. ! Set mask for obs to be handled by this processor
  694. MP_LOCAL_DUMMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
  695. IF ( MP_LOCAL_DUMMASK(N) ) THEN
  696. #endif
  697. ! Interpolate pressure to obs location column and convert from Pa to cb.
  698. do k = kds, kde
  699. pbbo(k) = .001*( &
  700. (1.-DYOB_MS)*( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS) + &
  701. DXOB_MS *pbase(IOB_MS+1,K,JOB_MS) ) + &
  702. DYOB_MS* ( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS+1) + &
  703. DXOB_MS *pbase(IOB_MS+1,K,JOB_MS+1) ) )
  704. ppbo(k) = .001*( &
  705. (1.-DYOB_MS)*( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS) + &
  706. DXOB_MS *pp(IOB_MS+1,K,JOB_MS) ) + &
  707. DYOB_MS* ( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS+1) + &
  708. DXOB_MS *pp(IOB_MS+1,K,JOB_MS+1) ) )
  709. enddo
  710. !ajb 20040119: Note based on bugfix for dot/cross points split across processors,
  711. !ajb which was actually a serial code fix: The ityp=2 (v-points) and
  712. !ajb ityp=3 (mass-points) cases should not use the ityp=1 (u-points)
  713. !ajb case rko! This is necessary for bit-for-bit reproducability
  714. !ajb with the parallel run. (coarse mesh)
  715. if(abs(rko(n)+99).lt.1.)then
  716. pob = varobs(5,n)
  717. if(pob .eq.-888888.) then
  718. hob = varobs(6,n)
  719. if(hob .gt. -800000. ) then
  720. pob = ht_to_p( hob, ppbo, pbbo, z, iob_ms, job_ms, &
  721. dxob_ms, dyob_ms, k_start, k_end, kds,kde, &
  722. ims,ime, jms,jme, kms,kme )
  723. endif
  724. endif
  725. if(pob .gt.-800000.)then
  726. do k=k_end-1,1,-1
  727. kbot = k
  728. if(pob .le. pbbo(k)+ppbo(k)) then
  729. goto 199
  730. endif
  731. enddo
  732. 199 continue
  733. pphi = ppbo(kbot+1)
  734. pbhi = pbbo(kbot+1)
  735. rko(n) = real(kbot+1)- &
  736. ( (pob-pbhi-pphi) / (pbbo(kbot)+ppbo(kbot)-pbhi-pphi) )
  737. rko(n)=max(rko(n),1.0)
  738. endif
  739. endif
  740. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  741. ENDIF !end IF( MP_LOCAL_DUMMASK(N) ) !ajb
  742. #endif
  743. ! ajb 20090423: If obs-in-height, varobs(5,n) is sum of pob (see note above).
  744. if(varobs(5,n) .eq. -888888. .and. varobs(6,n) .gt. -800000.) then
  745. varobs(5,n) = wrf_dm_sum_real ( pob )
  746. endif
  747. RC(N)=RKO(N)
  748. ENDDO ! END COARSE MESH LOOP OVER NSTA
  749. ELSE ! FINE MESH CASE
  750. !**********************************************************************
  751. !ajb_07012008: Conversion of obs coordinates to the fine mesh here
  752. !ajb is no longer necessary, since implementation of the WRF map pro-
  753. !ajb jections (to each nest directly) is implemented in sub in4dob.
  754. !**********************************************************************
  755. !ajb
  756. !ajb GET (I,J,K) OF OBSERVATIONS ON FINE MESH VALUES.
  757. DO N=1,NSTA
  758. RA(N)=RIO(N)-GRIDX ! ajb added 07012008
  759. RB(N)=RJO(N)-GRIDY ! ajb added 07012008
  760. IA(N)=RA(N)
  761. IB(N)=RB(N)
  762. IOB=MAX0(1,IA(N))
  763. IOB=MIN0(IOB,ide-1)
  764. JOB=MAX0(1,IB(N))
  765. JOB=MIN0(JOB,jde-1)
  766. DXOB=RA(N)-FLOAT(IA(N))
  767. DYOB=RB(N)-FLOAT(IB(N))
  768. ! Save mass-point arrays for computing rko for all var types
  769. if(ityp.eq.1) then
  770. iobmg(n) = MIN0(MAX0(1,int(RIO(n)-gridx_t)),ide-1)
  771. jobmg(n) = MIN0(MAX0(1,int(RJO(n)-gridy_t)),jde-1)
  772. dxobmg(n) = RIO(N)-gridx_t-FLOAT(int(RIO(N)-gridx_t))
  773. dyobmg(n) = RJO(N)-gridy_t-FLOAT(int(RJO(N)-gridy_t))
  774. endif
  775. iob_ms = iobmg(n)
  776. job_ms = jobmg(n)
  777. dxob_ms = dxobmg(n)
  778. dyob_ms = dyobmg(n)
  779. ! ajb 20090423: BUGFIX TO OBS_IN_HEIGHT OPTION (see COARSE MESH comments)
  780. pob = 0.0
  781. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  782. ! Set mask for obs to be handled by this processor
  783. MP_LOCAL_DUMMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
  784. IF ( MP_LOCAL_DUMMASK(N) ) THEN
  785. #endif
  786. ! Interpolate pressure to obs location column and convert from Pa to cb.
  787. do k = kds, kde
  788. pbbo(k) = .001*( &
  789. (1.-DYOB_MS)*( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS) + &
  790. DXOB_MS *pbase(IOB_MS+1,K,JOB_MS) ) + &
  791. DYOB_MS* ( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS+1) + &
  792. DXOB_MS *pbase(IOB_MS+1,K,JOB_MS+1) ) )
  793. ppbo(k) = .001*( &
  794. (1.-DYOB_MS)*( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS) + &
  795. DXOB_MS *pp(IOB_MS+1,K,JOB_MS) ) + &
  796. DYOB_MS* ( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS+1) + &
  797. DXOB_MS *pp(IOB_MS+1,K,JOB_MS+1) ) )
  798. enddo
  799. !ajb 20040119: Note based on bugfix for dot/cross points split across processors,
  800. !ajb which was actually a serial code fix: The ityp=2 (v-points) and
  801. !ajb itype=3 (mass-points) cases should not use the ityp=1 (u-points)
  802. !ajb case) rko! This is necessary for bit-for-bit reproducability
  803. !ajb with parallel run. (fine mesh)
  804. if(abs(rko(n)+99).lt.1.)then
  805. pob = varobs(5,n)
  806. if(pob .eq.-888888.) then
  807. hob = varobs(6,n)
  808. if(hob .gt. -800000. ) then
  809. pob = ht_to_p( hob, ppbo, pbbo, z, iob_ms, job_ms, &
  810. dxob_ms, dyob_ms, k_start, k_end, kds,kde, &
  811. ims,ime, jms,jme, kms,kme )
  812. endif
  813. endif
  814. if(pob .gt.-800000.)then
  815. do k=k_end-1,1,-1
  816. kbot = k
  817. if(pob .le. pbbo(k)+ppbo(k)) then
  818. goto 198
  819. endif
  820. enddo
  821. 198 continue
  822. pphi = ppbo(kbot+1)
  823. pbhi = pbbo(kbot+1)
  824. rko(n) = real(kbot+1)- &
  825. ( (pob-pbhi-pphi) / (pbbo(kbot)+ppbo(kbot)-pbhi-pphi) )
  826. rko(n)=max(rko(n),1.0)
  827. endif
  828. endif
  829. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  830. ENDIF !end IF( MP_LOCAL_DUMMASK(N) ) !ajb
  831. #endif
  832. ! ajb 20090423: If obs-in-height, varobs(5,n) is sum of pob (see note above).
  833. if(varobs(5,n) .eq. -888888. .and. varobs(6,n) .gt. -800000.) then
  834. varobs(5,n) = wrf_dm_sum_real ( pob )
  835. endif
  836. RC(N)=RKO(N)
  837. ENDDO ! END FINE MESH LOOP OVER NSTA
  838. ENDIF ! end if(inest.eq.1)
  839. ! INITIALIZE THE ARRAY OF DIFFERENCES BETWEEN THE OBSERVATIONS
  840. ! AND THE LOCAL FORECAST VALUES TO ZERO. FOR THE FINE MESH
  841. ! ONLY, SET THE DIFFERENCE TO A LARGE DUMMY VALUE IF THE
  842. ! OBSERVATION IS OUTSIDE THE FINE MESH DOMAIN.
  843. ! SET DIFFERENCE VALUE TO A DUMMY VALUE FOR OBS POINTS OUTSIDE
  844. ! CURRENT DOMAIN
  845. IF(ITYP.EQ.1) THEN
  846. NLB=1
  847. NLE=1
  848. ELSE IF(ITYP.EQ.2) THEN
  849. NLB=2
  850. NLE=2
  851. ELSE
  852. NLB=3
  853. NLE=5
  854. ENDIF
  855. DO IVAR=NLB,NLE
  856. DO N=1,NSTA
  857. IF((RA(N)-1.).LT.0)THEN
  858. ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
  859. ENDIF
  860. IF((RB(N)-1.).LT.0)THEN
  861. ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
  862. ENDIF
  863. IF((FLOAT(ide)-2.0*GRIDX-RA(N)-1.E-10).LT.0)THEN
  864. ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
  865. ENDIF
  866. IF((FLOAT(jde)-2.0*GRIDY-RB(N)-1.E-10).LT.0)THEN
  867. ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
  868. ENDIF
  869. if(rc(n).lt.1.)errf(ivar,n)=errf(ivar,n)+dummy
  870. ENDDO
  871. ENDDO
  872. ! NOW FIND THE EXACT OFFSET OF EACH OBSERVATION FROM THE
  873. ! GRID POINT TOWARD THE LOWER LEFT
  874. DO N=1,NSTA
  875. IA(N)=RA(N)
  876. IB(N)=RB(N)
  877. IC(N)=RC(N)
  878. ENDDO
  879. DO N=1,NSTA
  880. RA(N)=RA(N)-FLOAT(IA(N))
  881. RB(N)=RB(N)-FLOAT(IB(N))
  882. RC(N)=RC(N)-FLOAT(IC(N))
  883. ENDDO
  884. ! PERFORM A TRILINEAR EIGHT-POINT (3-D) INTERPOLATION
  885. ! TO FIND THE FORECAST VALUE AT THE EXACT OBSERVATION
  886. ! POINTS FOR U, V, T, AND Q.
  887. ! Compute local masks for dot and cross points.
  888. if(ityp.eq.1) then
  889. DO N=1,NSTA
  890. IOB=MAX0(1,IA(N))
  891. IOB=MIN0(IOB,ide-1)
  892. JOB=MAX0(1,IB(N))
  893. JOB=MIN0(JOB,jde-1)
  894. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  895. ! Set mask for U-momemtum points to be handled by this processor
  896. MP_LOCAL_UOBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
  897. #endif
  898. ENDDO
  899. endif
  900. if(ityp.eq.2) then
  901. DO N=1,NSTA
  902. IOB=MAX0(1,IA(N))
  903. IOB=MIN0(IOB,ide-1)
  904. JOB=MAX0(1,IB(N))
  905. JOB=MIN0(JOB,jde-1)
  906. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  907. ! Set mask for V-momentum points to be handled by this processor
  908. MP_LOCAL_VOBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
  909. #endif
  910. ENDDO
  911. endif
  912. if(ityp.eq.3) then
  913. DO N=1,NSTA
  914. IOB=MAX0(1,IA(N))
  915. IOB=MIN0(IOB,ide-1)
  916. JOB=MAX0(1,IB(N))
  917. JOB=MIN0(JOB,jde-1)
  918. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  919. ! Set mask for cross (mass) points to be handled by this processor
  920. MP_LOCAL_COBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
  921. #endif
  922. ENDDO
  923. endif
  924. !**********************************************************
  925. ! PROCESS U VARIABLE (IVAR=1)
  926. !**********************************************************
  927. IF(ITYP.EQ.1) THEN
  928. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  929. DO N=1,NSTA
  930. IF(MP_LOCAL_UOBMASK(N)) THEN
  931. ERRF(9,N)=rko(n) !RKO is needed by neighboring processors !ajb
  932. ENDIF
  933. ENDDO
  934. #endif
  935. IF(ISWIND.EQ.1) THEN
  936. DO N=1,NSTA
  937. IOB=MAX0(2,IA(N))
  938. IOB=MIN0(IOB,ide-1)
  939. IOBM=MAX0(1,IOB-1)
  940. IOBP=MIN0(ide-1,IOB+1)
  941. JOB=MAX0(2,IB(N))
  942. JOB=MIN0(JOB,jde-1)
  943. JOBM=MAX0(1,JOB-1)
  944. JOBP=MIN0(jde-1,JOB+1)
  945. KOB=MIN0(K_END,IC(N))
  946. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  947. IF(MP_LOCAL_UOBMASK(N))THEN ! Do if obs on this processor
  948. #endif
  949. KOBP=MIN0(KOB+1,k_end)
  950. DXOB=RA(N)
  951. DYOB=RB(N)
  952. DZOB=RC(N)
  953. ! Compute surface pressure values at surrounding U and V points
  954. PUG1 = .5*( pbase(IOBM,1,JOB) + pbase(IOB,1,JOB) )
  955. PUG2 = .5*( pbase(IOB,1,JOB) + pbase(IOBP,1,JOB) )
  956. ! This is to correct obs to model sigma level using reverse similarity theory
  957. if(rko(n).eq.1.0)then
  958. uratiob=((1.-DYOB)*((1.-DXOB)*uratio(IOB,JOB)+ &
  959. DXOB*uratio(IOBP,JOB) &
  960. )+DYOB*((1.-DXOB)*uratio(IOB,JOBP)+ &
  961. DXOB*uratio(IOBP,JOBP)))
  962. else
  963. uratiob=1.
  964. endif
  965. !YLIU Some PBL scheme do not define the vratio/uratio
  966. if(abs(uratiob).lt.1.0e-3) then
  967. uratiob=1.
  968. endif
  969. ! INITIAL ERRF(IVAR,N) IS ZERO FOR OBSERVATIONS POINTS
  970. ! WITHIN THE DOMAIN, AND A LARGE DUMMY VALUE FOR POINTS
  971. ! OUTSIDE THE CURRENT DOMAIN
  972. ! U COMPONENT WIND ERROR
  973. ERRF(1,N)=ERRF(1,N)+uratiob*VAROBS(1,N)-((1.-DZOB)* &
  974. ((1.-DyOB)*((1.- &
  975. DxOB)*UB(IOB,KOB,JOB)+DxOB*UB(IOB+1,KOB,JOB) &
  976. )+DyOB*((1.-DxOB)*UB(IOB,KOB,JOB+1)+DxOB* &
  977. UB(IOB+1,KOB,JOB+1)))+DZOB*((1.-DyOB)*((1.-DxOB) &
  978. *UB(IOB,KOBP,JOB)+DxOB*UB(IOB+1,KOBP,JOB))+ &
  979. DyOB*((1.-DxOB)*UB(IOB,KOBP,JOB+1)+DxOB* &
  980. UB(IOB+1,KOBP,JOB+1))))
  981. ! if(n.le.10) then
  982. ! write(6,*)
  983. ! write(6,'(a,i3,i3,i3,a,i3,a,i2)') 'ERRF1 at ',iob,job,kob, &
  984. ! ' N = ',n,' inest = ',inest
  985. ! write(6,*) 'VAROBS(1,N) = ',varobs(1,n)
  986. ! write(6,*) 'VAROBS(5,N) = ',varobs(5,n)
  987. ! write(6,*) 'UB(IOB,KOB,JOB) = ',UB(IOB,KOB,JOB)
  988. ! write(6,*) 'UB(IOB+1,KOB,JOB) = ',UB(IOB+1,KOB,JOB)
  989. ! write(6,*) 'UB(IOB,KOB,JOB+1) = ',UB(IOB,KOB,JOB+1)
  990. ! write(6,*) 'UB(IOB+1,KOB,JOB+1) = ',UB(IOB+1,KOB,JOB+1)
  991. ! write(6,*) 'UB(IOB,KOBP,JOB) = ',UB(IOB,KOBP,JOB)
  992. ! write(6,*) 'UB(IOB+1,KOBP,JOB) = ',UB(IOB+1,KOBP,JOB)
  993. ! write(6,*) 'UB(IOB,KOBP,JOB+1) = ',UB(IOB,KOBP,JOB+1)
  994. ! write(6,*) 'UB(IOB+1,KOBP,JOB+1) = ',UB(IOB+1,KOBP,JOB+1)
  995. ! write(6,*) 'uratiob = ',uratiob
  996. ! write(6,*) 'DXOB,DYOB,DZOB = ',DXOB,DYOB,DZOB
  997. ! write(6,*) 'ERRF(1,N) = ',errf(1,n)
  998. ! write(6,*)
  999. ! endif
  1000. ! Store model surface pressure (not the error!) at U point.
  1001. ERRF(7,N)=.001*( (1.-DXOB)*PUG1 + DXOB*PUG2 )
  1002. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1003. ENDIF ! end IF( MP_LOCAL_UOBMASK(N) )
  1004. #endif
  1005. ENDDO ! END U-POINT LOOP OVER OBS
  1006. ENDIF ! end if(iswind.eq.1)
  1007. ENDIF ! ITYP=1: PROCESS U
  1008. !**********************************************************
  1009. ! PROCESS V VARIABLE (IVAR=2)
  1010. !**********************************************************
  1011. IF(ITYP.EQ.2) THEN
  1012. IF(ISWIND.EQ.1) THEN
  1013. DO N=1,NSTA
  1014. IOB=MAX0(2,IA(N))
  1015. IOB=MIN0(IOB,ide-1)
  1016. IOBM=MAX0(1,IOB-1)
  1017. IOBP=MIN0(ide-1,IOB+1)
  1018. JOB=MAX0(2,IB(N))
  1019. JOB=MIN0(JOB,jde-1)
  1020. JOBM=MAX0(1,JOB-1)
  1021. JOBP=MIN0(jde-1,JOB+1)
  1022. KOB=MIN0(K_END,IC(N))
  1023. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1024. IF(MP_LOCAL_VOBMASK(N))THEN ! Do if obs on this processor
  1025. #endif
  1026. KOBP=MIN0(KOB+1,k_end)
  1027. DXOB=RA(N)
  1028. DYOB=RB(N)
  1029. DZOB=RC(N)
  1030. ! Compute surface pressure values at surrounding U and V points
  1031. PVG1 = .5*( pbase(IOB,1,JOBM) + pbase(IOB,1,JOB) )
  1032. PVG2 = .5*( pbase(IOB,1,JOB) + pbase(IOB,1,JOBP) )
  1033. ! This is to correct obs to model sigma level using reverse similarity theory
  1034. if(rko(n).eq.1.0)then
  1035. vratiob=((1.-DYOB)*((1.-DXOB)*vratio(IOB,JOB)+ &
  1036. DXOB*vratio(IOBP,JOB) &
  1037. )+DYOB*((1.-DXOB)*vratio(IOB,JOBP)+ &
  1038. DXOB*vratio(IOBP,JOBP)))
  1039. else
  1040. vratiob=1.
  1041. endif
  1042. !YLIU Some PBL scheme do not define the vratio/uratio
  1043. if(abs(vratiob).lt.1.0e-3) then
  1044. vratiob=1.
  1045. endif
  1046. ! INITIAL ERRF(IVAR,N) IS ZERO FOR OBSERVATIONS POINTS
  1047. ! WITHIN THE DOMAIN, AND A LARGE DUMMY VALUE FOR POINTS
  1048. ! OUTSIDE THE CURRENT DOMAIN
  1049. ! V COMPONENT WIND ERROR
  1050. ERRF(2,N)=ERRF(2,N)+vratiob*VAROBS(2,N)-((1.-DZOB)* &
  1051. ((1.-DyOB)*((1.- &
  1052. DxOB)*VB(IOB,KOB,JOB)+DxOB*VB(IOB+1,KOB,JOB) &
  1053. )+DyOB*((1.-DxOB)*VB(IOB,KOB,JOB+1)+DxOB* &
  1054. VB(IOB+1,KOB,JOB+1)))+DZOB*((1.-DyOB)*((1.-DxOB) &
  1055. *VB(IOB,KOBP,JOB)+DxOB*VB(IOB+1,KOBP,JOB))+ &
  1056. DyOB*((1.-DxOB)*VB(IOB,KOBP,JOB+1)+DxOB* &
  1057. VB(IOB+1,KOBP,JOB+1))))
  1058. ! if(n.le.10) then
  1059. ! write(6,*)
  1060. ! write(6,'(a,i3,i3,i3,a,i3,a,i2)') 'ERRF2 at ',iob,job,kob, &
  1061. ! ' N = ',n,' inest = ',inest
  1062. ! write(6,*) 'VAROBS(2,N) = ',varobs(2,n)
  1063. ! write(6,*) 'VAROBS(5,N) = ',varobs(5,n)
  1064. ! write(6,*) 'VB(IOB,KOB,JOB) = ',VB(IOB,KOB,JOB)
  1065. ! write(6,*) 'ERRF(2,N) = ',errf(2,n)
  1066. ! write(6,*) 'vratiob = ',vratiob
  1067. ! write(6,*)
  1068. ! endif
  1069. ! Store model surface pressure (not the error!) at V point.
  1070. ERRF(8,N)=.001*( (1.-DYOB)*PVG1 + DYOB*PVG2 )
  1071. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1072. ENDIF ! end IF( MP_LOCAL_VOBMASK(N) )
  1073. #endif
  1074. ENDDO ! END V-POINT LOOP OVER OBS
  1075. ENDIF ! end if(iswind.eq.1)
  1076. ENDIF ! ITYP=1: PROCESS V
  1077. !**********************************************************
  1078. ! PROCESS MASS-POINT VARIABLES IVAR=3 (T) AND IVAR=4 (QV)
  1079. !**********************************************************
  1080. IF(ITYP.EQ.3) THEN
  1081. IF(ISTEMP.EQ.1 .OR. ISMOIS.EQ.1) THEN
  1082. DO N=1,NSTA
  1083. IOB=MAX0(1,IA(N))
  1084. IOB=MIN0(IOB,ide-1)
  1085. JOB=MAX0(1,IB(N))
  1086. JOB=MIN0(JOB,jde-1)
  1087. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1088. IF(MP_LOCAL_COBMASK(N)) THEN ! Do if obs on this processor
  1089. #endif
  1090. KOB=MIN0(k_end,IC(N))
  1091. KOBP=MIN0(KOB+1,K_END)
  1092. DXOB=RA(N)
  1093. DYOB=RB(N)
  1094. DZOB=RC(N)
  1095. ! This is to correct obs to model sigma level using reverse similarity theory
  1096. if(rko(n).eq.1.0)then
  1097. tratxob=((1.-DYOB)*((1.-DXOB)*tratx(IOB,JOB)+ &
  1098. DXOB*tratx(IOB+1,JOB) &
  1099. )+DYOB*((1.-DXOB)*tratx(IOB,JOB+1)+ &
  1100. DXOB*tratx(IOB+1,JOB+1)))
  1101. else
  1102. tratxob=1.
  1103. endif
  1104. !yliu
  1105. if(abs(tratxob) .lt. 1.0E-3) tratxob=1.
  1106. !ajb We must convert temperature to potential temperature
  1107. obs_pottemp = -888888.
  1108. if(varobs(3,n).gt.-800000. .and. varobs(5,n).gt.-800000) then
  1109. obs_pottemp = varobs(3,n)*(100./varobs(5,n))**RCP - t0
  1110. endif
  1111. ERRF(3,N)=ERRF(3,N)+tratxob*obs_pottemp-((1.-DZOB)* &
  1112. ((1.-DyOB)*((1.- &
  1113. DxOB)*(TB(IOB,KOB,JOB))+DxOB* &
  1114. (TB(IOB+1,KOB,JOB)))+DyOB*((1.-DxOB)* &
  1115. (TB(IOB,KOB,JOB+1))+DxOB* &
  1116. (TB(IOB+1,KOB,JOB+1))))+DZOB*((1.- &
  1117. DyOB)*((1.-DxOB)*(TB(IOB,KOBP,JOB))+DxOB* &
  1118. (TB(IOB+1,KOBP,JOB)))+DyOB*((1.-DxOB)* &
  1119. (TB(IOB,KOBP,JOB+1))+DxOB* &
  1120. (TB(IOB+1,KOBP,JOB+1)))))
  1121. ! if(n.le.10) then
  1122. ! write(6,*)
  1123. ! write(6,'(a,i3,i3,i3,a,i3,a,i2)') 'ERRF3 at ',iob,job,kob, &
  1124. ! ' N = ',n,' inest = ',inest
  1125. ! write(6,*) 'VAROBS(3,N) = ',varobs(3,n)
  1126. ! write(6,*) 'VAROBS(5,N) = ',varobs(5,n)
  1127. ! write(6,*) 'TB(IOB,KOB,JOB) = ',TB(IOB,KOB,JOB)
  1128. ! write(6,*) 'TB(IOB+1,KOB,JOB) = ',TB(IOB+1,KOB,JOB)
  1129. ! write(6,*) 'TB(IOB,KOB,JOB+1) = ',TB(IOB,KOB,JOB+1)
  1130. ! write(6,*) 'TB(IOB+1,KOB,JOB+1) = ',TB(IOB+1,KOB,JOB+1)
  1131. ! write(6,*) 'TB(IOB,KOBP,JOB) = ',TB(IOB,KOBP,JOB)
  1132. ! write(6,*) 'TB(IOB+1,KOBP,JOB) = ',TB(IOB+1,KOBP,JOB)
  1133. ! write(6,*) 'TB(IOB,KOBP,JOB+1) = ',TB(IOB,KOBP,JOB+1)
  1134. ! write(6,*) 'TB(IOB+1,KOBP,JOB+1) = ',TB(IOB+1,KOBP,JOB+1)
  1135. ! write(6,*) 'tratxob = ',tratxob
  1136. ! write(6,*) 'DXOB,DYOB,DZOB = ',DXOB,DYOB,DZOB
  1137. ! write(6,*) 'ERRF(3,N) = ',errf(3,n)
  1138. ! write(6,*)
  1139. ! endif
  1140. ! MOISTURE ERROR
  1141. ERRF(4,N)=ERRF(4,N)+VAROBS(4,N)-((1.-DZOB)*((1.-DyOB)*((1.- &
  1142. DxOB)*QVB(IOB,KOB,JOB)+DxOB* &
  1143. QVB(IOB+1,KOB,JOB))+DyOB*((1.-DxOB)* &
  1144. QVB(IOB,KOB,JOB+1)+DxOB* &
  1145. QVB(IOB+1,KOB,JOB+1)))+DZOB*((1.- &
  1146. DyOB)*((1.-DxOB)*QVB(IOB,KOBP,JOB)+DxOB &
  1147. *QVB(IOB+1,KOBP,JOB))+DyOB*((1.-DxOB &
  1148. )*QVB(IOB,KOBP,JOB+1)+DxOB* &
  1149. QVB(IOB+1,KOBP,JOB+1))))
  1150. ! Store model surface pressure (not the error!) at T-point
  1151. ERRF(6,N)= .001* &
  1152. ((1.-DyOB)*((1.-DxOB)*pbase(IOB,1,JOB)+DxOB* &
  1153. pbase(IOB+1,1,JOB))+DyOB*((1.-DxOB)* &
  1154. pbase(IOB,1,JOB+1)+DxOB*pbase(IOB+1,1,JOB+1) ))
  1155. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1156. ENDIF ! end IF( MP_LOCAL_COBMASK(N) )
  1157. #endif
  1158. ENDDO ! END T and QV LOOP OVER OBS
  1159. ENDIF !end if(istemp.eq.1 .or. ismois.eq.1)
  1160. !*******************************************************
  1161. ! USE ERRF(5,N) TO STORE KPBL AT (I,J) NEAREST THE OBS
  1162. !*******************************************************
  1163. DO N=1,NSTA
  1164. IOB=MAX0(1,IA(N))
  1165. IOB=MIN0(IOB,ide-1)
  1166. JOB=MAX0(1,IB(N))
  1167. JOB=MIN0(JOB,jde-1)
  1168. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1169. IF(MP_LOCAL_COBMASK(N)) THEN ! Do if obs on this processor
  1170. #endif
  1171. DXOB=RA(N)
  1172. DYOB=RB(N)
  1173. ERRF(5,N) = kpbl(iob+nint(dxob),job+nint(dyob))
  1174. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1175. ENDIF ! end IF( MP_LOCAL_COBMASK(N) )
  1176. #endif
  1177. ENDDO
  1178. !!**********************************************************
  1179. ENDIF ! end if(ityp.eq.3)
  1180. ENDDO ! END BIG LOOP
  1181. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1182. ! Gather the errf values calculated by the processors with the obs.
  1183. CALL get_full_obs_vector(nsta, nerrf, niobf, mp_local_uobmask, &
  1184. mp_local_vobmask, mp_local_cobmask, errf)
  1185. ! 02252010: Go ahead and assign rko for "obs-off" processors here, to
  1186. ! fix the problem where duplicate obs can be dropped from
  1187. ! the "obs-on" processor, but not from the others, due to
  1188. ! rko being -99 on the "obs-off" processors.
  1189. do n=1,nsta
  1190. rko(n) = errf(9,n)
  1191. enddo
  1192. ! 02252010: End bugfix.
  1193. #endif
  1194. ! Print obs information.
  1195. CALL print_obs_info(iprt,inest,niobf,rio,rjo,rko, &
  1196. prt_max,prt_freq,obs_prt,stnid_prt, &
  1197. lat_prt,lon_prt,mlat_prt,mlon_prt, &
  1198. timeob,xtime)
  1199. ! DIFFERENCE BETWEEN OBS AND FCST IS COMPLETED
  1200. IF(INEST.EQ.1)THEN
  1201. INPF=NPFI
  1202. ELSE
  1203. FNPF=IRATIO**LEVIDN(INEST)
  1204. INPF=FNPF*NPFI
  1205. ENDIF
  1206. ! Gross error check for temperature. Set all vars bad.
  1207. do n=1,nsta
  1208. if((abs(errf(3,n)).gt.20.).and. &
  1209. (errf(3,n).gt.-800000.))then
  1210. errf(1,n)=-888888.
  1211. errf(2,n)=-888888.
  1212. errf(3,n)=-888888.
  1213. errf(4,n)=-888888.
  1214. varobs(1,n)=-888888.
  1215. varobs(2,n)=-888888.
  1216. varobs(3,n)=-888888.
  1217. varobs(4,n)=-888888.
  1218. endif
  1219. enddo
  1220. ! For printout
  1221. ! IF(MOD(KTAU,INPF).NE.0) THEN
  1222. ! RETURN
  1223. ! ENDIF
  1224. RETURN
  1225. END SUBROUTINE errob
  1226. SUBROUTINE upoint(i_start,i_end, j_start,j_end, ids,ide, ims,ime, jms,jme, &
  1227. arrin, arrout)
  1228. !------------------------------------------------------------------------------
  1229. ! PURPOSE: This subroutine interpolates a real 2D array defined over mass
  1230. ! coordinate points, to U (momentum) points.
  1231. !
  1232. !------------------------------------------------------------------------------
  1233. IMPLICIT NONE
  1234. INTEGER, INTENT(IN) :: i_start ! Starting i index for this model tile
  1235. INTEGER, INTENT(IN) :: i_end ! Ending i index for this model tile
  1236. INTEGER, INTENT(IN) :: j_start ! Starting j index for this model tile
  1237. INTEGER, INTENT(IN) :: j_end ! Ending j index for this model tile
  1238. INTEGER, INTENT(IN) :: ids ! Starting i index for entire model domain
  1239. INTEGER, INTENT(IN) :: ide ! Ending i index for entire model domain
  1240. INTEGER, INTENT(IN) :: ims ! Starting i index for model patch
  1241. INTEGER, INTENT(IN) :: ime ! Ending i index for model patch
  1242. INTEGER, INTENT(IN) :: jms ! Starting j index for model patch
  1243. INTEGER, INTENT(IN) :: jme ! Ending j index for model patch
  1244. REAL, INTENT(IN) :: arrin ( ims:ime, jms:jme ) ! input array on mass points
  1245. REAL, INTENT(OUT) :: arrout( ims:ime, jms:jme ) ! output array on U points
  1246. ! Local variables
  1247. integer :: i, j
  1248. ! Do domain interior first
  1249. do j = j_start, j_end
  1250. do i = max(2,i_start), i_end
  1251. arrout(i,j) = 0.5*(arrin(i,j)+arrin(i-1,j))
  1252. enddo
  1253. enddo
  1254. ! Do west-east boundaries
  1255. if(i_start .eq. ids) then
  1256. do j = j_start, j_end
  1257. arrout(i_start,j) = arrin(i_start,j)
  1258. enddo
  1259. endif
  1260. if(i_end .eq. ide-1) then
  1261. do j = j_start, j_end
  1262. arrout(i_end+1,j) = arrin(i_end,j)
  1263. enddo
  1264. endif
  1265. RETURN
  1266. END SUBROUTINE upoint
  1267. SUBROUTINE vpoint(i_start,i_end, j_start,j_end, jds,jde, ims,ime, jms,jme, &
  1268. arrin, arrout)
  1269. !------------------------------------------------------------------------------
  1270. ! PURPOSE: This subroutine interpolates a real 2D array defined over mass
  1271. ! coordinate points, to V (momentum) points.
  1272. !
  1273. !------------------------------------------------------------------------------
  1274. IMPLICIT NONE
  1275. INTEGER, INTENT(IN) :: i_start ! Starting i index for this model tile
  1276. INTEGER, INTENT(IN) :: i_end ! Ending i index for this model tile
  1277. INTEGER, INTENT(IN) :: j_start ! Starting j index for this model tile
  1278. INTEGER, INTENT(IN) :: j_end ! Ending j index for this model tile
  1279. INTEGER, INTENT(IN) :: jds ! Starting j index for entire model domain
  1280. INTEGER, INTENT(IN) :: jde ! Ending j index for entire model domain
  1281. INTEGER, INTENT(IN) :: ims ! Starting i index for model patch
  1282. INTEGER, INTENT(IN) :: ime ! Ending i index for model patch
  1283. INTEGER, INTENT(IN) :: jms ! Starting j index for model patch
  1284. INTEGER, INTENT(IN) :: jme ! Ending j index for model patch
  1285. REAL, INTENT(IN) :: arrin ( ims:ime, jms:jme ) ! input array on mass points
  1286. REAL, INTENT(OUT) :: arrout( ims:ime, jms:jme ) ! output array on V points
  1287. ! Local variables
  1288. integer :: i, j
  1289. ! Do domain interior first
  1290. do j = max(2,j_start), j_end
  1291. do i = i_start, i_end
  1292. arrout(i,j) = 0.5*(arrin(i,j)+arrin(i,j-1))
  1293. enddo
  1294. enddo
  1295. ! Do south-north boundaries
  1296. if(j_start .eq. jds) then
  1297. do i = i_start, i_end
  1298. arrout(i,j_start) = arrin(i,j_start)
  1299. enddo
  1300. endif
  1301. if(j_end .eq. jde-1) then
  1302. do i = i_start, i_end
  1303. arrout(i,j_end+1) = arrin(i,j_end)
  1304. enddo
  1305. endif
  1306. RETURN
  1307. END SUBROUTINE vpoint
  1308. LOGICAL FUNCTION TILE_MASK(iloc, jloc, its, ite, jts, jte)
  1309. !------------------------------------------------------------------------------
  1310. ! PURPOSE: Check to see if an i, j grid coordinate is in the tile index range.
  1311. !
  1312. ! Returns: TRUE if the grid coordinate (ILOC,JLOC) is in the tile defined by
  1313. ! tile-range indices (its,jts) and (ite,jte)
  1314. ! FALSE otherwise.
  1315. !
  1316. !------------------------------------------------------------------------------
  1317. IMPLICIT NONE
  1318. INTEGER, INTENT(IN) :: iloc
  1319. INTEGER, INTENT(IN) :: jloc
  1320. INTEGER, INTENT(IN) :: its
  1321. INTEGER, INTENT(IN) :: ite
  1322. INTEGER, INTENT(IN) :: jts
  1323. INTEGER, INTENT(IN) :: jte
  1324. ! Local variables
  1325. LOGICAL :: retval
  1326. TILE_MASK = (iloc .LE. ite .AND. iloc .GE. its .AND. &
  1327. jloc .LE. jte .AND. jloc .GE. jts )
  1328. RETURN
  1329. END FUNCTION TILE_MASK
  1330. !-----------------------------------------------------------------------
  1331. SUBROUTINE nudob(j, ivar, aten, inest, ifrest, ktau, ktaur, &
  1332. xtime, mu, msfx, msfy, nndgv, nerrf, niobf, maxdom, &
  1333. npfi, ionf, rinxy, twindo, &
  1334. nudge_pbl, &
  1335. sfcfact, sfcfacr, &
  1336. levidn, &
  1337. parid, nstat, &
  1338. rinfmn, rinfmx, pfree, dcon, tfaci, &
  1339. sfc_scheme_horiz, sfc_scheme_vert, maxsnd_gap, &
  1340. lev_in_ob, plfo, nlevs_ob, &
  1341. iratio, dx, dtmin, rio, rjo, rko, &
  1342. timeob, varobs, errf, pbase, ptop, pp, &
  1343. iswind, istemp, ismois, giv, git, giq, &
  1344. savwt, kpblt, nscan, &
  1345. vih1, vih2, terrh, zslab, &
  1346. iprt, &
  1347. ids,ide, jds,jde, kds,kde, & ! domain dims
  1348. ims,ime, jms,jme, kms,kme, & ! memory dims
  1349. its,ite, jts,jte, kts,kte ) ! tile dims
  1350. !-----------------------------------------------------------------------
  1351. USE module_model_constants
  1352. USE module_domain
  1353. !-----------------------------------------------------------------------
  1354. IMPLICIT NONE
  1355. !-----------------------------------------------------------------------
  1356. !
  1357. ! PURPOSE: THIS SUBROUTINE GENERATES NUDGING TENDENCIES FOR THE J-TH
  1358. ! VERTICAL SLICE (I-K PLANE) FOR FOUR-DIMENSIONAL DATA
  1359. ! ASSIMILATION FROM INDIVIDUAL OBSERVATIONS. THE NUDGING
  1360. ! TENDENCIES ARE FOUND FROM A ONE-PASS CALCULATION OF
  1361. ! WEIGHTING FACTORS SIMILAR TO THE BENJAMIN-SEAMAN OBJECTIVE
  1362. ! ANALYSIS. THIS SUBROUTINE IS DESIGNED FOR RAPID EXECUTION
  1363. ! AND MINIMAL STORAGE REQUIREMENTS. ALGORITHMS SHOULD BE
  1364. ! VECTORIZED WHEREVER POSSIBLE.
  1365. !
  1366. ! HISTORY: Original author: MM5 version???
  1367. ! 02/04/2004 - Creation of WRF version. Al Bourgeois
  1368. ! 08/28/2006 - Conversion from F77 to F90 Al Bourgeois
  1369. !------------------------------------------------------------------------------
  1370. !
  1371. ! NOTE: This routine was originally designed for MM5, which uses
  1372. ! a nonstandard (I,J) coordinate system. For WRF, I is the
  1373. ! east-west running coordinate, and J is the south-north
  1374. ! running coordinate. So a "J-slab" here is west-east in
  1375. ! extent, not south-north as for MM5. -ajb 06/10/2004
  1376. !
  1377. ! NET WEIGHTING (WT) OF THE DIFFERENCE BETWEEN THE OBSERVATIONS
  1378. ! AND LOCAL FORECAST VALUES IS BASED ON THE MULTIPLE OF THREE
  1379. ! TYPES OF FACTORS:
  1380. ! 1) TIME WEIGHTING - ONLY OBSERVATIONS WITHIN A SELECTED
  1381. ! TIME WINDOW (TWINDO) CENTERED AT THE CURRENT FORECAST
  1382. ! TIME (XTIME) ARE USED. OBSERVATIONS CLOSEST TO
  1383. ! XTIME ARE TIME-WEIGHTED MOST HEAVILY (TIMEWT)
  1384. ! 2) VERTICAL WEIGHTING - NON-ZERO WEIGHTS (WTSIG) ARE
  1385. ! CALCULATED WITHIN A VERTICAL REGION OF INFLUENCE
  1386. ! (RINSIG).
  1387. ! 3) HORIZONTAL WEIGHTING - NON-ZERO WEIGHTS (WTIJ) ARE
  1388. ! CALCULATED WITHIN A RADIUS OF INFLUENCE (RINXY). THE
  1389. ! VALUE OF RIN IS DEFINED IN KILOMETERS, AND CONVERTED
  1390. ! TO GRID LENGTHS FOR THE APPROPRIATE MESH SIZE.
  1391. !
  1392. ! THE FIVE FORECAST VARIABLES ARE PROCESSED BY CHANGING THE
  1393. ! VALUE OF IVAR AS FOLLOWS:
  1394. ! IVAR VARIABLE(TAU-1)
  1395. ! ---- ---------------
  1396. ! 1 U
  1397. ! 2 V
  1398. ! 3 T
  1399. ! 4 QV
  1400. ! 5 PSB(CROSS) REMOVED IN V3
  1401. ! (6) PSB(DOT)
  1402. !
  1403. !-----------------------------------------------------------------------
  1404. !
  1405. ! Description of input arguments.
  1406. !
  1407. !-----------------------------------------------------------------------
  1408. INTEGER, INTENT(IN) :: ids,ide, jds,jde, kds,kde ! domain dims.
  1409. INTEGER, INTENT(IN) :: ims,ime, jms,jme, kms,kme ! memory dims.
  1410. INTEGER, INTENT(IN) :: its,ite, jts,jte, kts,kte ! tile dims.
  1411. INTEGER, INTENT(IN) :: j ! south-north running coordinate.
  1412. INTEGER, INTENT(IN) :: ivar
  1413. INTEGER, INTENT(IN) :: inest ! domain index
  1414. LOGICAL, INTENT(IN) :: ifrest
  1415. INTEGER, INTENT(IN) :: ktau
  1416. INTEGER, INTENT(IN) :: ktaur
  1417. REAL, INTENT(IN) :: xtime ! forecast time in minutes
  1418. INTEGER, INTENT(IN) :: nndgv ! number of nudge variables
  1419. INTEGER, INTENT(IN) :: nerrf ! number of error fields
  1420. INTEGER, INTENT(IN) :: niobf ! number of observations
  1421. INTEGER, INTENT(IN) :: maxdom ! maximum number of domains
  1422. INTEGER, INTENT(IN) :: npfi
  1423. INTEGER, INTENT(IN) :: ionf
  1424. REAL, INTENT(IN) :: rinxy
  1425. REAL, INTENT(IN) :: twindo
  1426. REAL, intent(in) :: sfcfact ! scale for time window (surface obs)
  1427. REAL, intent(in) :: sfcfacr ! scale for hor rad inf (surface obs)
  1428. LOGICAL, intent(in) :: nudge_pbl ! flag for nudging in pbl
  1429. INTEGER, INTENT(IN) :: levidn(maxdom) ! level of nest
  1430. INTEGER, INTENT(IN) :: parid(maxdom) ! parent domain id
  1431. INTEGER, INTENT(IN) :: nstat ! number of obs stations
  1432. REAL, INTENT(IN) :: rinfmn ! minimum radius of influence
  1433. REAL, INTENT(IN) :: rinfmx ! maximum radius of influence
  1434. REAL, INTENT(IN) :: pfree ! pressure level (cb) where terrain effect becomes small
  1435. REAL, INTENT(IN) :: dcon ! 1/DPSMX
  1436. REAL, INTENT(IN) :: tfaci ! scale factor used for ramp-down in dynamic initialization
  1437. INTEGER , INTENT(IN) :: sfc_scheme_horiz ! horizontal spreading scheme for surf obs (wrf or orig mm5)
  1438. INTEGER , INTENT(IN) :: sfc_scheme_vert ! vertical spreading scheme for surf obs (orig or regime vif)
  1439. REAL , INTENT(IN) :: maxsnd_gap ! max allowed pressure gap in soundings, for interp (centibars)
  1440. REAL, INTENT(IN) :: lev_in_ob(niobf) ! Level in sounding-type obs.
  1441. REAL, intent(IN) :: plfo(niobf) ! Index for type of obs platform
  1442. REAL, INTENT(IN) :: nlevs_ob(niobf) ! Number of levels in sounding.
  1443. INTEGER, INTENT(IN) :: iratio ! Nest to parent gridsize ratio.
  1444. REAL, INTENT(IN) :: dx ! This domain grid cell-size (m)
  1445. REAL, INTENT(IN) :: dtmin ! Model time step in minutes
  1446. REAL, INTENT(IN) :: rio(niobf) ! Obs west-east coordinate (non-stag grid).
  1447. REAL, INTENT(IN) :: rjo(niobf) ! Obs south-north coordinate (non-stag grid).
  1448. REAL, INTENT(INOUT) :: rko(niobf) ! Obs vertical coordinate.
  1449. REAL, INTENT(IN) :: timeob(niobf)
  1450. REAL, INTENT(IN) :: varobs(nndgv,niobf)
  1451. REAL, INTENT(IN) :: errf(nerrf, niobf)
  1452. REAL, INTENT(IN) :: pbase( ims:ime, kms:kme ) ! Base pressure.
  1453. REAL, INTENT(IN) :: ptop
  1454. REAL, INTENT(IN) :: pp( ims:ime, kms:kme ) ! Pressure perturbation (Pa)
  1455. REAL, INTENT(IN) :: mu(ims:ime) ! Air mass on u, v, or mass-grid
  1456. REAL, INTENT(IN) :: msfx(ims:ime) ! Map scale (only used for vars u & v)
  1457. REAL, INTENT(IN) :: msfy(ims:ime) ! Map scale (only used for vars u & v)
  1458. INTEGER, intent(in) :: iswind ! Nudge flag for wind
  1459. INTEGER, intent(in) :: istemp ! Nudge flag for temperature
  1460. INTEGER, intent(in) :: ismois ! Nudge flag for moisture
  1461. REAL, intent(in) :: giv ! Coefficient for wind
  1462. REAL, intent(in) :: git ! Coefficient for temperature
  1463. REAL, intent(in) :: giq ! Coefficient for moisture
  1464. REAL, INTENT(INOUT) :: aten( ims:ime, kms:kme)
  1465. REAL, INTENT(INOUT) :: savwt( nndgv, ims:ime, kms:kme )
  1466. INTEGER, INTENT(IN) :: kpblt(ims:ime)
  1467. INTEGER, INTENT(IN) :: nscan ! number of scans
  1468. REAL, INTENT(IN) :: vih1(its:ite) ! Vert infl ht (m) abv grd for full wts
  1469. REAL, INTENT(IN) :: vih2(its:ite) ! Vert infl ht (m) abv grd for ramp
  1470. REAL, INTENT(IN) :: terrh(ims:ime) ! Terrain height (m)
  1471. ! INTEGER, INTENT(IN) :: vik1(its:ite) ! Vertical infl k-level for full wts
  1472. ! INTEGER, INTENT(IN) :: vik2(its:ite) ! Vertical infl k-level for ramp
  1473. REAL, INTENT(IN) :: zslab(ims:ime, kms:kme) ! model ht above ground (m)
  1474. LOGICAL, INTENT(IN) :: iprt ! print flag
  1475. ! Local variables
  1476. integer :: mm(maxdom)
  1477. integer :: kobs ! k-lev below obs (for obs straddling pblt)
  1478. integer :: kpbl_obs(nstat) ! kpbl at grid point (IOB,JOB) (ajb 20090519)
  1479. real :: ra(niobf)
  1480. real :: rb(niobf)
  1481. real :: psurf(niobf)
  1482. real :: wtsig(kms:kme),wt(ims:ime,kms:kme),wt2err(ims:ime,kms:kme)
  1483. real :: rscale(ims:ime) ! For converting to rho-coupled units.
  1484. real :: wtij(ims:ime) ! For holding weights in i-loop
  1485. real :: reserf(100)
  1486. character*40 name
  1487. character*3 chr_hr
  1488. character(len=200) :: msg ! Argument to wrf_message
  1489. !*** DECLARATIONS FOR IMPLICIT NONE
  1490. integer :: i,k,iplo,icut,ipl,inpf,infr,jjjn
  1491. integer :: igrid,n,nml,nnl,nsthis,nsmetar,nsspeci,nsship
  1492. integer :: nssynop,nstemp,nspilot,nssatwnds,nssams,nsprofs
  1493. integer :: maxi,mini,maxj,minj,nnn,nsndlev,njcsnd,kob
  1494. integer :: komin,komax,nn,nhi,nlo,nnjc
  1495. integer :: i_s,i_e
  1496. integer :: istq
  1497. real :: gfactor,rfactor,gridx,gridy,rindx,ris
  1498. real :: grfacx,grfacy
  1499. real :: timewt,pob
  1500. real :: ri,rj,rx,ry,rsq,pdfac,erfivr,dk,slope,rinfac
  1501. real :: dprim,dsq,d ! vars for mm5 surface-ob weighting
  1502. real :: rinprs,pijk,pobhi,poblo,pdiffj,w2eowt,gitq
  1503. real :: dz_ramp ! For ramping weights for surface obs
  1504. real :: scratch
  1505. integer :: kk !ajb temp
  1506. ! print *,'start nudob, nstat,j,ivar=',nstat,j,ivar
  1507. ! if(ivar.ne.4)return
  1508. !yliu start -- for multi-scans: NSCAN=0: original
  1509. ! NSCAN=1: added a scan with a larger Ri and smaller G
  1510. ! if(NSCAN.ne.0 .and. NSCAN.ne.1) stop
  1511. ! ajb note: Will need to increase memory for SAVWT if NSCAN=1:
  1512. if(NSCAN.ne.0) then
  1513. IF (iprt) then
  1514. write(msg,*) 'SAVWT must be resized for NSCAN=1'
  1515. call wrf_message(msg)
  1516. ENDIF
  1517. call wrf_error_fatal ( 'wrf_fddaobs_in: in4dob' )
  1518. endif
  1519. IPLO=0 + NSCAN*4
  1520. GFACTOR=1. + NSCAN*(-1. + 0.33333)
  1521. RFACTOR=1. + NSCAN*(-1. + 3.0)
  1522. !yliu end
  1523. ! jc
  1524. ! return if too close to j boundary
  1525. if(inest.eq.1.and.ivar.lt.3.and.(j.le.2.or.j.ge.jde-1)) then
  1526. ! write(6,*) '1 RETURN: IVAR = ',ivar,' J = ',j,
  1527. ! $ ' too close to boundary.'
  1528. return
  1529. endif
  1530. if(inest.eq.1.and.ivar.ge.3.and.(j.le.2.or.j.ge.jde-2)) then
  1531. ! write(6,*) '2 RETURN: IVAR = ',ivar,' J = ',j,
  1532. ! $ ' too close to boundary.'
  1533. return
  1534. endif
  1535. ! COMPUTE IPL WHICH REPRESENTS IVAR FOR EACH MESH IN SAVWT MODS
  1536. ICUT=0
  1537. IF(INEST.GT.1)ICUT=1
  1538. i_s = max0(2+icut,its)
  1539. i_e = min0(ide-1-icut,ite)
  1540. IPL=IVAR + IPLO !yliu +IPLO
  1541. ! DEFINE GRID-TYPE OFFSET FACTORS, IGRID AND GRID
  1542. INPF=(IRATIO**LEVIDN(INEST))*NPFI
  1543. INFR=(IRATIO**LEVIDN(INEST))*IONF
  1544. GRIDX=0.0
  1545. GRIDY=0.0
  1546. IGRID=0
  1547. IF(IVAR.GE.3)THEN
  1548. GRIDX=0.5
  1549. GRIDY=0.5
  1550. IGRID=1
  1551. ELSEIF(IVAR.eq.1) THEN
  1552. GRIDY=0.5
  1553. GRIDX=0.0
  1554. IGRID=1
  1555. ELSEIF(IVAR.eq.2) THEN
  1556. GRIDX=0.5
  1557. GRIDY=0.0
  1558. IGRID=1
  1559. ENDIF
  1560. ! TRANSFORM THE HORIZONTAL RADIUS OF INFLUENCE, RINXY, FROM
  1561. ! KILOMETERS TO GRID LENGTHS, RINDX
  1562. RINDX=RINXY*1000./DX * RFACTOR !yliu *RFACTOR
  1563. RIS=RINDX*RINDX
  1564. IF(IFREST.AND.KTAU.EQ.KTAUR)GOTO 5
  1565. IF(MOD(KTAU,INFR).NE.0)GOTO 126
  1566. 5 CONTINUE
  1567. IF (iprt) THEN
  1568. IF(J.EQ.10) then
  1569. write(msg,6) INEST,J,KTAU,XTIME,IVAR,IPL,rindx
  1570. call wrf_message(msg)
  1571. ENDIF
  1572. ENDIF
  1573. 6 FORMAT(1X,'OBS NUDGING FOR IN,J,KTAU,XTIME,', &
  1574. 'IVAR,IPL: ',I2,1X,I2,1X,I5,1X,F8.2,1X,I2,1X,I2, &
  1575. ' rindx=',f4.1)
  1576. !********************************************************************
  1577. !ajb_07012008 Setting ra and rb for the fine mesh her is now simple.
  1578. ! Values are no longer calculated here based on the
  1579. ! coarse mesh, since direct use of WRF map projections
  1580. ! on each nest was implemented in subroutine in4dob.
  1581. !********************************************************************
  1582. ! SET RA AND RB
  1583. DO N=1,NSTAT
  1584. RA(N)=RIO(N)-GRIDX
  1585. RB(N)=RJO(N)-GRIDY
  1586. ENDDO
  1587. ! INITIALIZE WEIGHTING ARRAYS TO ZERO
  1588. DO I=its,ite
  1589. DO K=1,kte
  1590. WT(I,K)=0.0
  1591. WT2ERR(I,K)=0.0
  1592. ENDDO
  1593. ENDDO
  1594. ! DO P* COMPUTATIONS ON DOT POINTS FOR IVAR.LT.3 (U AND V)
  1595. ! AND CROSS POINTS FOR IVAR.GE.3 (T,Q,P*).
  1596. !
  1597. ! COMPUTE P* AT OBS LOCATION (RA,RB). DO THIS AS SEPARATE VECTOR LOOP H
  1598. ! SO IT IS ALREADY AVAILABLE IN NSTAT LOOP 120 BELOW
  1599. ! PSURF IS NOT AVAILABLE GLOBALLY, THEREFORE, THE BILINEAR INTERPOLATION
  1600. ! AROUND THE OBS POINT IS DONE IN ERROB() AND STORED IN ERRF([678],N) FOR
  1601. ! THE POINT (6=PRESS, 7=U-MOM, 8=V-MOM).
  1602. ! ajb 05052009: psurf is actually pbase(k=1) interpolated to obs (i,j).
  1603. DO N=1,NSTAT
  1604. IF(IVAR.GE.3)THEN
  1605. PSURF(N)=ERRF(6,N)
  1606. ELSE
  1607. IF(IVAR.EQ.1)THEN
  1608. PSURF(N)=ERRF(7,N) ! U-points
  1609. ELSE
  1610. PSURF(N)=ERRF(8,N) ! V-points
  1611. ENDIF
  1612. ENDIF
  1613. ENDDO
  1614. ! DETERMINE THE LIMITS OF THE SEARCH REGION FOR THE CURRENT
  1615. ! J-STRIP
  1616. MAXJ=J+IFIX(RINDX*RINFMX+0.99) !ajb
  1617. MINJ=J-IFIX(RINDX*RINFMX+0.99) !ajb
  1618. ! jc comment out this? want to use obs beyond the domain?
  1619. ! MAXJ=MIN0(JL-IGRID,MAXJ) !yliu
  1620. ! MINJ=MAX0(1,MINJ) !yliu
  1621. n=1
  1622. !***********************************************************************
  1623. DO nnn=1,NSTAT ! BEGIN OUTER LOOP FOR THE NSTAT OBSERVATIONS
  1624. !***********************************************************************
  1625. ! Soundings are consecutive obs, but they need to be treated as a single
  1626. ! entity. Thus change the looping to nnn, with n defined separately.
  1627. !yliu
  1628. ! note for sfc data: nsndlev=1 and njcsnd=1
  1629. nsndlev=int(nlevs_ob(n)-lev_in_ob(n))+1
  1630. ! yliu start -- set together with the other parts
  1631. ! test: do the sounding levels as individual obs
  1632. ! nsndlev=1
  1633. ! yliu end
  1634. njcsnd=nsndlev
  1635. ! set pob here, to be used later
  1636. pob=varobs(5,n)
  1637. ! print *, "s-- n=,nsndlev",n,njcsnd,J, ipl
  1638. ! print *, "s--",ivar,(errf(ivar,i),i=n,n+njcsnd)
  1639. ! CHECK TO SEE OF STATION N HAS DATA FOR VARIABLE IVAR
  1640. ! AND IF IT IS SUFFICIENTLY CLOSE TO THE J STRIP. THIS
  1641. ! SHOULD ELIMINATE MOST STATIONS FROM FURTHER CONSIDER-
  1642. ! ATION.
  1643. !yliu: Skip bad obs if it is sfc or single level sounding.
  1644. !yliu: Before this (020918), a snd will be skipped if its first
  1645. !yliu level has bad data- often true due to elevation
  1646. IF( ABS(ERRF(IVAR,N)).GT.9.E4 .and. njcsnd.eq.1 ) THEN
  1647. ! print *, " bad obs skipped"
  1648. ELSEIF( RB(N).LT.FLOAT(MINJ) .OR. RB(N).GT.FLOAT(MAXJ) ) THEN
  1649. ! print *, " skipped obs far away from this J-slice"
  1650. !----------------------------------------------------------------------
  1651. ELSE ! BEGIN SECTION FOR PROCESSING THE OBSERVATION
  1652. !----------------------------------------------------------------------
  1653. ! DETERMINE THE LIMITS OF APPLICATION OF THE OBS IN THE VERTICAL
  1654. ! FOR THE VERTICAL WEIGHTING, WTSIG
  1655. ! ASSIMILATE OBSERVATIONS ON PRESSURE LEVELS, EXCEPT FOR SURFACE
  1656. !ajb 20021210: (Bugfix) RKO is not available globally. It is computed in
  1657. !ajb ERROB() by the processor handling the obs point, and stored in ERRF(9,N).
  1658. #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
  1659. rko(n) = errf(9,n) !ajb 20021210
  1660. kpbl_obs(n) = errf(5,n) !ajb 20090519
  1661. #endif
  1662. !ajb 20090427 added .45 to rko so KOB is equal to 1 only if RKO > 1.05
  1663. KOB=nint(RKO(N)+0.45)
  1664. KOB=MIN0(kte,KOB)
  1665. KOB=MAX0(1,KOB)
  1666. ! ASSIMILATE SURFACE LAYER DATA ON SIGMA
  1667. IF(KOB.EQ.1.AND.IVAR.LE.4.and.nlevs_ob(n).lt.1.5) THEN
  1668. ! Compute temporal weight
  1669. timewt = get_timewt(xtime,dtmin,twindo,sfcfact,timeob(n))
  1670. DO K=1,kte
  1671. WTSIG(K)=0.0
  1672. ENDDO
  1673. ! DEFINE WTSIG: (FOR SRP: SPREAD SURFACE DATA THROUGH LOWEST 200 M)
  1674. ! WTSIG(1)=1.0
  1675. ! WTSIG(2)=0.67
  1676. ! WTSIG(3)=0.33
  1677. ! KOMIN=3
  1678. ! KOMAX=1
  1679. ! DEFINE THE MAX AND MIN I VALUES FOR POSSIBLE NONZERO
  1680. ! WEIGHTS, BASED ON THE RADIUS OF INFLUENCE, RINDX (IN GRID LENGTHS).
  1681. ! fix this because kpblt at 1 and il is 0
  1682. MAXI=IFIX(RA(N)+0.99+RINDX*sfcfacr)
  1683. MAXI=MIN0(ide-1,MAXI)
  1684. MINI=IFIX(RA(N)-RINDX*sfcfacr-0.99)
  1685. MINI=MAX0(2,MINI)
  1686. !yliu start
  1687. ! use also obs outside of this domain -- surface obs
  1688. ! if(RA(N).LT.0.-RINDX .or. RA(N).GT.float(IL+RINDX) .or.
  1689. ! & RB(N).LT.0.-RINDX .or. RB(N).GT.float(JL+RINDX)) then
  1690. ! print *, " skipped obs far away from this domain"
  1691. ! currently can use obs within this domain or ones very close to (1/3
  1692. ! influence of radius in the coarse domain) this
  1693. ! domain. In later case, use BC column value to approximate the model value
  1694. ! at obs point -- ERRF need model field in errob.F !!
  1695. if ( RA(N).GE.(0.-RINDX*sfcfacr/3) &
  1696. .and. RA(N).LE.float(ide)+RINDX*sfcfacr/3 &
  1697. .and. RB(N).GE.(0.-RINDX*sfcfacr/3) &
  1698. .and. RB(N).LE.float(jde)+RINDX*sfcfacr/3) then
  1699. ! or use obs within this domain only
  1700. ! if(RA(N).LT.1 .or. RA(N).GT.float(IL) .or.
  1701. ! & RB(N).LT.1 .or. RB(N).GT.float(JL)) then
  1702. ! print *, " skipped obs far outside of this domain"
  1703. ! if(j.eq.3 .and. ivar.eq.3) then
  1704. ! write(6,*) 'N = ',n,' exit 120 3'
  1705. ! endif
  1706. !yliu end
  1707. !
  1708. ! LOOP THROUGH THE NECESSARY GRID POINTS SURROUNDING
  1709. ! OBSERVATION N. COMPUTE THE HORIZONTAL DISTANCE TO
  1710. ! THE OBS AND FIND THE WEIGHTING SUM OVER ALL OBS
  1711. RJ=FLOAT(J)
  1712. RX=RJ-RB(N)
  1713. ! WEIGHTS FOR THE 3-D VARIABLES
  1714. ERFIVR=ERRF(IVAR,N)
  1715. !ajb Compute and add weights to sum only if nudge_pbl switch is on.
  1716. if(nudge_pbl) then
  1717. ! Apply selected horizontal spreading scheme.
  1718. if(SFC_SCHEME_HORIZ.eq.1) then ! original mm5 scheme
  1719. DO I=max0(its,MINI),min0(ite,MAXI)
  1720. RI=FLOAT(I)
  1721. RY=RI-RA(N)
  1722. RIS=RINDX*RINDX*sfcfacr*sfcfacr
  1723. RSQ=RX*RX+RY*RY
  1724. ! THIS FUNCTION DECREASES WTIJ AS PSFC CHANGES WITHIN SEARCH RADIUS
  1725. DPRIM=SQRT(RSQ)
  1726. D=DPRIM+RINDX*DCON*ABS(psurf(n)-.001*pbase(i,1))
  1727. DSQ=D*D
  1728. WTIJ(i)=(RIS-DSQ)/(RIS+DSQ)
  1729. WTIJ(i)=AMAX1(0.0,WTIJ(i))
  1730. ENDDO
  1731. else ! wrf scheme
  1732. DO I=max0(its,MINI),min0(ite,MAXI)
  1733. RI=FLOAT(I)
  1734. RY=RI-RA(N)
  1735. RIS=RINDX*RINDX*sfcfacr*sfcfacr
  1736. RSQ=RX*RX+RY*RY
  1737. ! THIS FUNCTION DECREASES WTIJ AS PSFC CHANGES WITHIN SEARCH RADIUS
  1738. wtij(i)=(ris-rsq)/(ris+rsq)
  1739. scratch = (abs (psurf(n)-.001*pbase(i,1))*DCON)
  1740. pdfac=1.-AMIN1(1.0,scratch)
  1741. wtij(i)=wtij(i)*pdfac
  1742. WTIJ(i)=AMAX1(0.0,WTIJ(i))
  1743. ENDDO
  1744. endif
  1745. ! Apply selected vertical spreading scheme.
  1746. if(SFC_SCHEME_VERT.eq.1) then ! original simple scheme
  1747. DO I=max0(its,MINI),min0(ite,MAXI)
  1748. ! try making sfc obs weighting go thru pbl
  1749. komax=max0(3,kpblt(i))
  1750. IF (iprt) THEN
  1751. if (kpblt(i).gt.25 .and. ktau.ne.0) &
  1752. write(6,552)inest,i,j,kpblt(i)
  1753. 552 FORMAT('kpblt is gt 25, inest,i,j,kpblt=',4i4)
  1754. ENDIF
  1755. if(kpblt(i).gt.25) komax=3
  1756. komin=1
  1757. dk=float(komax)
  1758. do k=komin,komax
  1759. wtsig(k)=float(komax-k+1)/dk
  1760. WT(I,K)=WT(I,K)+TIMEWT*WTSIG(K)*WTIJ(i)
  1761. WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ(i)*WTIJ(i)*WTSIG(K) &
  1762. *WTSIG(K)*ERFIVR
  1763. enddo
  1764. ENDDO
  1765. else ! regime-based vif scheme
  1766. ! Here we calculate weights in the vertical coordinate, based on vih1 and vih2.
  1767. ! In the equation for wtsig(k), Z=zslab(i,k)-terrh(i) contains the model Z-values
  1768. ! (height above ground in meters) on a J-slab. The equation produces wtsig = 1.0 at
  1769. ! levels 1 to K, where z(K) < vih1 < z(K+1). For the example below, in the equation
  1770. ! for wtsig(k), the expression vih1(i)-Z(i,k) is strictly positive for k=1,2,3 since
  1771. ! levels 1, 2, and 3 are below vih1. So xtsig(k)=min(1.0, 1.0-x) where x > 0 ==>
  1772. ! wtsig(k)=1 for k=1,2,3.
  1773. !
  1774. ! For levels K+1 and up, wtsig will decrease linearly with height, with values
  1775. ! along the ramp that has value 1.0 at vih1 and 0.0 at vih2. In the example:
  1776. !
  1777. ! dz_ramp = 1/(200-150) = 1/50
  1778. ! xtsig(4) = 1 + (150-175)/50 = 1 - 1/2 = 1/2
  1779. !
  1780. ! WTSIG
  1781. ! 1 -|* * * * * *
  1782. ! |
  1783. ! | *
  1784. ! |
  1785. ! | *
  1786. ! |
  1787. ! | *
  1788. ! 0 -|--|-------|-----------|------|----|----|---------|----> Z = HT ABOVE
  1789. ! 15 55 115 150 175 200 250 GROUND
  1790. ! k=1 k=2 k=3 vih1 k=4 vih2 k=5
  1791. DO I=max0(its,MINI),min0(ite,MAXI)
  1792. dz_ramp = 1.0 / max( 1.0, vih2(i)-vih1(i) ) ! vih2 >= vih1 by construct
  1793. LML: do k = kts, kte
  1794. wtsig(k) = min( 1.0, 1.0 + ( vih1(i)-zslab(i,k)+terrh(i) ) * dz_ramp )
  1795. wtsig(k) = max( 0.0, wtsig(k))
  1796. if(wtsig(k).le.0.0) EXIT LML
  1797. WT(I,K)=WT(I,K)+TIMEWT*WTSIG(K)*WTIJ(i)
  1798. WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ(i)*WTIJ(i)*WTSIG(K) &
  1799. *WTSIG(K)*ERFIVR
  1800. enddo LML
  1801. ENDDO
  1802. endif
  1803. endif ! end if nudge-pbl switch is on
  1804. endif ! end check for obs in domain
  1805. ! END SURFACE-LAYER OBS NUDGING
  1806. ELSE
  1807. ! Compute temporal weight
  1808. timewt = get_timewt(xtime,dtmin,twindo,1.,timeob(n))
  1809. ! BEGIN CALCULATIONS TO SPREAD OBS INFLUENCE ALONG PRESSURE LEVELS
  1810. !
  1811. ! print *,'in upper air section'
  1812. ! DEFINE THE MAX AND MIN I VALUES FOR POSSIBLE NONZERO
  1813. ! WEIGHTS, BASED ON THE RADIUS OF INFLUENCE, RINDX, AND RINFAC.
  1814. ! RINFAC VARIES AS A LINEAR FUNCTION FROM FROM RINFMN AT P*+PTOP
  1815. ! TO RINFMX AT PFREE AND "ABOVE" (LOWER PRESSURE).
  1816. !ajb SLOPE=(RINFMN-RINFMX)/(PSBO(N)+PTOP-PFREE)
  1817. slope = (RINFMN-RINFMX)/(psurf(n)-PFREE)
  1818. RINFAC=SLOPE*POB+RINFMX-SLOPE*pfree
  1819. RINFAC=AMAX1(RINFAC,RINFMN)
  1820. RINFAC=AMIN1(RINFAC,RINFMX)
  1821. !yliu: for multilevel upper-air data, take the maximum
  1822. ! for the I loop.
  1823. if(nsndlev.gt.1) RINFAC = RINFMX
  1824. !yliu end
  1825. MAXI=IFIX(RA(N)+0.99+RINDX*RINFAC)
  1826. MAXI=MIN0(ide-IGRID,MAXI)
  1827. MINI=IFIX(RA(N)-RINDX*RINFAC-0.99)
  1828. MINI=MAX0(1,MINI)
  1829. ! yliu start
  1830. ! use also obs outside of but close to this domain -- upr data
  1831. ! if( RA(N).LT.(0.-RINFAC*RINDX)
  1832. ! & .or. RA(N).GT.float(IL)+RINFAC*RINDX
  1833. ! & .or. RB(N).LT.(0.-RINFAC*RINDX)
  1834. ! & .or. RB(N).GT.float(JL)+RINFAC*RINDX)then
  1835. ! print *, " skipped obs far away from this I-range"
  1836. ! currently can use obs within this domain or ones very close to (1/3
  1837. ! influence of radius in the coarse domain) this
  1838. ! domain. In later case, use BC column value to approximate the model value
  1839. ! at obs point -- ERRF need model field in errob.F !!
  1840. !cc if (i.eq.39 .and. j.eq.34) then
  1841. !cc write(6,*) 'RA(N) = ',ra(n)
  1842. !cc write(6,*) 'rinfac = ',rinfac,' rindx = ',rindx
  1843. !cc endif
  1844. if( RA(N).GE.(0.-RINFAC*RINDX/3) &
  1845. .and. RA(N).LE.float(ide)+RINFAC*RINDX/3 &
  1846. .and. RB(N).GE.(0.-RINFAC*RINDX/3) &
  1847. .and. RB(N).LE.float(jde)+RINFAC*RINDX/3) then
  1848. ! or use obs within this domain only
  1849. ! if(RA(N).LT.1 .or. RA(N).GT.float(IL) .or.
  1850. ! & RB(N).LT.1 .or. RB(N).GT.float(JL)) then
  1851. ! print *, " skipped obs far outside of this domain"
  1852. ! yliu end
  1853. ! is this 2 needed here - kpbl not used?
  1854. ! MINI=MAX0(2,MINI)
  1855. ! LOOP THROUGH THE NECESSARY GRID POINTS SURROUNDING
  1856. ! OBSERVATION N. COMPUTE THE HORIZONTAL DISTANCE TO
  1857. ! THE OBS AND FIND THE WEIGHTING SUM OVER ALL OBS
  1858. RJ=FLOAT(J)
  1859. RX=RJ-RB(N)
  1860. ! WEIGHTS FOR THE 3-D VARIABLES
  1861. !
  1862. ERFIVR=ERRF(IVAR,N)
  1863. ! jc
  1864. nsndlev=int(nlevs_ob(n)-lev_in_ob(n))+1
  1865. ! yliu start
  1866. ! test: do the sounding levels as individual obs
  1867. ! nsndlev=1
  1868. ! yliu end
  1869. njcsnd=nsndlev
  1870. !
  1871. DO I=max0(its,MINI),min0(ite,MAXI)
  1872. ! jc
  1873. RI=FLOAT(I)
  1874. RY=RI-RA(N)
  1875. RIS=RINDX*RINFAC*RINDX*RINFAC
  1876. RSQ=RX*RX+RY*RY
  1877. ! yliu test: for upper-air data, keep D1 influence radii
  1878. WTIJ(i)=(RIS-RSQ)/(RIS+RSQ)
  1879. WTIJ=AMAX1(0.0,WTIJ(i))
  1880. ! weight ob in vertical with +- 50 mb
  1881. ! yliu: 75 hba for single upper-air, 30hba for multi-level soundings
  1882. if(nsndlev.eq.1) then
  1883. rinprs=7.5
  1884. !
  1885. else
  1886. rinprs=3.0
  1887. endif
  1888. ! yliu end
  1889. !$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
  1890. ! --- HANDLE 1-LEVEL and MULTI-LEVEL OBSERVATIONS SEPARATELY ---
  1891. !$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
  1892. if(nsndlev.eq.1)then
  1893. !----------------------------------------------------------------------
  1894. ! --- HANDLE 1-LEVEL OBSERVATIONS ---
  1895. !----------------------------------------------------------------------
  1896. ! if(I.eq.MINI) print *, " Single snd "
  1897. ! ERFIVR is the residual (difference) between the ob and the model
  1898. ! at that point. We can analyze that residual up and down.
  1899. ! First find komin for ob.
  1900. !yliu start -- in the old code, komax and komin were reversed!
  1901. do k=kte,1,-1
  1902. pijk = .001*(pbase(i,k)+pp(i,k))
  1903. ! print *,'k,pijk,pob,rinprs=',k,pijk,pob,rinprs
  1904. if(pijk.ge.(pob+rinprs)) then
  1905. komin=k
  1906. go to 325
  1907. endif
  1908. enddo
  1909. komin=1
  1910. 325 continue
  1911. ! now find komax for ob
  1912. do k=3,kte
  1913. pijk = .001*(pbase(i,k)+pp(i,k))
  1914. if(pijk.le.(pob-rinprs)) then
  1915. komax=k
  1916. go to 326
  1917. endif
  1918. enddo
  1919. komax=kte ! yliu 20050706
  1920. 326 continue
  1921. ! yliu: single-level upper-air data will act either above or below the PBL top
  1922. ! ajb: Reset komin or komax. if kobs>kpbl_obs, komin=kpbl_obs+1, else komax=kpbl_obs
  1923. if( (kpblt(i).le.komax) .and. (kpblt(i).ge.komin) ) then
  1924. kobs = 1
  1925. OBS_K: do k = komin, komax
  1926. if( pob .gt. .001*(pbase(i,k)+pp(i,k)) ) then
  1927. kobs = k
  1928. EXIT OBS_K
  1929. endif
  1930. enddo OBS_K
  1931. if(kobs.gt.kpbl_obs(n)) then
  1932. ! Obs will act only above the PBL top
  1933. komin=max0(kobs, komin) ! kobs here is kpblt(i)+1
  1934. else ! Obs acts below PBL top
  1935. ! Obs will act only below the PBL top
  1936. komax=min0(kpblt(i), komax)
  1937. endif
  1938. endif
  1939. ! yliu end
  1940. !
  1941. ! print *,'1 level, komin,komax=',komin,komax
  1942. ! if(i.eq.MINI) then
  1943. ! print *, "yyyyyyyyyyS IPL erfivr=", IPL, ERFIVR,J,pob
  1944. ! ERFIVR=0
  1945. ! endif
  1946. do k=1,kte
  1947. reserf(k)=0.0
  1948. wtsig(k)=0.0
  1949. enddo
  1950. !yliu end
  1951. !ajb Add weights to sum only if nudge_pbl switch is on OR obs is above pbl top.
  1952. if(nudge_pbl .or. komin.ge.kpblt(i)) then
  1953. do k=komin,komax
  1954. pijk = .001*(pbase(i,k)+pp(i,k))
  1955. reserf(k)=erfivr
  1956. wtsig(k)=1.-abs(pijk-pob)/rinprs
  1957. wtsig(k)=amax1(wtsig(k),0.0)
  1958. ! print *,'k,pijk,pob,rinprs,wtsig=',k,pijk,pob,rinprs,wtsig(k)
  1959. ! Now calculate WT and WT2ERR for each i,j,k point cajb
  1960. WT(I,K)=WT(I,K)+TIMEWT*WTIJ(i)*wtsig(k)
  1961. WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ(i)*WTIJ(i)* &
  1962. reserf(k)*wtsig(k)*wtsig(k)
  1963. enddo
  1964. endif
  1965. else
  1966. !----------------------------------------------------------------------
  1967. ! --- HANDLE MULTI-LEVEL OBSERVATIONS ---
  1968. !----------------------------------------------------------------------
  1969. !yliu start
  1970. ! if(I.eq.MINI) print *, " Multi-level snd "
  1971. ! print *, " n=,nsndlev",n,nsndlev,nlevs_ob(n),lev_in_ob(n) &
  1972. ! ,nlevs_ob(n+nsndlev-1),lev_in_ob(n+nsndlev-1)
  1973. if(nlevs_ob(n+nsndlev-1).ne.lev_in_ob(n+nsndlev-1)) then
  1974. IF (iprt) THEN
  1975. write(msg,*) "n = ",n,"nsndlev = ",nsndlev
  1976. call wrf_message(msg)
  1977. write(msg,*) "nlevs_ob,lev_in_ob", &
  1978. nlevs_ob(n+nsndlev-1),lev_in_ob(n+nsndlev-1)
  1979. call wrf_message(msg)
  1980. call wrf_message("in nudobs.F: sounding level messed up, stopping")
  1981. ENDIF
  1982. call wrf_error_fatal ( 'wrf_fddaobs_in: in4dob' )
  1983. endif
  1984. !yliu end
  1985. ! This is for a multi-level observation
  1986. ! The trick here is that the sounding is "one ob". You don't
  1987. ! want multiple levels to each be treated like separate
  1988. ! and independent observations.
  1989. ! At each i,j want to interpolate sounding to the model levels at that
  1990. ! particular point.
  1991. komin=1
  1992. komax=kte-2
  1993. ! this loop goes to 1501
  1994. ! do from kte-2 to 1 so don't adjust top of model. Arbitrary.
  1995. !yliu start
  1996. do k=1,kte
  1997. reserf(k)=0.0
  1998. wtsig(k)=0.0
  1999. enddo
  2000. !yliu end
  2001. do k=komax,komin,-1
  2002. pijk = .001*(pbase(i,k)+pp(i,k))
  2003. ! if sigma level pressure is .gt. than the lowest ob level, don't interpolate
  2004. if(pijk.gt.varobs(5,n)) then
  2005. go to 1501
  2006. endif
  2007. ! if sigma level pressure is .lt. than the highest ob level, don't interpolate
  2008. if(pijk.le.varobs(5,n+nsndlev-1)) then
  2009. go to 1501
  2010. endif
  2011. ! now interpolate sounding to this k
  2012. ! yliu start-- recalculate WTij for each k-level
  2013. !ajb SLOPE = (RINFMN-RINFMX)/(pdoc(i,j)+PTOP-PFREE)
  2014. slope = (RINFMN-RINFMX)/ (.001*pbase(i,1)-PFREE)
  2015. RINFAC=SLOPE*pijk+RINFMX-SLOPE*PFREE
  2016. RINFAC=AMAX1(RINFAC,RINFMN)
  2017. RINFAC=AMIN1(RINFAC,RINFMX)
  2018. RIS=RINDX*RINFAC*RINDX*RINFAC
  2019. RSQ=RX*RX+RY*RY
  2020. ! for upper-air data, keep D1 influence radii
  2021. WTIJ(i)=(RIS-RSQ)/(RIS+RSQ)
  2022. WTIJ(i)=AMAX1(0.0,WTIJ(i))
  2023. ! yliu end
  2024. ! this loop goes to 1503
  2025. do nn=2,nsndlev
  2026. ! only set pobhi if varobs(ivar) is ok
  2027. pobhi=-888888.
  2028. if(varobs(ivar,n+nn-1).gt.-800000. &
  2029. .and. varobs(5,n+nn-1).gt.-800000.) then
  2030. pobhi=varobs(5,n+nn-1)
  2031. nhi=n+nn-1
  2032. if(pobhi.lt.pijk .and. abs(pobhi-pijk).lt.0.5*maxsnd_gap) then
  2033. go to 1502 ! within maxsnd_gap/2 of obs height
  2034. endif
  2035. endif
  2036. enddo
  2037. ! did not find any ob above within maxsnd_gap/2, so jump out
  2038. go to 1501
  2039. 1502 continue
  2040. nlo=nhi-1
  2041. do nnjc=nhi-1,n,-1
  2042. if(varobs(ivar,nnjc).gt.-800000. &
  2043. .and. varobs(5,nnjc).gt.-800000.) then
  2044. poblo=varobs(5,nnjc)
  2045. nlo=nnjc
  2046. if(poblo.gt.pijk .and. abs(poblo-pijk).lt.0.5*maxsnd_gap) then
  2047. go to 1505 ! within maxsnd_gap/2 of obs height
  2048. endif
  2049. endif
  2050. enddo
  2051. !yliu end --
  2052. ! did not find any ob below within maxsnd_gap/2, so jump out
  2053. go to 1501
  2054. 1505 continue
  2055. ! interpolate to model level
  2056. pdiffj=alog(pijk/poblo)/alog(pobhi/poblo)
  2057. reserf(k)=errf(ivar,nlo)+ &
  2058. (errf(ivar,nhi)-errf(ivar,nlo))*pdiffj
  2059. wtsig(k)=1.
  2060. 1501 continue
  2061. ! now calculate WT and WT2ERR for each i,j,k point cajb
  2062. !ajb Add weights to sum only if nudge_pbl switch is on OR k > kpblt.
  2063. if(nudge_pbl .or. k.gt.kpblt(i)) then
  2064. WT(I,K)=WT(I,K)+TIMEWT*WTIJ(i)*wtsig(k)
  2065. WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ(i)*WTIJ(i)* &
  2066. reserf(k)*wtsig(k)*wtsig(k)
  2067. endif
  2068. enddo ! enddo k levels
  2069. ! end multi-levels
  2070. endif ! end if(nsndlev.eq.1)
  2071. !$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
  2072. ! END 1-LEVEL AND MULTI-LEVEL OBSERVATIONS
  2073. !$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
  2074. !
  2075. ENDDO ! END DO MINI,MAXI LOOP
  2076. endif ! check for obs in domain
  2077. ! END OF NUDGING TO OBS ON PRESSURE LEVELS
  2078. ENDIF !end IF(KOB.EQ.1.AND.IVAR.LE.4.and.nlevs_ob(n).lt.1.5)
  2079. !----------------------------------------------------------------------
  2080. ENDIF ! END SECTION FOR PROCESSING OF OBSERVATION
  2081. !----------------------------------------------------------------------
  2082. ! n=n+1
  2083. n=n+njcsnd
  2084. !yliu 1202 continue
  2085. if(n.gt.nstat)then
  2086. ! print *,'n,nstat=',n,nstat,ivar,j
  2087. go to 1203
  2088. endif
  2089. ! print *, "e-- n=,nsndlev",n,njcsnd,nlevs_ob(n),lev_in_ob(n)
  2090. !***********************************************************************
  2091. ENDDO ! END OUTER LOOP FOR THE NSTAT OBSERVATIONS
  2092. !***********************************************************************
  2093. 1203 continue
  2094. ! WEIGHTS AND WEIGHTED DIFFERENCES HAVE BEEN SUMMED. NOW
  2095. ! APPLY THE NUDGING FACTOR AND THE RESULTANT TENDENCY TO
  2096. ! THE ATEN ARRAY
  2097. ! ASSURE THAT WT(I,K) AND WTP(I,K) ARE NONZERO SINCE
  2098. ! THEY ARE USED BELOW IN THE DENOMINATOR.
  2099. DO K=kts,kte
  2100. DO I=its,ite
  2101. IF(WT(I,K).EQ.0)THEN
  2102. WT2ERR(I,K)=0.0
  2103. ENDIF
  2104. IF(WT(I,K).EQ.0)THEN
  2105. WT(I,K)=1.0
  2106. ENDIF
  2107. ENDDO
  2108. ENDDO
  2109. 126 CONTINUE
  2110. IF(IVAR.GE.3)GOTO 170
  2111. ! this is for u,v
  2112. ! 3-D DOT POINT TENDENCIES
  2113. ! Calculate scales for converting nudge factor from u (v)
  2114. ! to rho_u (or rho_v) units.
  2115. IF (IVAR == 1) THEN
  2116. call calc_rcouple_scales(mu,msfy,rscale,ims,ime,its,ite)
  2117. ELSE IF (IVAR == 2) THEN
  2118. call calc_rcouple_scales(mu,msfx,rscale,ims,ime,its,ite)
  2119. END IF
  2120. DO K=1,kte
  2121. DO I=i_s,i_e
  2122. IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
  2123. W2EOWT=WT2ERR(I,K)/WT(I,K)
  2124. ELSE
  2125. W2EOWT=SAVWT(IPL,I,K)
  2126. ! write(6,'(a,4i4,f8.3)') 'i,j,k,ipl,W2EOWT = ',i,j,k,ipl,W2EOWT
  2127. ENDIF
  2128. ! if(ivar .eq. 1 .and. i.eq.38 .and. j.eq.78 .and. k.eq.1) then
  2129. ! scratch = GIV*RSCALE(I)*W2EOWT*TFACI*ISWIND*GFACTOR
  2130. ! write(6,*) 'ATEN calc: k = ',k
  2131. ! write(6,*) 'U before: aten = ',aten(i,k),' scr = ',scratch
  2132. ! write(6,*) 'GIV = ',giv,' rscale = ',rscale(i),
  2133. ! $ ' W2EOWT = ',w2eowt
  2134. ! write(6,*) 'TFACI = ',tfaci,' ISWIND = ',iswind,
  2135. ! $ ' GFACTOR = ',gfactor
  2136. ! endif
  2137. !
  2138. ! if(ivar .eq. 2 .and. i.eq.39 .and. j.eq.29) then
  2139. ! scratch = GIV*RSCALE(I)*W2EOWT*TFACI*ISWIND*GFACTOR
  2140. ! write(6,*) 'ATEN calc: k = ',k
  2141. ! write(6,*) 'V before: aten = ',aten(i,k),' scr = ',scratch
  2142. ! write(6,*) 'GIV = ',giv,' rscale = ',rscale(i),
  2143. ! $ ' W2EOWT = ',w2eowt
  2144. ! write(6,*) 'TFACI = ',tfaci,' ISWIND = ',iswind,
  2145. ! $ ' GFACTOR = ',gfactor
  2146. ! endif
  2147. ! if(ivar .eq. 1 .and. i.eq.38 .and. (j.ge.36.and.j.le.62) .and. k.eq.7) then
  2148. ! scratch = GIV*RSCALE(I)*W2EOWT*TFACI*ISWIND*GFACTOR
  2149. ! write(6,*)
  2150. ! write(6,*) 'ATEN calc: j = ',j,' k = ',k
  2151. ! write(6,*) 'U before: aten = ',aten(i,k),' scr = ',scratch
  2152. ! write(6,*) 'GIV = ',giv,' rscale = ',rscale(i),' W2EOWT = ',w2eowt
  2153. ! write(6,*) 'TFACI = ',tfaci,' ISWIND = ',iswind,' GFACTOR = ',gfactor
  2154. ! endif
  2155. ATEN(i,k)=ATEN(i,k)+GIV*RSCALE(I) &
  2156. *W2EOWT*TFACI &
  2157. *ISWIND *GFACTOR !yliu *GFACTOR
  2158. ! if(ivar .eq. 1 .and. i.eq.38 .and. j.eq.78 .and. k.eq.1) then
  2159. ! write(6,*) 'U after: aten = ',aten(i,k),' scr = ',scratch
  2160. ! endif
  2161. ! if(ivar .eq. 2 .and. i.eq.39 .and. j.eq.29) then
  2162. ! write(6,*) 'V after: aten = ',aten(i,k),' scr = ',scratch
  2163. ! endif
  2164. ENDDO
  2165. ENDDO
  2166. IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
  2167. DO K=1,kte
  2168. DO I=its,ite
  2169. SAVWT(IPL,I,K)=WT2ERR(I,K)/WT(I,K)
  2170. ! write(6,'(a,4i4,f8.3)') 'i,j,k,ipl,savwt = ',i,j,k,ipl,savwt(ipl,i,k)
  2171. ENDDO
  2172. ENDDO
  2173. ENDIF
  2174. RETURN
  2175. 170 CONTINUE
  2176. ! 3-D CROSS-POINT TENDENCIES
  2177. ! this is for t (ivar=3) and q (ivsr=4)
  2178. IF(3-IVAR.LT.0)THEN
  2179. GITQ=GIQ
  2180. ELSE
  2181. GITQ=GIT
  2182. ENDIF
  2183. IF(3-IVAR.LT.0)THEN
  2184. ISTQ=ISMOIS
  2185. ELSE
  2186. ISTQ=ISTEMP
  2187. ENDIF
  2188. DO K=1,kte
  2189. DO I=i_s,i_e
  2190. IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
  2191. W2EOWT=WT2ERR(I,K)/WT(I,K)
  2192. ELSE
  2193. W2EOWT=SAVWT(IPL,I,K)
  2194. ENDIF
  2195. ! if(ivar .eq. 3 .and. i.eq.39 .and. j.eq.49) then
  2196. ! scratch = GITQ*MU(I)*W2EOWT*TFACI*ISTQ*GFACTOR
  2197. ! write(6,*) 'ATEN calc: k = ',k
  2198. ! write(6,*) 'T before: aten = ',aten(i,k),' scr = ',scratch
  2199. ! write(6,*) 'GITQ = ',gitq,' MU = ',mu(i), &
  2200. ! ' W2EOWT = ',w2eowt
  2201. ! write(6,*) ' TFACI = ',tfaci,' ISTQ = ',istq, &
  2202. ! ' GFACTOR = ',gfactor
  2203. ! endif
  2204. ! if(ivar .eq. 4 .and. i.eq.39 .and. j.eq.29) then
  2205. ! scratch = GITQ*MU(I)*W2EOWT*TFACI*ISTQ*GFACTOR
  2206. ! write(6,*) 'ATEN calc: k = ',k
  2207. ! write(6,*) 'Q before: aten = ',aten(i,k),' scr = ',scratch
  2208. ! write(6,*) 'GITQ = ',gitq,' MU = ',mu(i),
  2209. ! $ ' W2EOWT = ',w2eowt
  2210. ! write(6,*) ' TFACI = ',tfaci,' ISTQ = ',istq,
  2211. ! $ ' GFACTOR = ',gfactor
  2212. ! endif
  2213. ATEN(i,k)=ATEN(i,k)+GITQ*MU(I) &
  2214. *W2EOWT*TFACI*ISTQ *GFACTOR !yliu *GFACTOR
  2215. ! if(ivar .eq. 3 .and. i.eq.39 .and. j.eq.49) then
  2216. ! write(6,*) 'T after: aten = ',aten(i,k),' scr = ',scratch
  2217. ! endif
  2218. ! if(ivar .eq. 4 .and. i.eq.39 .and. j.eq.29) then
  2219. ! write(6,*) 'Q after: aten = ',aten(i,k),' scr = ',scratch
  2220. ! endif
  2221. ENDDO
  2222. ENDDO
  2223. IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR)) THEN
  2224. DO K=1,kte
  2225. DO I=its,ite
  2226. SAVWT(IPL,I,K)=WT2ERR(I,K)/WT(I,K)
  2227. ENDDO
  2228. ENDDO
  2229. ENDIF
  2230. RETURN
  2231. END SUBROUTINE nudob
  2232. SUBROUTINE date_string(year, month, day, hour, minute, second, cdate)
  2233. !-----------------------------------------------------------------------
  2234. ! PURPOSE: Form a date string (YYYY-MM-DD_hh:mm:ss) from integer
  2235. ! components.
  2236. !-----------------------------------------------------------------------
  2237. IMPLICIT NONE
  2238. !-----------------------------------------------------------------------
  2239. INTEGER, INTENT(IN) :: year
  2240. INTEGER, INTENT(IN) :: month
  2241. INTEGER, INTENT(IN) :: day
  2242. INTEGER, INTENT(IN) :: hour
  2243. INTEGER, INTENT(IN) :: minute
  2244. INTEGER, INTENT(IN) :: second
  2245. CHARACTER*19, INTENT(INOUT) :: cdate
  2246. ! Local variables
  2247. integer :: ic ! loop counter
  2248. cdate(1:19) = "0000-00-00_00:00:00"
  2249. write(cdate( 1: 4),'(i4)') year
  2250. write(cdate( 6: 7),'(i2)') month
  2251. write(cdate( 9:10),'(i2)') day
  2252. write(cdate(12:13),'(i2)') hour
  2253. write(cdate(15:16),'(i2)') minute
  2254. write(cdate(18:19),'(i2)') second
  2255. do ic = 1,19
  2256. if(cdate(ic:ic) .eq. " ") cdate(ic:ic) = "0"
  2257. enddo
  2258. RETURN
  2259. END SUBROUTINE date_string
  2260. SUBROUTINE calc_rcouple_scales(a, msf, rscale, ims,ime, its,ite)
  2261. !-----------------------------------------------------------------------
  2262. IMPLICIT NONE
  2263. !-----------------------------------------------------------------------
  2264. INTEGER, INTENT(IN) :: ims,ime ! Memory dimensions
  2265. INTEGER, INTENT(IN) :: its,ite ! Tile dimensions
  2266. REAL, INTENT(IN) :: a( ims:ime ) ! Air mass array
  2267. REAL, INTENT(IN) :: msf( ims:ime ) ! Map scale factor array
  2268. REAL, INTENT(OUT) :: rscale( ims:ime ) ! Scales for rho-coupling
  2269. ! Local variables
  2270. integer :: i
  2271. ! Calculate scales to be used for producing rho-coupled nudging factors.
  2272. do i = its,ite
  2273. rscale(i) = a(i)/msf(i)
  2274. enddo
  2275. RETURN
  2276. END SUBROUTINE calc_rcouple_scales
  2277. SUBROUTINE print_obs_info(iprt,inest,niobf,rio,rjo,rko, &
  2278. prt_max,prt_freq,obs,stnid,lat,lon, &
  2279. mlat,mlon,timeob,xtime)
  2280. !*************************************************************************
  2281. ! Purpose: Print obs information.
  2282. !*************************************************************************
  2283. IMPLICIT NONE
  2284. LOGICAL, intent(in) :: iprt ! Print flag
  2285. INTEGER, intent(in) :: inest ! Nest level
  2286. INTEGER, intent(in) :: niobf ! Maximum number of observations
  2287. REAL, intent(in) :: rio(niobf) ! West-east coord (non-stagger)
  2288. REAL, intent(in) :: rjo(niobf) ! South-north coord (non-stagger)
  2289. REAL, intent(in) :: rko(niobf) ! Bottom-top north coord (non-stagger)
  2290. INTEGER, intent(in) :: prt_max ! Max no. of obs for diagnostic printout
  2291. INTEGER, intent(in) :: prt_freq ! Frequency for diagnostic printout
  2292. INTEGER, intent(in) :: obs(prt_max) ! Saved obs indices to print
  2293. INTEGER, intent(in) :: stnid(40,prt_max) ! Saved station ids
  2294. REAL, intent(in) :: lat(prt_max) ! Saved latitudes
  2295. REAL, intent(in) :: lon(prt_max) ! Saved longitudes
  2296. REAL, intent(in) :: mlat(prt_max) ! Saved model latitudes
  2297. REAL, intent(in) :: mlon(prt_max) ! Saved longitudes
  2298. REAL, intent(in) :: timeob(niobf) ! Times of each observation (hours)
  2299. REAL, intent(in) :: xtime ! Model time in minutes
  2300. ! Local variables
  2301. integer :: i ! Loop counter over obs station chars
  2302. integer :: n ! Loop counter over obs
  2303. integer :: pnx ! Obs index for printout
  2304. character(len=200) :: msg ! Argument to wrf_message
  2305. character(len=20) :: station_id ! Station id of observation
  2306. if(iprt) then
  2307. if(prt_max.gt.0) then
  2308. if(obs(1).ne.-999) then
  2309. call wrf_message("")
  2310. write(msg,fmt='(a,i4,a,f8.1,a)') 'REPORTING OBS MASS-PT LOCS FOR NEST ', &
  2311. inest,' AT XTIME=',xtime,' MINUTES'
  2312. call wrf_message(msg)
  2313. write(msg,fmt='(a,i4,a,i5,a)') 'FREQ=',prt_freq,', MAX=',prt_max, &
  2314. ' LOCS, NEWLY READ OBS ONLY, -999 => OBS OFF PROC'
  2315. call wrf_message(msg)
  2316. call wrf_message("")
  2317. write(msg,fmt='(3a)') ' OBS# I J K OBS LAT', &
  2318. ' OBS LON XLAT(I,J) XLONG(I,J) TIME(hrs)', &
  2319. ' OBS STATION ID'
  2320. call wrf_message(msg)
  2321. endif
  2322. endif
  2323. ! Note: rio and rjo are referenced to non-staggered grid (not mass-point!)
  2324. ! Hence subtract .5 from each to get mass-point coords.
  2325. do n=1,prt_max
  2326. pnx = obs(n)
  2327. if(pnx.ne.-999) then
  2328. ! Retrieve 15 chars of station id
  2329. do i = 1,15
  2330. station_id(i:i) = char(stnid(i,n))
  2331. enddo
  2332. write(msg,fmt='(2x,i7,3f8.3,2f9.3,2x,f9.3,2x,f9.3,3x,f6.2,7x,a15)') &
  2333. pnx,rio(pnx)-.5,rjo(pnx)-.5,rko(pnx),lat(n),lon(n), &
  2334. mlat(n),mlon(n),timeob(pnx),station_id
  2335. call wrf_message(msg)
  2336. endif
  2337. enddo
  2338. if(obs(1).ne.-999) call wrf_message("")
  2339. endif
  2340. END SUBROUTINE print_obs_info
  2341. REAL FUNCTION ht_to_p( h, pbbc, ppbc, z, ic, jc, dx, dy, &
  2342. k_start, k_end, kds,kde, ims,ime, jms,jme, kms,kme )
  2343. !******************************************************************************
  2344. ! Purpose: Interpolate pressure at a specified x (ic), y (jc), and height (h).
  2345. ! The input pressure column pbbc+ppbc (base and perturbn) must already
  2346. ! be horizontally interpolated to the x, y position. The subroutine
  2347. ! get_height_column is called here to horizontally interpolated the
  2348. ! 3D height field z to get a height column at (iob, job).
  2349. !******************************************************************************
  2350. IMPLICIT NONE
  2351. REAL, INTENT(IN) :: h ! height value (m)
  2352. INTEGER, INTENT(IN) :: k_start, k_end ! loop bounds
  2353. INTEGER, INTENT(IN) :: kds,kde ! vertical dim.
  2354. INTEGER, INTENT(IN) :: ims,ime, jms,jme, kms,kme ! memory dims.
  2355. REAL, INTENT(IN) :: pbbc(kds:kde) ! column base pressure (cb)
  2356. REAL, INTENT(IN) :: ppbc(kds:kde) ! column pressure perturbation (cb)
  2357. REAL, INTENT(IN) :: z( ims:ime, kms:kme, jms:jme ) ! ht (m) above sl on half-levels
  2358. INTEGER, INTENT(IN) :: ic ! i-coord of desired p
  2359. INTEGER, INTENT(IN) :: jc ! j-coord of desired p
  2360. REAL, INTENT(IN) :: dx ! interp. fraction (x dir)
  2361. REAL, INTENT(IN) :: dy ! interp. fraction (y dir)
  2362. ! Local variables
  2363. INTEGER :: k ! loop counter
  2364. INTEGER :: klo ! lower k bound
  2365. REAL :: zlo ! lower z bound for h
  2366. REAL :: zhi ! upper z bound for h
  2367. REAL :: p ! interpolated pressure value
  2368. REAL :: ln_p ! log p
  2369. REAL :: ln_plo ! log plo
  2370. REAL :: ln_phi ! log phi
  2371. REAL :: z_at_p( kms:kme ) ! height at p levels
  2372. ! Get interpolated z column on pressure (half-) levels at (ic,jc)
  2373. call get_height_column(z, ic, jc, dx, dy, z_at_p, &
  2374. k_start, k_end, kds,kde, &
  2375. ims,ime, jms,jme, kms,kme )
  2376. ! Now we have pbbc, ppbc, z_at_p, so compute p at h. First, find
  2377. ! bounding layers klo and khi so that z_at_p(klo) <= h <= z_at_p(khi)
  2378. ZLEVS: do k = k_start+1, k_end
  2379. klo = k-1
  2380. if(h .le. z_at_p(k)) then
  2381. EXIT ZLEVS
  2382. endif
  2383. enddo ZLEVS
  2384. zlo = z_at_p(klo)
  2385. zhi = z_at_p(klo+1)
  2386. ! Interpolate natural log of pressure
  2387. ln_plo = log( pbbc(klo+1) + ppbc(klo+1) )
  2388. ln_phi = log( pbbc(klo) + ppbc(klo) )
  2389. if(h.le.zlo) then
  2390. ln_p = ln_phi ! set to k=1 pressure
  2391. else if (h.ge.zhi) then
  2392. ln_p = ln_plo ! set to k=k_end pressure
  2393. else
  2394. ln_p = ln_plo + (ln_phi-ln_plo)*((zhi-h)/(zhi-zlo))
  2395. endif
  2396. ! Return pressure
  2397. p = exp(ln_p)
  2398. ht_to_p = p
  2399. RETURN
  2400. END FUNCTION ht_to_p
  2401. SUBROUTINE get_height_column( z, ic, jc, dx, dy, z_at_p, &
  2402. k_start, k_end, kds,kde, &
  2403. ims,ime, jms,jme, kms,kme )
  2404. !*************************************************************************
  2405. ! Purpose: Compute column height at ic, jc location on p levels
  2406. !*************************************************************************
  2407. IMPLICIT NONE
  2408. INTEGER, INTENT(IN) :: k_start, k_end ! Loop bounds
  2409. INTEGER, INTENT(IN) :: kds,kde ! vertical dim.
  2410. INTEGER, INTENT(IN) :: ims,ime, jms,jme, kms,kme ! memory dims.
  2411. REAL, INTENT(IN) :: z( ims:ime, kms:kme, jms:jme ) ! ht (m) on half-levels
  2412. INTEGER, INTENT(IN) :: ic ! i-coord of desired p
  2413. INTEGER, INTENT(IN) :: jc ! j-coord of desired p
  2414. REAL, INTENT(IN) :: dx ! interp. fraction (x dir)
  2415. REAL, INTENT(IN) :: dy ! interp. fraction (y dir)
  2416. REAL, INTENT(OUT) :: z_at_p( kms:kme ) ! column height at p levels
  2417. ! Local variables
  2418. INTEGER :: k ! loop counter
  2419. do k = kds, kde
  2420. z_at_p(k) = &
  2421. (1.-DY)*( (1.-DX)*z(IC,K,JC) + &
  2422. DX *z(IC+1,K,JC) ) + &
  2423. DY* ( (1.-DX)*z(IC,K,JC+1) + &
  2424. DX *z(IC+1,K,JC+1) )
  2425. enddo
  2426. END SUBROUTINE get_height_column
  2427. SUBROUTINE get_base_state_height_column( p_top, p00, t00, a, g, r_d, &
  2428. znu, z_at_p, k_start, k_end, kds,kde, kms,kme )
  2429. !********************************************************
  2430. ! Purpose: Compute base-state column height on p levels.
  2431. ! See, e.g., eqns 1.3-1.5 in MM5 User's Guide.
  2432. ! Height is a function of pressure plus the constants:
  2433. ! p00 - sea level pressure (Pa)
  2434. ! t00 - sea level temperature (K)
  2435. ! a - base state lapse rate (k/m)
  2436. ! r_d - gas constant (J/Kg/K) (Joule=1kg/m**2/s**2)
  2437. ! g - gravitational constant (m/s**2)
  2438. !********************************************************
  2439. IMPLICIT NONE
  2440. REAL, INTENT(IN) :: p_top ! pressure at top of model
  2441. REAL, INTENT(IN) :: p00 ! base state pressure
  2442. REAL, INTENT(IN) :: t00 ! base state temperature
  2443. REAL, INTENT(IN) :: a ! base state lapse rate
  2444. REAL, INTENT(IN) :: g ! gravity constant
  2445. REAL, INTENT(IN) :: r_d ! gas constant
  2446. INTEGER, INTENT(IN) :: k_start, k_end ! Loop bounds
  2447. INTEGER, INTENT(IN) :: kds,kde ! vertical dim.
  2448. INTEGER, INTENT(IN) :: kms,kme ! vertical memory dim.
  2449. REAL, INTENT(IN) :: znu( kms:kme ) ! eta values on half (mass) levels
  2450. REAL, INTENT(OUT) :: z_at_p( kms:kme ) ! column height at p levels
  2451. ! Local variables
  2452. integer :: k ! loop counter
  2453. real :: ps0 ! base state pressure at surface
  2454. real :: pb(kms:kme) ! pressure on half eta levels
  2455. real :: logterm ! temporary for Z calculation
  2456. real :: ginv ! 1/g
  2457. ginv = 1/g
  2458. ! Compute base state pressure on half eta levels.
  2459. do k = k_start, k_end
  2460. pb(k) = znu(k)*(p00 - p_top) + p_top
  2461. enddo
  2462. ! Use hydrostatic relation to compute height at pressure levels.
  2463. do k = k_start, k_end
  2464. logterm = log(pb(k)/p00)
  2465. z_at_p(k) = .5*r_d*a*ginv*logterm*logterm - r_d*t00*ginv*logterm
  2466. enddo
  2467. END SUBROUTINE get_base_state_height_column
  2468. REAL FUNCTION get_timewt(xtime,dtmin,twindo,scalef,obtime)
  2469. !*************************************************************************
  2470. ! Purpose: Compute the temporal weight factor for an observation
  2471. !*************************************************************************
  2472. IMPLICIT NONE
  2473. REAL, INTENT(IN) :: xtime ! model time (minutes)
  2474. REAL, INTENT(IN) :: dtmin ! model timestep (minutes)
  2475. REAL, INTENT(IN) :: twindo ! half window (hours)
  2476. REAL, INTENT(IN) :: scalef ! window scale factor
  2477. REAL, INTENT(IN) :: obtime ! observation time (hours)
  2478. ! Local variables
  2479. real :: fdtim ! reference time (minutes)
  2480. real :: tw1 ! half of twindo, scaled, in minutes
  2481. real :: tw2 ! twindo, scaled, in minutes
  2482. real :: tconst ! reciprical of tw1
  2483. real :: ttim ! obtime in minutes
  2484. real :: dift ! | fdtim-ttim |
  2485. real :: timewt ! returned weight
  2486. ! DETERMINE THE TIME-WEIGHT FACTOR FOR N
  2487. FDTIM=XTIME-DTMIN
  2488. ! TWINDO IS IN MINUTES:
  2489. TW1=TWINDO/2.*60.*scalef
  2490. TW2=TWINDO*60.*scalef
  2491. TCONST=1./TW1
  2492. TIMEWT=0.0
  2493. TTIM=obtime*60.
  2494. !***********TTIM=TARGET TIME IN MINUTES
  2495. DIFT=ABS(FDTIM-TTIM)
  2496. IF(DIFT.LE.TW1)TIMEWT=1.0
  2497. IF(DIFT.GT.TW1.AND.DIFT.LE.TW2) THEN
  2498. IF(FDTIM.LT.TTIM)TIMEWT=(FDTIM-(TTIM-TW2))*TCONST
  2499. IF(FDTIM.GT.TTIM)TIMEWT=((TTIM+TW2)-FDTIM)*TCONST
  2500. ENDIF
  2501. get_timewt = timewt
  2502. END FUNCTION get_timewt
  2503. SUBROUTINE print_vif_var(var, vif, nfullmin, nrampmin )
  2504. !********************************************************
  2505. ! Purpose: Print a description of the vertical influence
  2506. ! function for a given variable.
  2507. !********************************************************
  2508. IMPLICIT NONE
  2509. character(len=4), intent(in) :: var ! Variable (wind, temp, mois)
  2510. real, intent(in) :: vif(6) ! Vertical influence function
  2511. real, intent(in) :: nfullmin ! Vert infl fcn full nudge min
  2512. real, intent(in) :: nrampmin ! Vert infl fcn ramp decr min
  2513. ! Local variables
  2514. character(len=200) :: msg1, msg2
  2515. character(len=8) :: regime
  2516. real :: nfullr1, nrampr1
  2517. real :: nfullr2, nrampr2
  2518. real :: nfullr4, nrampr4
  2519. nfullr1 = vif(1)
  2520. nrampr1 = vif(2)
  2521. nfullr2 = vif(3)
  2522. nrampr2 = vif(4)
  2523. nfullr4 = vif(5)
  2524. nrampr4 = vif(6)
  2525. if(var.eq.'wind') then
  2526. write(msg1,fmt='(a)') ' For winds:'
  2527. elseif (var.eq.'temp') then
  2528. write(msg1,fmt='(a)') ' For temperature:'
  2529. elseif (var.eq.'mois') then
  2530. write(msg1,fmt='(a)') ' For moisture:'
  2531. else
  2532. write(msg1,fmt='(a,a4)') 'Unknown variable type: ',var
  2533. call wrf_message(msg1)
  2534. call wrf_error_fatal ( 'print_vif_var: module_fddaobs_rtfdda STOP' )
  2535. endif
  2536. call wrf_message(msg1)
  2537. ! For this variable, print a description of the vif for each regime
  2538. call print_vif_regime(1, nfullr1, nrampr1, nfullmin, nrampmin)
  2539. call print_vif_regime(2, nfullr2, nrampr2, nfullmin, nrampmin)
  2540. call print_vif_regime(4, nfullr4, nrampr4, nfullmin, nrampmin)
  2541. END SUBROUTINE print_vif_var
  2542. SUBROUTINE print_vif_regime(reg, nfullr, nrampr, nfullmin, nrampmin )
  2543. !********************************************************
  2544. ! Purpose: Print a description of the vertical influence
  2545. ! function for a given regime.
  2546. !********************************************************
  2547. IMPLICIT NONE
  2548. integer, intent(in) :: reg ! Regime number (1, 2, 4)
  2549. real, intent(in) :: nfullr ! Full nudge range for regime
  2550. real, intent(in) :: nrampr ! Rampdown range for regime
  2551. real, intent(in) :: nfullmin ! Vert infl fcn full nudge min
  2552. real, intent(in) :: nrampmin ! Vert infl fcn ramp decr min
  2553. ! Local variables
  2554. character(len=200) :: msg1, msg2
  2555. character(len=8) :: regime
  2556. if(reg.eq.1) then
  2557. write(regime,fmt='(a)') 'Regime 1'
  2558. elseif (reg.eq.2) then
  2559. write(regime,fmt='(a)') 'Regime 2'
  2560. elseif (reg.eq.4) then
  2561. write(regime,fmt='(a)') 'Regime 4'
  2562. else
  2563. write(msg1,fmt='(a,i3)') 'Unknown regime number: ',reg
  2564. call wrf_message(msg1)
  2565. call wrf_error_fatal ( 'print_vif_regime: module_fddaobs_rtfdda STOP' )
  2566. endif
  2567. !Set msg1 for description of full weighting range
  2568. if(nfullr.lt.0) then
  2569. if(nfullr.eq.-5000) then
  2570. write(msg1,fmt='(2x,a8,a)') regime, ': Full weighting to the PBL top'
  2571. elseif (nfullr.lt.-5000) then
  2572. write(msg1,fmt='(2x,a8,a,i4,a)') regime, ': Full weighting to ',int(-5000.-nfullr), &
  2573. ' m above the PBL top'
  2574. else
  2575. write(msg1,fmt='(2x,a8,a,i4,a)') regime, ': Full weighting to ',int(nfullr+5000.), &
  2576. ' m below the PBL top'
  2577. endif
  2578. else
  2579. write(msg1,fmt='(2x,a8,a,i4,a)') regime, ': Full weighting through ', &
  2580. int(max(nfullr,nfullmin)),' m'
  2581. endif
  2582. !Set msg2 for description of rampdown range
  2583. if(nrampr.lt.0) then
  2584. if(nrampr.eq.-5000) then
  2585. write(msg2,fmt='(a)') ' and a vertical rampdown up to the PBL top.'
  2586. elseif (nrampr.lt.-5000) then
  2587. write(msg2,fmt='(a,i4,a)') ' and a vertical rampdown to ',int(-5000.-nrampr), &
  2588. ' m above the PBL top.'
  2589. else
  2590. write(msg2,fmt='(a,i4,a)') ' and a vertical rampdown to ',int(nrampr+5000.), &
  2591. ' m below the PBL top.'
  2592. endif
  2593. else
  2594. write(msg2,fmt='(a,i4,a)') ' and a vertical rampdown in the next ', &
  2595. int(max(nrampr,nrampmin)),' m.'
  2596. endif
  2597. call wrf_message(TRIM(msg1)//msg2)
  2598. END SUBROUTINE print_vif_regime
  2599. #endif
  2600. END MODULE module_fddaobs_rtfdda