PageRenderTime 67ms CodeModel.GetById 23ms 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

Large files files are truncated, but you can click here to view the full file

  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* &

Large files files are truncated, but you can click here to view the full file