PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/wrfv2_fire/phys/module_fr_sfire_phys.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 1755 lines | 965 code | 237 blank | 553 comment | 75 complexity | bc832edc5d8b31d4f09e343acb31d622 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. !
  2. !*** Jan Mandel August-October 2007 email: jmandel@ucar.edu or Jan.Mandel@gmail.com
  3. !
  4. ! This file contains parts copied and/or adapted from earlier codes by
  5. ! Terry Clark, Janice Coen, Don Latham, and Net Patton.
  6. module module_fr_sfire_phys
  7. use module_model_constants, only: cp,xlv
  8. use module_fr_sfire_util
  9. implicit none
  10. PRIVATE
  11. type fire_params
  12. real,pointer,dimension(:,:):: vx,vy ! wind velocity (m/s)
  13. real,pointer,dimension(:,:):: zsf ! terrain height (m)
  14. real,pointer,dimension(:,:):: dzdxf,dzdyf ! terrain grad (1)
  15. real,pointer,dimension(:,:):: bbb,phisc,phiwc,r_0 ! spread formula coefficients
  16. real,pointer,dimension(:,:):: fgip ! init mass of surface fuel (kg/m^2)
  17. real,pointer,dimension(:,:):: ischap ! 1 if chapparal
  18. real,pointer,dimension(:,:):: fuel_time ! time to burn to 1/e (s)
  19. real,pointer,dimension(:,:):: fmc_g ! fuel moisture contents, ground (1)
  20. real,pointer,dimension(:,:):: nfuel_cat ! fuel category (integer values)
  21. end type fire_params
  22. ! subroutines and functions
  23. PUBLIC:: init_fuel_cats,fire_ros,heat_fluxes,set_nfuel_cat,set_fire_params, &
  24. write_fuels_m,fire_risk,fire_intensity,fuel_moisture,advance_moisture,fuel_name,&
  25. fire_rate_of_spread
  26. ! types
  27. public:: fire_params
  28. ! variables
  29. PUBLIC:: fire_wind_height,fcz0,fcwh,have_fuel_cats,nfuelcats,no_fuel_cat,no_fuel_cat2,windrf,moisture_classes
  30. PUBLIC:: mfuelcats
  31. ! NOTE: fcwh and fcz0 are called fwh and fz0 in read/write statements
  32. ! moisture behavior, see Mandel et al EGU 2012
  33. !! To add moisture classes:
  34. ! 1. change parameter max_moisture_classes below
  35. ! 2. change the default of nfmc to the same value in Registry/registry.fire
  36. ! 3. add the appropriate lines real::fmc_gw<number>= <default values>
  37. ! 4. add dfault
  38. !*** dimensions
  39. INTEGER, PARAMETER :: mfuelcats = 30 ! max number of fuel categories
  40. integer, parameter::max_moisture_classes=5
  41. !***
  42. integer, parameter::zm=max_moisture_classes - 3
  43. integer:: moisture_classes=3
  44. real, dimension(max_moisture_classes):: drying_lag,wetting_lag,saturation_moisture,saturation_rain, &
  45. rain_threshold,rec_drying_lag_sec,rec_wetting_lag_sec
  46. integer, dimension(max_moisture_classes):: drying_model,wetting_model,fmc_gc_initialization
  47. ! relative weights of moisture class for each fuel category
  48. integer::itmp
  49. CHARACTER (len=80), DIMENSION(max_moisture_classes), save :: moisture_class_name
  50. real, dimension(mfuelcats):: & ! should sum up to one
  51. fmc_gw01=(/ (1.0, itmp=1,mfuelcats) /), &
  52. fmc_gw02=(/ (0.0, itmp=1,mfuelcats) /), &
  53. fmc_gw03=(/ (0.0, itmp=1,mfuelcats) /), &
  54. fmc_gw04=(/ (0.0, itmp=1,mfuelcats) /), &
  55. fmc_gw05=(/ (0.0, itmp=1,mfuelcats) /)
  56. data moisture_class_name /'1-hour fuel','10-hour fuel','100-hour fuel',zm*'NOT USED'/
  57. data drying_lag /1., 10., 100. , zm*0./ ! time lag (h) approaching equilibrium moisture
  58. data wetting_lag /14, 140., 1400., zm*0./ ! time lag (h) for approaching saturation in rain
  59. data saturation_moisture /2.5, 2.5, 2.5 , zm*0./ ! saturation moisture contents (1) in rain
  60. data saturation_rain /8.0, 8.0, 8.0 , zm*0./ ! stronger rain matters only in duration (mm/h)
  61. data rain_threshold /0.05, 0.05, 0.05, zm*0 /! rain intensity this small is same as nothing
  62. data drying_model /1, 1, 1, zm*1 /
  63. data wetting_model /1, 1, 1, zm*1 /
  64. data fmc_gc_initialization /2, 2, 2, zm*2 / ! initialization 0=input, 1=from fuelmc_g, 2=from equilibrium
  65. real, dimension(7)::eq_p
  66. data eq_p/ 1.035e-09, & !(3.893e-10, 1.681e-09) ! coefficients of the equilibrium fuel moisture polynomial
  67. -2.62e-07, & !(-4.593e-07, -6.473e-08) ! fitted from the graph in Schroeder and Buck (1970)
  68. 2.507e-05, & !(2.194e-06, 4.795e-05)
  69. -0.001107, & !(-0.002353, 0.000139)
  70. 0.02245, & !(-0.009188, 0.05409)
  71. -0.05901, & !(-0.3721, 0.254)
  72. 3.043/ !(2.17, 3.915)
  73. ! =========================================================================
  74. ! Following table copied from module_fr_cawfe_fuel by Ned Patton with minor changes.
  75. ! Based on: Clark, T. L., J. L. Coen and D. Latham: 2004,
  76. ! "Description of a coupled atmosphere-fire model",
  77. ! International Journal of Wildland Fire, 13, 49-63.
  78. !
  79. ! edited by Jan Mandel jmandel@ucar.edu September 2007
  80. !
  81. ! - moved all fuel related constants and the initialization subroutine here
  82. ! - copied descriptions for fuel categories from fire_sfc.m4 in the original CAWFE code
  83. ! This file had to be copied under a new name because packages in wrf physics
  84. ! layer are not allowed to call each other.
  85. !D in col 2 means quantity derived from the others
  86. !
  87. ! Scalar constants (data same for all fuel categories):
  88. ! HFGL SURFACE FIRE HEAT FLUX THRESHOLD TO IGNITE CANOPY (W/m^2)
  89. ! CMBCNST JOULES PER KG OF DRY FUEL
  90. ! FUELHEAT FUEL PARTICLE LOW HEAT CONTENT, BTU/LB
  91. ! FUELMC_G FUEL PARTICLE (SURFACE) MOISTURE CONTENT
  92. !D BMST RATIO OF LATENT TO SENSIBLE HEAT FROM SFC BURN:
  93. ! % of total fuel mass that is water (not quite
  94. ! = % fuel moisture). BMST= (H20)/(H20+DRY)
  95. ! so BMST = FUELMC_G / (1 + FUELMC_G) where
  96. ! FUELMC_G = ground fuel moisture
  97. !
  98. ! Data arrays indexed by fuel category:
  99. ! FGI INITIAL TOTAL MASS OF SURFACE FUEL (KG/M**2)
  100. ! FUELDEPTHM FUEL DEPTH, IN M (CONVERTED TO FT)
  101. ! SAVR FUEL PARTICLE SURFACE-AREA-TO-VOLUME RATIO, 1/FT
  102. ! GRASS: 3500., 10 hr fuel: 109., 100 hr fuel: 30.
  103. ! FUELMCE MOISTURE CONTENT OF EXTINCTION; 0.30 FOR MANY DEAD FUELS; 0.15 FOR GRASS
  104. ! FUELDENS OVENDRY PARTICLE DENSITY, LB/FT^3
  105. ! ST FUEL PARTICLE TOTAL MINERAL CONTENT
  106. ! SE FUEL PARTICLE EFFECTIVE MINERAL CONTENT
  107. ! WEIGHT WEIGHTING PARAMETER THAT DETERMINES THE SLOPE OF THE MASS LOSS CURVE
  108. ! RANGES FROM ~5 (FAST BURNUP) TO 1000 ( ~40% DECR OVER 10 MIN).
  109. ! FCI_D INITIAL DRY MASS OF CANOPY FUEL
  110. ! FCT BURN OUT TIME FOR CANOPY FUEL, AFTER DRY (S)
  111. ! ichap 1 if chaparral, 0 if not
  112. !D FCI INITIAL TOTAL MASS OF CANOPY FUEL
  113. !D FCBR FUEL CANOPY BURN RATE (KG/M**2/S)
  114. !
  115. ! scalar fuel coefficients
  116. REAL, SAVE:: cmbcnst,hfgl,fuelmc_g,fuelmc_c, fire_wind_height
  117. ! computed values
  118. REAL, SAVE:: fuelheat
  119. ! defaults, may be changed in init_fuel_cats
  120. DATA cmbcnst / 17.433e+06/ ! J/kg dry fuel
  121. DATA hfgl / 17.e4 / ! W/m^2
  122. DATA fuelmc_g / 0.08 / ! set = 0 for dry ground fuel
  123. DATA fuelmc_c / 1.00 / ! set = 0 for dry canopy
  124. DATA fire_wind_height/6.096/ ! m, 6.096m Behave, 0 to use fwh in each category
  125. ! REAL, PARAMETER :: bmst = fuelmc_g/(1+fuelmc_g)
  126. ! REAL, PARAMETER :: fuelheat = cmbcnst * 4.30e-04 ! convert J/kg to BTU/lb
  127. ! real, parameter :: xlv = 2.5e6 ! to make it selfcontained
  128. ! real, parameter :: cp = 7.*287./2 ! to make it selfcontained
  129. ! fuel categorytables
  130. INTEGER, PARAMETER :: nf=14 ! fuel cats in data stmts, for fillers only`
  131. INTEGER, SAVE :: nfuelcats = 13 ! number of fuel categories, can be reset from namelist.fire
  132. INTEGER, PARAMETER :: zf = mfuelcats-nf ! number of zero fillers in data stmt
  133. INTEGER, SAVE :: no_fuel_cat = 14 ! special no fuel category outside of 1:nfuelcats
  134. INTEGER, SAVE :: no_fuel_cat2 = 14 ! all categories between no_fuel_cat and no_fuel_cat2 are no fuel
  135. INTEGER, SAVE :: ibeh=1 ! type of spread formula
  136. CHARACTER (len=80), DIMENSION(mfuelcats ), save :: fuel_name
  137. INTEGER, DIMENSION( mfuelcats ), save :: ichap
  138. REAL , DIMENSION( mfuelcats ), save :: windrf,weight,fgi,fci,fci_d,fct,fcbr, &
  139. fueldepthm,fueldens,fuelmce, &
  140. fcwh,fcz0, ffw, &
  141. savr,st,se,adjr0,adjrw,adjrs, &
  142. fmc_gl_stdev,fmc_gl_ndwi_0,fmc_gl_ndwi_rate,fmc_gl_ndwi_stdev
  143. REAL , DIMENSION( mfuelcats , max_moisture_classes), save :: fmc_gw
  144. ! =============================================================================
  145. ! Standard 13 fire behavior fuel models (for surface fires), along with some
  146. ! estimated canopy properties (for crown fire).
  147. ! =============================================================================
  148. DATA fuel_name / &
  149. 'FUEL MODEL 1: Short grass (1 ft)', &
  150. 'FUEL MODEL 2: Timber (grass and understory)', &
  151. 'FUEL MODEL 3: Tall grass (2.5 ft)', &
  152. 'FUEL MODEL 4: Chaparral (6 ft)', &
  153. 'FUEL MODEL 5: Brush (2 ft) ', &
  154. 'FUEL MODEL 6: Dormant brush, hardwood slash', &
  155. 'FUEL MODEL 7: Southern rough', &
  156. 'FUEL MODEL 8: Closed timber litter', &
  157. 'FUEL MODEL 9: Hardwood litter', &
  158. 'FUEL MODEL 10: Timber (litter + understory)', &
  159. 'FUEL MODEL 11: Light logging slash', &
  160. 'FUEL MODEL 12: Medium logging slash', &
  161. 'FUEL MODEL 13: Heavy logging slash', &
  162. 'FUEL MODEL 14: no fuel', &
  163. zf*' '/
  164. DATA windrf /0.36, 0.36, 0.44, 0.55, 0.42, 0.44, 0.44, &
  165. 0.36, 0.36, 0.36, 0.36, 0.43, 0.46, 1e-7, zf*0 / ! added jmandel October 2010
  166. DATA fgi / 0.166, 0.897, 0.675, 2.468, 0.785, 1.345, 1.092, &
  167. 1.121, 0.780, 2.694, 2.582, 7.749, 13.024, 1.e-7, zf*0. /
  168. DATA fueldepthm /0.305, 0.305, 0.762, 1.829, 0.61, 0.762,0.762, &
  169. 0.0610, 0.0610, 0.305, 0.305, 0.701, 0.914, 0.305,zf*0. /
  170. DATA savr / 3500., 2784., 1500., 1739., 1683., 1564., 1562., &
  171. 1889., 2484., 1764., 1182., 1145., 1159., 3500., zf*0. /
  172. DATA fuelmce / 0.12, 0.15, 0.25, 0.20, 0.20, 0.25, 0.40, &
  173. 0.30, 0.25, 0.25, 0.15, 0.20, 0.25, 0.12 , zf*0. /
  174. DATA fueldens / nf * 32., zf*0. / ! 32 if solid, 19 if rotten.
  175. DATA st / nf* 0.0555 , zf*0./
  176. DATA se / nf* 0.010 , zf*0./
  177. ! ----- Notes on weight: (4) - best fit of Latham data;
  178. ! (5)-(7) could be 60-120; (8)-(10) could be 300-1600;
  179. ! (11)-(13) could be 300-1600
  180. DATA weight / 7., 7., 7., 180., 100., 100., 100., &
  181. 900., 900., 900., 900., 900., 900., 7. , zf*0./
  182. ! ----- 1.12083 is 5 tons/acre. 5-50 tons/acre orig., 100-300 after blowdown
  183. DATA fci_d / 0., 0., 0., 1.123, 0., 0., 0., &
  184. 1.121, 1.121, 1.121, 1.121, 1.121, 1.121, 0., zf*0./
  185. DATA fct / 60., 60., 60., 60., 60., 60., 60., &
  186. 60., 120., 180., 180., 180., 180. , 60. , zf*0. /
  187. DATA ichap / 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , zf*0/
  188. DATA fcwh / 6.096, 6.096, 6.096, 6.096, 6.096, 6.096, 6.096, &
  189. 6.096, 6.096, 6.096, 6.096, 6.096, 6.096, 6.096, zf*0. / ! consistent with BEHAVE
  190. ! roughness length 0.13*fueldepthm except cat 3 fz0=0.1 for consistency with landuse
  191. ! fz0 = 0.0396,0.0396,0.0991,0.2378,0.0793,0.0991,0.0991,
  192. DATA fcz0 / 0.0396,0.0396,0.1000,0.2378,0.0793,0.0991,0.0991, &
  193. 0.0079,0.0079,0.0396,0.0396,0.0911,0.1188,0.0396, zf * 0. /
  194. !DATA fcwh /0.6 , 0.6, 1.5, 36, 1.2, 1.5, 1.5, &
  195. ! 0.12, 0.12, 0.6, 0.6, 1.38, 1.8, 1.8, zf*0 / ! fuel wind height, added jm 2/23/11
  196. !DATA fcz0 /0.3, 0.3, 0.75, 18., 0.6, 0.75, 0.75, &
  197. ! 0.06, 0.06, 0.3, 0.3, 0.69, 0.9, 0.9, zf*0 / ! fuel roughness height, added jm 2/23/11
  198. DATA ffw /nf* 0.9, zf*0/
  199. DATA fmc_gl_ndwi_0 /nf*0.1, zf*0./
  200. DATA fmc_gl_ndwi_rate /nf*0.6, zf*0./
  201. DATA fmc_gl_ndwi_stdev /nf*0.2, zf*0./
  202. DATA fmc_gl_stdev /nf*0.2, zf*0./
  203. DATA adjr0 /mfuelcats*1./
  204. DATA adjrw /mfuelcats*1./
  205. DATA adjrs /mfuelcats*1./
  206. ! =========================================================================
  207. logical, save :: have_fuel_cats=.false.
  208. contains
  209. subroutine fuel_moisture( &
  210. id, & ! for prints and maybe file names
  211. nfmc, &
  212. ids,ide, jds,jde, & ! atm grid dimensions
  213. ims,ime, jms,jme, &
  214. ips,ipe,jps,jpe, &
  215. its,ite,jts,jte, &
  216. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  217. ifms, ifme, jfms, jfme, &
  218. ifts,ifte,jfts,jfte, &
  219. ir,jr, & ! atm/fire grid ratio
  220. nfuel_cat, & ! fuel data
  221. fndwi, & ! satellite sensing on fire grid
  222. fmc_gc, & ! moisture contents by class on atmospheric grid
  223. fmc_g & ! weighted fuel moisture contents on fire grid
  224. )
  225. implicit none
  226. !**** arguments
  227. integer, intent(in):: &
  228. id,nfmc, &
  229. ids,ide, jds,jde, & ! atm grid dimensions
  230. ims,ime, jms,jme, &
  231. ips,ipe,jps,jpe, &
  232. its,ite,jts,jte, &
  233. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  234. ifms, ifme, jfms, jfme, &
  235. ifts,ifte,jfts,jfte, &
  236. ir,jr ! atm/fire grid ratio
  237. real,intent(in),dimension(ifms:ifme,jfms:jfme):: nfuel_cat, & ! fuel data
  238. fndwi ! satellite sensing interpolated to fire grid
  239. real,intent(inout),dimension(ims:ime,nfmc,jms:jme):: fmc_gc
  240. real,intent(out),dimension(ifms:ifme,jfms:jfme):: fmc_g ! fuel data
  241. !**** local
  242. real, dimension(its-1:ite+1,jts-1:jte+1):: fmc_k ! copy of fmc_gc(:,k,:)
  243. real, dimension(ifts:ifte,jfts:jfte):: fmc_f, & ! interpolation of fmc_gc(:,k,:) to the fire grid
  244. nwdi_f ! inerpolation of nwdi to the fire grid
  245. integer::i,j,k,n
  246. integer::ibs,ibe,jbs,jbe
  247. real::f1,w1,w2,f2,fa,fc
  248. character(len=128)::msg
  249. call check_mesh_2dim(ifts,ifte,jfts,jfte,ifds,ifde,jfds,jfde) ! check if fire tile fits into domain
  250. call check_mesh_2dim(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme) ! check if fire tile fits into memory
  251. do j=jfts,jfte
  252. do i=ifts,ifte
  253. fmc_g(i,j)=0. ! initialize sum over classes
  254. enddo
  255. enddo
  256. ! one beyond the tile but not beyond the domain boundary
  257. ibs=max(ids,its-1)
  258. ibe=min(ide,ite+1)
  259. jbs=max(jds,jts-1)
  260. jbe=min(jde,jte+1)
  261. call check_mesh_2dim(ibs,ibe,jbs,jbe,ims,ime,jms,jme) ! check if tile with halo fits into memory
  262. do k=1,moisture_classes
  263. ! copy halo beyond the tile but not beyond the domain boundary
  264. do j=jbs,jbe
  265. do i=ibs,ibe
  266. fmc_k(i,j)=fmc_gc(i,k,j) ! copy slice to 2d array
  267. enddo
  268. enddo
  269. call print_2d_stats(ibs,ibe,jbs,jbe,its-1,ite+1,jts-1,jte+1,fmc_k,'fuel_moisture: fmc_k')
  270. ! interpolate moisture contents in the class k to the fire mesh
  271. call interpolate_z2fire(id,0, & ! for debug output, <= 0 no output
  272. ids,ide,jds,jde, & ! atm grid dimensions
  273. its-1,ite+1,jts-1,jte+1, & ! memory dimensions
  274. ips,ipe,jps,jpe, &
  275. its,ite,jts,jte, &
  276. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  277. ifts, ifte, jfts, jfte, &
  278. ifts,ifte, jfts,jfte, &
  279. ir,jr, & ! atm/fire grid ratio
  280. fmc_k, & ! atm grid arrays in
  281. fmc_f) ! fire grid arrays out
  282. call print_2d_stats(ifts,ifte,jfts,jfte,ifts,ifte,jfts,jfte,fmc_f,'fuel_moisture: fmc_f')
  283. if(k .eq. kfmc_ndwi)then ! if live moisture, assimilate ndwi
  284. call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fndwi,'fuel_moisture: fndwi')
  285. write(msg,'(a,i4)')'Assimilating NDWI in fuel moisture class ',k
  286. call message(msg)
  287. endif
  288. ! add moisture contents for class k to the fuel moisture
  289. do j=jfts,jfte
  290. do i=ifts,ifte
  291. n = nfuel_cat(i,j)
  292. if(n > 0)then
  293. if(k .ne. kfmc_ndwi)then
  294. fmc_g(i,j)=fmc_g(i,j)+fmc_gw(n,k)*fmc_f(i,j) ! add to sum over classes
  295. else ! if live moisture, assimilate ndwi
  296. f1=fmc_f(i,j)
  297. w1 = fmc_gl_stdev(n)
  298. w1 = 1./(w1*w1) ! weight of forecast
  299. w2 = fmc_gl_ndwi_stdev(n)
  300. w2 = 1./(w2*w2) ! weight of update
  301. f2 = fmc_gl_ndwi_0(n) + fmc_gl_ndwi_rate(n) * fndwi(i,j) ! from regression
  302. fa = (w1*f1 + w2*f2) / (w1 + w2) ! updated value
  303. fc = fmc_gw(n,k)*fa ! times proportion of live fuel
  304. fmc_g(i,j)=fmc_g(i,j)+fc ! add to sum over classes
  305. ! write(*,*)'NDWI:',i,j,f1,f2,w1,w2,f1,fa,fmc_gw(n,k),fc,fmc_g(i,j)
  306. endif
  307. endif
  308. enddo
  309. enddo
  310. enddo
  311. call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fmc_g,'fuel_moisture: fmc_g')
  312. end subroutine fuel_moisture
  313. subroutine advance_moisture( &
  314. initialize, & ! initialize timestepping. true on the first call at time 0, then false
  315. ims,ime, jms,jme, & ! memory dimensions
  316. its,ite, jts,jte, & ! tile dimensions
  317. nfmc, & ! dimension of moisture fields
  318. moisture_dt, & ! timestep = time step time elapsed from the last call
  319. fmep_decay_tlag, & ! moisture extended model assimilated diffs. decay time lag
  320. rainc, rainnc, & ! accumulated rain
  321. t2, q2, psfc, & ! temperature (K), vapor contents (kg/kg), pressure (Pa) at the surface
  322. rain_old, & ! previous value of accumulated rain
  323. t2_old, q2_old, psfc_old, & ! previous values of the atmospheric state at surface
  324. rh_fire, & ! relative humidity at surface, for diagnostic only
  325. fmc_gc, & ! fuel moisture by class, updated
  326. fmep, & ! fuel moisture extended model parameters
  327. fmc_equi, & ! fuel moisture equilibrium by class, for diagnostics only
  328. fmc_lag & ! fuel moisture tendency by classe, for diagnostics only
  329. )
  330. implicit none
  331. !*** arguments
  332. logical, intent(in):: initialize
  333. integer, intent(in):: &
  334. ims,ime, jms,jme, & ! memory dimensions
  335. its,ite, jts,jte, & ! tile dimensions
  336. nfmc ! number of moisture fields
  337. real, intent(in):: moisture_dt, fmep_decay_tlag
  338. real, intent(in), dimension(ims:ime,jms:jme):: t2, q2, psfc, rainc, rainnc
  339. real, intent(inout), dimension(ims:ime,jms:jme):: t2_old, q2_old, psfc_old, rain_old
  340. real, intent(inout), dimension(ims:ime,nfmc,jms:jme):: fmc_gc
  341. real, intent(inout), dimension(ims:ime,2,jms:jme):: fmep
  342. real, intent(out), dimension(ims:ime,nfmc,jms:jme):: fmc_equi, fmc_lag
  343. real, intent(out), dimension(ims:ime,jms:jme)::rh_fire
  344. !*** global
  345. ! fuel properties moisture set by init_fuel_cats
  346. !*** local
  347. integer:: i,j,k
  348. real::rain_int, T, P, Q, QRS, ES, RH, tend, EMC_d, EMC_w, EMC, R, rain_diff, fmc, rlag, equi, &
  349. d, w, rhmax, rhmin, change, rainmax,rainmin, fmc_old, H, deltaS, deltaE
  350. real, parameter::tol=1e-2 ! relative change larger than that will switch to exponential ode solver
  351. character(len=256)::msg
  352. logical::bad_wrf
  353. integer::msglevel=2
  354. logical, parameter::check_rh=.false.
  355. integer::check_data=2 ! 0=nothing, 1=replace quietly, 2=warning (also printed if msglevel>2), 3=crash
  356. real::epsilon,Pws,Pw,t2_min,q2_min,psfc_min
  357. real::t2_floor=200. ! minimum allowed temperature (K)
  358. real::q2_floor=1e-8 ! miniumu allowed moisture contents (kg/kg)
  359. real::psfc_floor=1000. ! mimimum allowed surface pressiure (Pa)
  360. !*** executable
  361. ! check arguments
  362. if(msglevel>1)then
  363. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  364. write(msg,'(a,f10.2,a,i4,a,i4)')'advance_moisture dt=',moisture_dt,'s using ',moisture_classes,' classes from possible ',nfmc
  365. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  366. call message(msg,level=2)
  367. endif
  368. if(moisture_classes > nfmc .or. moisture_classes > max_moisture_classes)then
  369. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  370. write(msg,*)'advance_moisture: moisture_classes=',moisture_classes, &
  371. ' > nfmc=',nfmc,' or > max_moisture_classes=',max_moisture_classes
  372. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  373. call crash(msg)
  374. endif
  375. call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,t2,'T2')
  376. call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,q2,'Q2')
  377. call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,psfc,'PSFC')
  378. if(initialize) then
  379. call message('advance_moisture: initializing, copying surface variables to old')
  380. call copy2old
  381. else
  382. call print_3d_stats_by_slice(its,ite,1,moisture_classes,jts,jte,ims,ime,1,nfmc,jms,jme,fmc_gc,'before advance fmc_gc')
  383. endif
  384. if(check_data.ge.2 .or. msglevel.ge.2)then
  385. t2_min = huge(t2_min)
  386. q2_min = huge(q2_min)
  387. psfc_min = huge(psfc_min)
  388. do j=jts,jte
  389. do i=its,ite
  390. t2_min=min(t2(i,j),t2_min)
  391. q2_min=min(q2(i,j),q2_min)
  392. psfc_min=min(psfc(i,j),psfc_min)
  393. enddo
  394. enddo
  395. bad_wrf = ( t2_min<t2_floor .or. psfc_min<psfc_floor .or. q2_min<q2_floor)
  396. if(bad_wrf .or. msglevel.ge.2)then
  397. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  398. 91 format(a,3(2x,a,e11.3))
  399. write(msg,91)'minimal ','t2',t2_min,'q2',q2_min,'psfc',psfc_min
  400. call message(msg,level=0)
  401. write(msg,91)'floor ','t2',t2_floor,'q2',q2_floor,'psfc',psfc_floor
  402. call message(msg,level=0)
  403. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  404. endif
  405. if(bad_wrf)then
  406. if(check_data.ge.3)then
  407. call crash('advance_moisture: invalid data passed from WRF')
  408. else
  409. call message('WARNING: advance_moisture: nonphysical input values replaced by floor',level=0)
  410. endif
  411. endif
  412. endif
  413. ! one time step
  414. rhmax=-huge(rhmax)
  415. rhmin=huge(rhmin)
  416. rainmax=-huge(rainmax)
  417. rainmin= huge(rainmin)
  418. do j=jts,jte
  419. do k=1,moisture_classes
  420. do i=its,ite
  421. ! old fuel moisture contents
  422. ! compute the rain intensity from the difference of accumulated rain
  423. rain_diff = ((rainc(i,j) + rainnc(i,j)) - rain_old(i,j))
  424. if(moisture_dt > 0.)then
  425. rain_int = 3600. * rain_diff / moisture_dt
  426. else
  427. rain_int = 0.
  428. endif
  429. rainmax = max(rainmax,rain_int)
  430. rainmin = min(rainmin,rain_int)
  431. R = rain_int - rain_threshold(k)
  432. ! average the inputs for second order accuracy
  433. T = 0.5 * (t2_old(i,j) + t2(i,j))
  434. P = 0.5 * (psfc_old(i,j) + psfc(i,j))
  435. Q = 0.5 * (q2_old(i,j) + q2(i,j))
  436. ! replace nonphysical values by floor
  437. if(check_data .ge. 1)then
  438. T = max(T,t2_floor)
  439. P = max(P,psfc_floor)
  440. Q = max(Q,q2_floor)
  441. endif
  442. ! compute the relative humidity
  443. ! ES=610.78*exp(17.269*(T-273.161)/(T-35.861))
  444. ! QRS=0.622*ES/(P-0.378*ES)
  445. ! RH = Q/QRS
  446. ! function rh_from_q from Adam Kochanski following Murphy and Koop, Q.J.R. Meteorol. Soc (2005) 131 1539-1565 eq. (10)
  447. epsilon = 0.622 ! Molecular weight of water (18.02 g/mol) to molecular weight of dry air (28.97 g/mol)
  448. ! vapor pressure [Pa]
  449. Pw=q*P/(epsilon+(1-epsilon)*q);
  450. ! saturation vapor pressure [Pa]
  451. Pws= exp( 54.842763 - 6763.22/T - 4.210 * log(T) + 0.000367*T + &
  452. tanh(0.0415*(T - 218.8)) * (53.878 - 1331.22/T - 9.44523 * log(T) + 0.014025*T))
  453. !realtive humidity [1]
  454. RH = Pw/Pws
  455. rh_fire(i,j)=RH
  456. rhmax=max(RH,rhmax)
  457. rhmin=min(RH,rhmin)
  458. deltaE = fmep(i,1,j)
  459. deltaS = fmep(i,2,j)
  460. if(.not.check_rh)then
  461. RH = min(RH,1.0)
  462. else
  463. if(RH < 0.0 .or. RH > 1.0 .or. RH .ne. RH )then
  464. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  465. write(msg,'(a,2i6,5(a,f10.2))')'At i,j ',i,j,' RH=',RH, &
  466. ' from T=',T,' P=',P,' Q=',Q
  467. call message(msg)
  468. call crash('Relative humidity must be between 0 and 1, saturated water contents must be >0')
  469. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  470. endif
  471. endif
  472. !print *,'ADV_MOIST i=',i,' j=',j,' T=',T,' P=',P,' Q=',Q,' ES=',ES,' QRS=',QRS,' RH=',RH
  473. if (R > 0.) then
  474. select case(wetting_model(k))
  475. case(1) ! saturation_moisture=2.5 wetting_lag=14h saturation_rain=8 mm/h calibrated to VanWagner&Pickett 1985 per 24 hours
  476. EMC_w=saturation_moisture(k) + deltaS
  477. EMC_d=saturation_moisture(k) + deltaS
  478. rlag=rec_wetting_lag_sec(k) * (1. - exp(-R/saturation_rain(k)))
  479. end select
  480. else ! not raining
  481. select case(drying_model(k))
  482. case(1) ! Van Wagner and Pickett (1972, 1985) per Viney (1991) eq (7) (8)
  483. H = RH * 100.
  484. d=0.942*H**0.679 + 0.4994e-4*exp(0.1*H) + 0.18*(21.1+273.15-T)*(1-exp(-0.115*H)) ! equilibrium moisture for drying
  485. w=0.618*H**0.753 + 0.4540e-4*exp(0.1*H) + 0.18*(21.1+273.15-T)*(1-exp(-0.115*H)) ! equilibrium moisture for adsorbtion
  486. if(d.ne.d.or.w.ne.w)call crash('equilibrium moisture calculation failed, result is NaN')
  487. d = d*0.01
  488. w = w*0.01
  489. EMC_d = max(max(d,w)+deltaE,0.0)
  490. EMC_w = max(min(d,w)+deltaE,0.0)
  491. rlag=rec_drying_lag_sec(k)
  492. end select
  493. endif
  494. !*** MODELS THAT ARE NOT OF THE EXPONENTIAL TIME LAG KIND
  495. ! ARE RESPONSIBLE FOR THEIR OWN LOGIC, THESE MODELS
  496. ! SHOULD COMPUTE fmc_gc(i,k,j) DIRECTLY AND SET TLAG < 0
  497. !
  498. if(rlag > 0.0)then
  499. if(.not.initialize .or. fmc_gc_initialization(k).eq.0)then ! take old from before, no initialization
  500. fmc_old = fmc_gc(i,k,j)
  501. elseif(fmc_gc_initialization(k).eq.1)then ! from scalar fuelmc_g
  502. fmc_old = fuelmc_g
  503. elseif(fmc_gc_initialization(k).eq.2)then ! from computed equilibrium
  504. fmc_old=0.5*(EMC_d+EMC_w)
  505. else
  506. call crash('bad value of fmc_gc_initialization(k), must be between 0 and 2')
  507. endif
  508. equi = max(min(fmc_old, EMC_d),EMC_w) ! take lower or upper equilibrium value
  509. change = moisture_dt * rlag
  510. if(change < tol)then
  511. if(fire_print_msg.ge.3)call message('midpoint method')
  512. fmc = fmc_old + (equi - fmc_old)*change*(1.0 - 0.5*change) ! 2nd order Taylor
  513. else
  514. if(fire_print_msg.ge.3)call message('exponential method')
  515. fmc = fmc_old + (equi - fmc_old)*(1 - exp(-change))
  516. endif
  517. fmc_gc(i,k,j) = fmc
  518. ! diagnostics out
  519. fmc_equi(i,k,j)=equi
  520. fmc_lag(i,k,j)=1.0/(3600.0*rlag)
  521. ! diagnostic prints
  522. if(fire_print_msg.ge.3)then
  523. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  524. write(msg,*)'i=',i,' j=',j,'EMC_w=',EMC_w,' EMC_d=',EMC_d
  525. call message(msg)
  526. write(msg,*)'fmc_old=',fmc,' equi=',equi,' change=',change,' fmc=',fmc
  527. call message(msg)
  528. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  529. endif
  530. endif
  531. enddo
  532. enddo
  533. enddo
  534. ! assimilated differences decay
  535. do j=jts,jte
  536. do k=1,2
  537. do i=its,ite
  538. change = moisture_dt / (fmep_decay_tlag * 3600.)
  539. if(change < tol) then
  540. fmep(i,k,j) = fmep(i,k,j)*(1.0 - change * (1.0 - 0.5 * change))
  541. else
  542. fmep(i,k,j) = fmep(i,k,j)*exp(-change)
  543. endif
  544. enddo
  545. enddo
  546. enddo
  547. if(fire_print_msg.ge.2)then
  548. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  549. write(msg,2)'Rain intensity min',rainmin, ' max',rainmax,' mm/h'
  550. call message(msg)
  551. if(rainmin <0.)then
  552. call message('WARNING rain accumulation must increase')
  553. endif
  554. write(msg,2)'Relative humidity min',100*rhmin,' max',100*rhmax,'%'
  555. call message(msg)
  556. if(.not.(rhmax<=1.0 .and. rhmin>=0))then
  557. call message('WARNING Relative humidity must be between 0 and 100%')
  558. endif
  559. 2 format(2(a,f10.2),a)
  560. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  561. endif
  562. call print_3d_stats_by_slice(its,ite,1,moisture_classes,jts,jte,ims,ime,1,nfmc,jms,jme,fmc_equi,'equilibrium fmc_equi')
  563. call print_3d_stats_by_slice(its,ite,1,moisture_classes,jts,jte,ims,ime,1,nfmc,jms,jme,fmc_lag,'time lag')
  564. call print_3d_stats_by_slice(its,ite,1,moisture_classes,jts,jte,ims,ime,1,nfmc,jms,jme,fmc_gc,'after advance fmc_gc')
  565. call copy2old
  566. return
  567. contains
  568. subroutine copy2old
  569. do j=jts,jte
  570. do i=its,ite
  571. rain_old(i,j) = rainc(i,j) + rainnc(i,j)
  572. t2_old(i,j) = t2(i,j)
  573. q2_old(i,j) = q2(i,j)
  574. psfc_old(i,j) = psfc(i,j)
  575. enddo
  576. enddo
  577. end subroutine copy2old
  578. subroutine get_equi_moist
  579. end subroutine get_equi_moist
  580. end subroutine advance_moisture
  581. subroutine init_fuel_cats(init_fuel_moisture)
  582. implicit none
  583. !*** purpose: initialize fuel tables and variables by constants
  584. !*** arguments:
  585. logical, intent(in)::init_fuel_moisture
  586. logical, external:: wrf_dm_on_monitor
  587. !$ integer, external:: OMP_GET_THREAD_NUM
  588. !*** local
  589. integer:: i,j,k,ii,iounit,ierr,kk
  590. character(len=128):: msg
  591. REAL , DIMENSION( mfuelcats ) :: fwh, fz0
  592. !*** executable
  593. ! read
  594. namelist /fuel_scalars/ cmbcnst,hfgl,fuelmc_g,fuelmc_c,nfuelcats,no_fuel_cat,no_fuel_cat2,fire_wind_height,ibeh
  595. namelist /fuel_categories/ fuel_name,windrf,fgi,fueldepthm,savr, &
  596. fuelmce,fueldens,st,se,weight,fci_d,fct,ichap,fwh,fz0,ffw, &
  597. fmc_gl_ndwi_0,fmc_gl_ndwi_rate,fmc_gl_ndwi_stdev, fmc_gl_stdev, &
  598. adjr0,adjrw,adjrs,fmc_gw01,fmc_gw02,fmc_gw03,fmc_gw04,fmc_gw05
  599. namelist /moisture/ moisture_classes,drying_lag,wetting_lag,saturation_moisture,saturation_rain,rain_threshold, &
  600. drying_model,wetting_model, moisture_class_name,fmc_gc_initialization
  601. !$ if (OMP_GET_THREAD_NUM() .ne. 0)then
  602. !$ call crash('init_fuel_cats: must be called from master thread')
  603. !$ endif
  604. IF ( wrf_dm_on_monitor() ) THEN
  605. ! we are the master task
  606. ! copy in defaults
  607. fwh=fcwh
  608. fz0=fcz0
  609. ! read the file
  610. iounit=open_text_file('namelist.fire','read')
  611. read(iounit,fuel_scalars,iostat=ierr)
  612. if(ierr.ne.0)call crash('init_fuel_cats: error reading namelist fuel_scalars in file namelist.fire')
  613. read(iounit,fuel_categories,iostat=ierr)
  614. if(ierr.ne.0)call crash('init_fuel_cats: error reading namelist fuel_categories in file namelist.fire')
  615. if(init_fuel_moisture)then
  616. read(iounit,moisture,iostat=ierr)
  617. if(ierr.ne.0)call crash('init_fuel_cats: error reading namelist moisture in file namelist.fire')
  618. endif
  619. fmc_gw(1:mfuelcats,1)=fmc_gw01
  620. fmc_gw(1:mfuelcats,2)=fmc_gw02
  621. fmc_gw(1:mfuelcats,3)=fmc_gw03
  622. fmc_gw(1:mfuelcats,4)=fmc_gw04
  623. fmc_gw(1:mfuelcats,5)=fmc_gw05
  624. CLOSE(iounit)
  625. ! copy out to permanent names
  626. fcwh=fwh
  627. fcz0=fz0
  628. if (nfuelcats>mfuelcats) then
  629. write(msg,*)'nfuelcats=',nfuelcats,' too large, increase mfuelcats'
  630. call crash(msg)
  631. endif
  632. if (no_fuel_cat >= 1 .and. no_fuel_cat <= nfuelcats)then
  633. write(msg,*)'no_fuel_cat=',no_fuel_cat,' may not be between 1 and nfuelcats=',nfuelcats
  634. call crash(msg)
  635. endif
  636. if (no_fuel_cat > no_fuel_cat2)then
  637. write(msg,*)'no_fuel_cat=',no_fuel_cat,' must not be larger than no_fuel_cat2=',no_fuel_cat2
  638. call crash(msg)
  639. endif
  640. ENDIF
  641. ! broadcast fuel tables
  642. call wrf_dm_bcast_real(cmbcnst,1)
  643. call wrf_dm_bcast_real(hfgl,1)
  644. call wrf_dm_bcast_real(fuelmc_g,1)
  645. call wrf_dm_bcast_real(fuelmc_c,1)
  646. call wrf_dm_bcast_real(fire_wind_height,1)
  647. call wrf_dm_bcast_integer(nfuelcats,1)
  648. call wrf_dm_bcast_integer(no_fuel_cat,1)
  649. call wrf_dm_bcast_integer(no_fuel_cat2,1)
  650. call wrf_dm_bcast_integer(ibeh,1)
  651. call wrf_dm_bcast_real(windrf, nfuelcats)
  652. call wrf_dm_bcast_real(fgi, nfuelcats)
  653. call wrf_dm_bcast_real(fueldepthm,nfuelcats)
  654. call wrf_dm_bcast_real(savr, nfuelcats)
  655. call wrf_dm_bcast_real(fuelmce, nfuelcats)
  656. call wrf_dm_bcast_real(fueldens, nfuelcats)
  657. call wrf_dm_bcast_real(st, nfuelcats)
  658. call wrf_dm_bcast_real(se, nfuelcats)
  659. call wrf_dm_bcast_real(weight, nfuelcats)
  660. call wrf_dm_bcast_real(fci_d, nfuelcats)
  661. call wrf_dm_bcast_real(fct, nfuelcats)
  662. call wrf_dm_bcast_integer(ichap, nfuelcats)
  663. call wrf_dm_bcast_real(fcwh, nfuelcats)
  664. call wrf_dm_bcast_real(fcz0, nfuelcats)
  665. call wrf_dm_bcast_real(ffw, nfuelcats)
  666. call wrf_dm_bcast_real(adjr0, nfuelcats)
  667. call wrf_dm_bcast_real(adjrw, nfuelcats)
  668. call wrf_dm_bcast_real(adjrs, nfuelcats)
  669. call wrf_dm_bcast_real(fmc_gl_ndwi_0, nfuelcats)
  670. call wrf_dm_bcast_real(fmc_gl_ndwi_rate, nfuelcats)
  671. call wrf_dm_bcast_real(fmc_gl_ndwi_stdev,nfuelcats)
  672. call wrf_dm_bcast_real(fmc_gl_stdev, nfuelcats)
  673. ! broadcast moisture tables
  674. call wrf_dm_bcast_integer(moisture_classes,1)
  675. call wrf_dm_bcast_real(drying_lag, max_moisture_classes)
  676. call wrf_dm_bcast_real(wetting_lag, max_moisture_classes)
  677. call wrf_dm_bcast_real(saturation_moisture, max_moisture_classes)
  678. call wrf_dm_bcast_real(saturation_rain, max_moisture_classes)
  679. call wrf_dm_bcast_real(rain_threshold, max_moisture_classes)
  680. call wrf_dm_bcast_integer(drying_model, max_moisture_classes)
  681. call wrf_dm_bcast_integer(wetting_model, max_moisture_classes)
  682. call wrf_dm_bcast_integer(fmc_gc_initialization, max_moisture_classes)
  683. call wrf_dm_bcast_real(fmc_gw, mfuelcats*max_moisture_classes)
  684. ! moisture model derived scalars
  685. do i=1,moisture_classes
  686. rec_drying_lag_sec(i) = 1.0/(3600.0*drying_lag(i))
  687. rec_wetting_lag_sec(i) = 1.0/(3600.0*wetting_lag(i))
  688. enddo
  689. !-------------------------------- fuel model
  690. ! compute derived scalars
  691. fuelheat = cmbcnst * 4.30e-04 ! convert J/kg to BTU/lb
  692. ! compute derived fuel category coefficients
  693. DO i = 1,nfuelcats
  694. fci(i) = (1.+fuelmc_c)*fci_d(i)
  695. if(fct(i) .ne. 0.)then
  696. fcbr(i) = fci_d(i)/fct(i) ! to avoid division by zero
  697. else
  698. fcbr(i) = 0
  699. endif
  700. END DO
  701. ! prints
  702. call message('**********************************************************')
  703. call message('FUEL COEFFICIENTS')
  704. write(msg,8)'cmbcnst ',cmbcnst
  705. call message(msg)
  706. write(msg,8)'hfgl ',hfgl
  707. call message(msg)
  708. write(msg,8)'fuelmc_g ',fuelmc_g
  709. call message(msg)
  710. write(msg,8)'fuelmc_c ',fuelmc_c
  711. call message(msg)
  712. write(msg,8)'fuelheat ',fuelheat
  713. call message(msg)
  714. write(msg,7)'nfuelcats ',nfuelcats
  715. call message(msg)
  716. write(msg,7)'no_fuel_cat',no_fuel_cat
  717. call message(msg)
  718. write(msg,7)'no_fuel_cat2',no_fuel_cat2
  719. call message(msg)
  720. if(init_fuel_moisture)then
  721. write(msg,7)'moisture_classes',moisture_classes
  722. call message(msg)
  723. endif
  724. j=1
  725. 7 format(a,5(1x,i8,4x))
  726. 8 format(a,5(1x,g12.5e2))
  727. 9 format(a,5(1x,a))
  728. 10 format(a,i2.2,2x,5(1x,g12.5e2))
  729. do i=1,nfuelcats,j
  730. k=min(i+j-1,nfuelcats)
  731. call message(' ')
  732. write(msg,7)'CATEGORY ',(ii,ii=i,k)
  733. call message(msg)
  734. write(msg,9)'fuel name ',(trim(fuel_name(ii)),ii=i,k)
  735. call message(msg)
  736. write(msg,8)'fwh ',(fcwh(ii),ii=i,k)
  737. call message(msg)
  738. write(msg,8)'fz0 ',(fcz0(ii),ii=i,k)
  739. call message(msg)
  740. write(msg,8)'windrf ',(windrf(ii),ii=i,k)
  741. call message(msg)
  742. write(msg,8)'fgi ',(fgi(ii),ii=i,k)
  743. call message(msg)
  744. write(msg,8)'fueldepthm',(fueldepthm(ii),ii=i,k)
  745. call message(msg)
  746. write(msg,8)'savr ',(savr(ii),ii=i,k)
  747. call message(msg)
  748. write(msg,8)'fuelmce ',(fuelmce(ii),ii=i,k)
  749. call message(msg)
  750. write(msg,8)'fueldens ',(fueldens(ii),ii=i,k)
  751. call message(msg)
  752. write(msg,8)'st ',(st(ii),ii=i,k)
  753. call message(msg)
  754. write(msg,8)'se ',(se(ii),ii=i,k)
  755. call message(msg)
  756. write(msg,8)'weight ',(weight(ii),ii=i,k)
  757. call message(msg)
  758. write(msg,8)'fci_d ',(fci_d(ii),ii=i,k)
  759. call message(msg)
  760. write(msg,8)'fct ',(fct(ii),ii=i,k)
  761. call message(msg)
  762. write(msg,7)'ichap ',(ichap(ii),ii=i,k)
  763. call message(msg)
  764. write(msg,8)'fci ',(fci(ii),ii=i,k)
  765. call message(msg)
  766. write(msg,8)'fcbr ',(fcbr(ii),ii=i,k)
  767. call message(msg)
  768. write(msg,8)'ffw ',(ffw(ii),ii=i,k)
  769. call message(msg)
  770. write(msg,8)'adjr0 ',(adjr0(ii),ii=i,k)
  771. call message(msg)
  772. write(msg,8)'adjrw ',(adjrw(ii),ii=i,k)
  773. call message(msg)
  774. write(msg,8)'adjrs ',(adjrs(ii),ii=i,k)
  775. call message(msg)
  776. if(init_fuel_moisture)then
  777. do kk=1,moisture_classes
  778. write(msg,10)'fmc_gw',kk,(fmc_gw(ii,kk),ii=i,k)
  779. call message(msg)
  780. enddo
  781. endif
  782. if(kfmc_ndwi>0)then
  783. write(msg,8)'fmc_gl_stdev ',(fmc_gl_stdev(ii),ii=i,k)
  784. call message(msg)
  785. write(msg,8)'fmc_gl_ndwi_0 ',(fmc_gl_ndwi_0(ii),ii=i,k)
  786. call message(msg)
  787. write(msg,8)'fmc_gl_ndwi_rate ',(fmc_gl_ndwi_rate(ii),ii=i,k)
  788. call message(msg)
  789. write(msg,8)'fmc_gl_ndwi_stdev',(fmc_gl_ndwi_stdev(ii),ii=i,k)
  790. call message(msg)
  791. endif
  792. enddo
  793. call message(' ')
  794. call message('**********************************************************')
  795. if(init_fuel_moisture)then
  796. j=1
  797. do i=1,moisture_classes,j
  798. k=min(i+j-1,nfuelcats)
  799. call message(' ')
  800. write(msg,7)'FUEL MOISTURE CLASS',(ii,ii=i,k)
  801. call message(msg)
  802. write(msg,9)'moisture class name ',(trim(moisture_class_name(ii)),ii=i,k)
  803. call message(msg)
  804. write(msg,7)'drying_model ',(drying_model(ii),ii=i,k)
  805. call message(msg)
  806. write(msg,8)'drying_lag (h) ',(drying_lag(ii),ii=i,k)
  807. call message(msg)
  808. write(msg,7)'wetting_model ',(wetting_model(ii),ii=i,k)
  809. call message(msg)
  810. write(msg,7)'fmc_gc_initialization ',(fmc_gc_initialization(ii),ii=i,k)
  811. call message(msg)
  812. write(msg,8)'wetting_lag (h) ',(wetting_lag(ii),ii=i,k)
  813. call message(msg)
  814. write(msg,8)'saturation_moisture (1)',(saturation_moisture(ii),ii=i,k)
  815. call message(msg)
  816. write(msg,8)'saturation_rain (mm/h) ',(saturation_rain(ii),ii=i,k)
  817. call message(msg)
  818. write(msg,8)'rain_threshold (mm/h) ',(rain_threshold(ii),ii=i,k)
  819. call message(msg)
  820. enddo
  821. call message(' ')
  822. call message('**********************************************************')
  823. call message(' ')
  824. endif
  825. have_fuel_cats=.true.
  826. ! and print to file
  827. IF ( wrf_dm_on_monitor() ) THEN
  828. call write_fuels_m(61,30.,1.)
  829. ENDIF
  830. end subroutine init_fuel_cats
  831. subroutine write_fuels_m(nsteps,maxwind,maxslope)
  832. implicit none
  833. integer, intent(in):: nsteps ! number of steps for speed computation
  834. real, intent(in):: maxwind,maxslope ! computer from zero to these
  835. integer:: iounit,k,j,i,isave
  836. type(fire_params)::fp
  837. real, dimension(1:3,1:nsteps), target::vx,vy,zsf,dzdxf,dzdyf,bbb,phisc,phiwc,r_0,fgip,ischap,fmc_g,wind,nfuel_cat
  838. real, dimension(1:3,1:nsteps)::fuel_time,ros,fwh,fz0
  839. real::ros_back,ros_wind,ros_slope,propx,propy,r
  840. if(.not.have_fuel_cats)call crash('write_fuels_m: fuel categories not yet set')
  841. fp%vx=>vx
  842. fp%vy=>vy
  843. fp%dzdxf=>dzdxf
  844. fp%dzdyf=>dzdyf
  845. fp%bbb=>bbb
  846. fp%phisc=>phisc
  847. fp%phiwc=>phiwc
  848. fp%r_0=>r_0
  849. fp%fgip=>fgip
  850. fp%ischap=>ischap
  851. fp%fmc_g=>fmc_g
  852. fp%nfuel_cat=>nfuel_cat
  853. iounit = open_text_file('fuels.m','write')
  854. 10 format('fuel(',i3,').',a,'=',"'",a,"'",';% ',a)
  855. do k=1,nfuelcats
  856. write(iounit,10)k,'fuel_name',trim(fuel_name(k)),'FUEL MODEL NAME'
  857. call write_var(k,'windrf',windrf(k),'WIND REDUCTION FACTOR FROM FCWH TO MIDFLAME HEIGHT' )
  858. call write_var(k,'fwh',fcwh(k),'WIND HEIGHT TO INTERPOLATE VERTICALLY TO (M)' )
  859. call write_var(k,'fz0',fcz0(k),'ROUGHNESS LENGTH FOR VERTICAL WIND LOG INTERPOLATION (M)' )
  860. call write_var(k,'fgi',fgi(k),'INITIAL TOTAL MASS OF SURFACE FUEL (KG/M**2)' )
  861. call write_var(k,'fueldepthm',fueldepthm(k),'FUEL DEPTH (M)')
  862. call write_var(k,'savr',savr(k),'FUEL PARTICLE SURFACE-AREA-TO-VOLUME RATIO, 1/FT')
  863. call write_var(k,'fuelmce',fuelmce(k),'MOISTURE CONTENT OF EXTINCTION')
  864. call write_var(k,'fueldens',fueldens(k),'OVENDRY PARTICLE DENSITY, LB/FT^3')
  865. call write_var(k,'st',st(k),'FUEL PARTICLE TOTAL MINERAL CONTENT')
  866. call write_var(k,'se',se(k),'FUEL PARTICLE EFFECTIVE MINERAL CONTENT')
  867. call write_var(k,'weight',weight(k),'WEIGHTING PARAMETER THAT DETERMINES THE SLOPE OF THE MASS LOSS CURVE')
  868. call write_var(k,'fci_d',fci_d(k),'INITIAL DRY MASS OF CANOPY FUEL')
  869. call write_var(k,'fct',fct(k),'BURN OUT TIME FOR CANOPY FUEL, AFTER DRY (S)')
  870. call write_var(k,'ichap',float(ichap(k)),'1 if chaparral, 0 if not')
  871. call write_var(k,'fci',fci(k),'INITIAL TOTAL MASS OF CANOPY FUEL')
  872. call write_var(k,'fcbr',fcbr(k),'FUEL CANOPY BURN RATE (KG/M**2/S)')
  873. call write_var(k,'adjr0',adjr0(k),'MULTIPLICATIVE ADJUSTMENT OF BACKING SPREAD RATE')
  874. call write_var(k,'adjrw',adjrw(k),'MULTIPLICATIVE ADJUSTMENT OF WIND CONTRIBUTION TO SPREAD RATE')
  875. call write_var(k,'adjrs',adjrs(k),'MULTIPLICATIVE ADJUSTMENT OF SLOPE CONTRIBUTION TO SPREAD RATE')
  876. call write_var(k,'ffw',ffw(k),'FUEL FRACTION CONSUMED IN THE FLAMING ZONE')
  877. call write_var(k,'hfgl',hfgl,'SURFACE FIRE HEAT FLUX THRESHOLD TO IGNITE CANOPY (W/m^2)')
  878. call write_var(k,'cmbcnst',cmbcnst,'JOULES PER KG OF DRY FUEL')
  879. call write_var(k,'fuelheat',fuelheat,'FUEL PARTICLE LOW HEAT CONTENT, BTU/LB')
  880. call write_var(k,'fuelmc_g',fuelmc_g,'FUEL PARTICLE (SURFACE) MOISTURE CONTENT')
  881. call write_var(k,'fuelmc_c',fuelmc_c,'FUEL PARTICLE (CANOPY) MOISTURE CONTENT')
  882. ! set up fuel arrays
  883. !subroutine set_fire_params( &
  884. ! ifds,ifde,jfds,jfde, &
  885. ! ifms,ifme,jfms,jfme, &
  886. ! ifts,ifte,jfts,jfte, &
  887. ! fdx,fdy,nfuel_cat0, &
  888. ! nfuel_cat,fuel_time, &
  889. ! fp )
  890. nfuel_cat = k
  891. do j=1,nsteps ! set moisture - must be before set_fire_params
  892. fmc_g(1,j)=fuelmc_g
  893. fmc_g(2,j)=fuelmc_g
  894. fmc_g(3,j)=(fuelmce(k)*(j-1))/(nsteps-2)
  895. enddo
  896. isave=fire_fmc_read
  897. fire_fmc_read=0
  898. call set_fire_params( &
  899. 1,3,1,nsteps, &
  900. 1,3,1,nsteps, &
  901. 1,3,1,nsteps, &
  902. 0.,0.,k, &
  903. nfuel_cat,fuel_time, &
  904. fp )
  905. fire_fmc_read=isave
  906. ! set up windspeed slope moisture table
  907. propx=1.
  908. propy=0.
  909. do j=1,nsteps
  910. r=float(j-1)/float(nsteps-1)
  911. ! line 1 varies windspeed (in x direction), zero slope
  912. wind(1,j)=maxwind*r
  913. vx(1,j)=wind(1,j)*windrf(k)
  914. vy(1,j)=0.
  915. dzdxf(1,j)=0.
  916. dzdyf(1,j)=0.
  917. ! line 2 varies slope (in x direction), zero slope
  918. vx(2,j)=0.
  919. vy(2,j)=0.
  920. dzdxf(2,j)=maxslope*r
  921. dzdyf(2,j)=0.
  922. ! line 3 varies moisture, zero slope and wind
  923. vx(3,j)=0.
  924. vy(3,j)=0.
  925. dzdxf(3,j)=0.
  926. dzdyf(3,j)=0.
  927. enddo
  928. do j=1,nsteps
  929. do i=1,3
  930. call fire_ros(ros_back,ros_wind,ros_slope, &
  931. propx,propy,i,j,fp)
  932. ros(i,j)=ros_back+ros_wind+ros_slope
  933. enddo
  934. write(iounit,13)k,'wind',j,wind(1,j),'wind speed at 6.1m'
  935. write(iounit,13)k,'ros_wind',j,ros(1,j),'rate of spread for the wind speed at 6.1m'
  936. write(iounit,13)k,'slope',j,dzdxf(2,j),'slope'
  937. write(iounit,13)k,'ros_slope',j,ros(2,j),'rate of spread for the slope'
  938. write(iounit,13)k,'fmc_g',j,fmc_g(3,j),'fuel moisture content'
  939. write(iounit,13)k,'ros_fmc_g',j,ros(3,j),'rate of spread for the fuel moisture content'
  940. enddo
  941. enddo
  942. 13 format('fuel(',i3,').',a,'(',i3,')=',g12.5e2,';% ',a)
  943. close(iounit)
  944. ! stop
  945. contains
  946. subroutine write_var(k,name,value,descr)
  947. ! write entry for one variable
  948. integer, intent(in)::k
  949. character(len=*), intent(in)::name,descr
  950. real, intent(in)::value
  951. write(iounit,11)k,name,value
  952. write(iounit,12)k,name,descr
  953. 11 format('fuel(',i3,').',a,'=',g12.5e2, ';')
  954. 12 format('fuel(',i3,').',a,"_descr='",a,"';")
  955. end subroutine write_var
  956. end subroutine write_fuels_m
  957. !
  958. !*******************
  959. !
  960. subroutine set_fire_params( &
  961. ifds,ifde,jfds,jfde, &
  962. ifms,ifme,jfms,jfme, &
  963. ifts,ifte,jfts,jfte, &
  964. fdx,fdy,nfuel_cat0, &
  965. nfuel_cat,fuel_time, &
  966. fp )
  967. implicit none
  968. !*** purpose: Set all fire model params arrays, constant values.
  969. !*** arguments
  970. integer, intent(in)::ifds,ifde,jfds,jfde ! fire domain bounds
  971. integer, intent(in)::ifts,ifte,jfts,jfte ! fire tile bounds
  972. integer, intent(in)::ifms,ifme,jfms,jfme ! memory array bounds
  973. real, intent(in):: fdx,fdy ! fire mesh spacing
  974. integer,intent(in)::nfuel_cat0 ! default fuel category, if nfuel_cat=0
  975. real, intent(inout),dimension(ifms:ifme, jfms:jfme)::nfuel_cat ! fuel data
  976. real, intent(out), dimension(ifms:ifme, jfms:jfme)::fuel_time ! fire params arrays
  977. type(fire_params),intent(inout)::fp
  978. !*** local
  979. real:: fuelload, fueldepth, rtemp1, rtemp2, &
  980. qig, epsilon, rhob, wn, betaop, e, c, &
  981. xifr, etas, etam, a, gammax, gamma, ratio, ir, &
  982. fuelloadm,fdxinv,fdyinv,betafl, bmst
  983. integer:: i,j,k
  984. integer::nerr
  985. character(len=128)::msg
  986. !*** executable
  987. if(.not.have_fuel_cats)call crash('set_fire_params: fuel categories not yet set')
  988. call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fp%fmc_g,'set_fire_params: fmc_g')
  989. nerr=0
  990. do j=jfts,jfte
  991. do i=ifts,ifte
  992. ! fuel category
  993. k=int( nfuel_cat(i,j) )
  994. if(k.ge.no_fuel_cat.and.k.le.no_fuel_cat2)then ! no fuel
  995. fp%fgip(i,j)=0. ! no mass
  996. fp%ischap(i,j)=0.
  997. fp%phisc(i,j)=0. !
  998. fp%bbb(i,j)=1. !
  999. fuel_time(i,j)=7./0.85 ! does not matter, just what was there before
  1000. fp%phiwc(i,j)=0.
  1001. fp%r_0(i,j)=0. ! no fuel, no spread.
  1002. else
  1003. ! if(k.eq.0.and.nfuel_cat0.ge.1.and.nfuel_cat0.le.nfuelcats)then
  1004. ! ! replace k=0 by default
  1005. ! k=nfuel_cat0
  1006. ! nerr=nerr+1
  1007. ! endif
  1008. if(k.lt.1.or.k.gt.nfuelcats)then
  1009. !$OMP CRITICAL(SFIRE_PHYS_CRIT)
  1010. write(msg,'(3(a,i5))')'nfuel_cat(', i ,',',j,')=',k
  1011. !$OMP END CRITICAL(SFIRE_PHYS_CRIT)
  1012. call message(msg)
  1013. if(k.eq.0)then
  1014. call message('Possibly nfuel_cat is uninitialized on input')
  1015. endif
  1016. call crash('set_fire_params: fuel category out of bounds')
  1017. endif
  1018. fuel_time(i,j)=weight(k)/0.85 ! cell based
  1019. ! do not understand calculations of stime in binit.m4
  1020. ! set fuel time constant: weight=1000=>40% decrease over 10 min
  1021. ! fuel decreases as exp(-t/fuel_time)
  1022. ! exp(-600*0.85/1000) = approx 0.6
  1023. fp%ischap(i,j)=ichap(k)
  1024. fp%fgip(i,j)=fgi(k)
  1025. if(fire_fmc_read.eq.1)then
  1026. fp%fmc_g(i,j)=fuelmc_g
  1027. endif
  1028. ! print *,'fmc_g:',fire_fmc_read,i,j,fp%fmc_g(i,j)
  1029. ! end jm addition
  1030. !
  1031. !*** rest copied from wf2_janice/fire_startup.m4 with minimal changes
  1032. !
  1033. ! ...Settings of fire spread parameters from Rothermel follows. These
  1034. ! don't need to be recalculated later.
  1035. bmst = fp%fmc_g(i,j) / (1.+fp%fmc_g(i,j))
  1036. fuelloadm= (1.-bmst) * fgi(k) ! fuelload without moisture
  1037. fuelload = fuelloadm * (.3048)**2 * 2.205 ! to lb/ft^2
  1038. fueldepth = fueldepthm(k)/0.3048 ! to ft
  1039. betafl = fuelload/(fueldepth * fueldens(k))! packing ratio
  1040. betaop = 3.348 * savr(k)**(-0.8189) ! optimum packing ratio
  1041. qig = 250. + 1116.*fp%fmc_g(i,j) ! heat of preignition, btu/lb
  1042. epsilon = exp(-138./savr(k) ) ! effective heating number
  1043. rhob = fuelload/fueldepth ! ovendry bulk density, lb/ft^3
  1044. c = 7.47 * exp( -0.133 * savr(k)**0.55) ! const in wind coef
  1045. fp%bbb(i,j) = 0.02526 * savr(k)**0.54 ! const in wind coef
  1046. !if(fire_wind_log_interp .eq. 4 .or. fire_use_windrf .eq. 1) then
  1047. ! c = c * windrf(k)**fp%bbb(i,j) ! jm: multiply wind by reduction factor
  1048. !endif
  1049. e = 0.715 * exp( -3.59e-4 * savr(k)) ! const in wind coef
  1050. fp%phiwc(i,j) = c * (betafl/betaop)**(-e)
  1051. ! phis = 5.275 *(fp%betafl(i,j))**(-0.3) *tanphim**2 ! slope factor
  1052. fp%phisc(i,j) = 5.275 *(betafl)**(-0.3) ! const in slope coeff
  1053. rtemp2 = savr(k)**1.5
  1054. gammax = rtemp2/(495. + 0.0594*rtemp2) ! maximum rxn vel, 1/min
  1055. a = 1./(4.774 * savr(k)**0.1 - 7.27) ! coef for optimum…

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