PageRenderTime 69ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/wrfv2_fire/phys/module_fr_sfire_atm.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 2218 lines | 1267 code | 333 blank | 618 comment | 61 complexity | 01cc9230d1f3bc6663e5572fcf894d4f MD5 | raw file
Possible License(s): AGPL-1.0
  1. !WRF:MEDIATION_LAYER:FIRE_MODEL
  2. !*** Jan Mandel August 2007 - February 2010
  3. !*** email: Jan.Mandel@gmail.com
  4. ! Routines dealing with the atmosphere
  5. module module_fr_sfire_atm
  6. use module_model_constants, only: cp,xlv,g
  7. use module_fr_sfire_phys, only: fire_wind_height,have_fuel_cats,fcz0,fcwh,nfuelcats,no_fuel_cat,no_fuel_cat2,windrf
  8. use module_fr_sfire_util
  9. USE module_dm , only : wrf_dm_sum_reals
  10. use module_fr_sfire_phys, only: mfuelcats, nfuelcats ! for emissions
  11. USE module_state_description, only: num_tracer
  12. use module_fr_sfire_phys, only: fuel_name
  13. #ifdef WRF_CHEM
  14. USE module_state_description, only: num_chem
  15. USE module_configure, only: &
  16. p_co, &
  17. p_ch4, &
  18. p_h2, &
  19. p_no, &
  20. p_no2, &
  21. p_so2, &
  22. p_nh3, &
  23. p_p25, &
  24. p_p25i, &
  25. p_p25j, &
  26. p_oc1, &
  27. p_oc2, &
  28. p_bc1, &
  29. p_bc2, &
  30. p_ald, &
  31. p_csl, &
  32. p_eth, &
  33. p_hc3, &
  34. p_hc5, &
  35. p_hcho, &
  36. p_iso, &
  37. p_ket, &
  38. p_mgly, &
  39. p_ol2, &
  40. p_olt, &
  41. p_oli, &
  42. p_ora2,&
  43. p_tol, &
  44. p_xyl, &
  45. p_bigalk, &
  46. p_bigene, &
  47. p_c10h16, &
  48. p_c2h4, &
  49. p_c2h5oh, &
  50. p_c2h6, &
  51. p_c3h6, &
  52. p_c3h8, &
  53. p_ch3cooh, &
  54. p_ch3oh, &
  55. p_cres, &
  56. p_glyald, &
  57. ! p_hyac, &
  58. p_isopr, &
  59. p_macr, &
  60. p_mek, &
  61. p_mvk, &
  62. p_smoke ! tracer smoke exists only with CHEM
  63. #endif
  64. USE module_state_description, only: &
  65. p_tr17_1, &
  66. p_tr17_2, &
  67. p_tr17_3, &
  68. p_tr17_4, &
  69. p_tr17_5, &
  70. p_tr17_6, &
  71. p_tr17_7, &
  72. p_tr17_8
  73. implicit none
  74. #ifndef WRF_CHEM
  75. integer, parameter, private:: num_chem=0
  76. #endif
  77. logical, save :: have_wind_log_interpolation = .false. ! status
  78. ! emission tables
  79. REAL, dimension(mfuelcats), save:: &
  80. co=0., &
  81. ch4=0., &
  82. h2=0., &
  83. no=0., &
  84. no2=0., &
  85. so2=0., &
  86. nh3=0., &
  87. oc1=0., &
  88. oc2=0., &
  89. bc1=0., &
  90. bc2=0., &
  91. ald=0., &
  92. csl=0., &
  93. eth=0., &
  94. hc3=0., &
  95. p25=0., &
  96. p25i=0., &
  97. p25j=0., &
  98. hc5=0., &
  99. hcho=0., &
  100. iso=0., &
  101. ket=0., &
  102. mgly=0., &
  103. ol2=0., &
  104. olt=0., &
  105. oli=0., &
  106. ora2=0.,&
  107. tol=0., &
  108. xyl=0., &
  109. bigalk=0., &
  110. bigene=0., &
  111. c10h16=0., &
  112. c2h4=0., &
  113. c2h5oh=0., &
  114. c2h6=0., &
  115. c3h6=0., &
  116. c3h8=0., &
  117. ch3cooh=0., &
  118. ch3oh=0., &
  119. cres=0., &
  120. glyald=0., &
  121. ! hyac=0., &
  122. isopr=0., &
  123. macr=0., &
  124. mek=0., &
  125. mvk=0., &
  126. smoke=0., &
  127. tr17_1=0., &
  128. tr17_2=0., &
  129. tr17_3=0., &
  130. tr17_4=0., &
  131. tr17_5=0., &
  132. tr17_6=0., &
  133. tr17_7=0., &
  134. tr17_8=0.
  135. real, parameter:: & ! reciprocal molecular weights (mol/g)
  136. imw_co = 1./28.010,&
  137. imw_ch4 = 1./16.04,&
  138. imw_h2 = 1./2.016,&
  139. imw_no = 1./30.006,&
  140. imw_no2 = 1./46.006,&
  141. imw_so2 = 1./64.066,&
  142. imw_nh3 = 1./17.031
  143. real, parameter:: mw_air=28.97 ! molecular weight of air g/mol
  144. ! should be declared in the registry and stored in the state in future because of restarts
  145. real, pointer, save, dimension(:)::c_chem
  146. real, pointer, save, dimension(:)::c_fuel
  147. real, pointer, save, dimension(:)::c_tracer
  148. logical, save:: emis_read = .false.
  149. integer, save:: msglevel =1,printsums=0 ! when to print sums
  150. integer, parameter:: line=5 ! number of species, emissions, etc. per line
  151. contains
  152. ! chem arrays are chem tracer
  153. ! indices p_species are generated in inc/scalar_indices.inc and included in frame/module_configure.F
  154. subroutine read_emissions_table(chem_opt,tracer_opt)
  155. implicit none
  156. integer, intent(in)::chem_opt,tracer_opt
  157. logical, external:: wrf_dm_on_monitor
  158. external::wrf_dm_bcast_integer , wrf_dm_bcast_real
  159. integer, dimension(10)::compatible_chem_opt
  160. integer:: iounit,ierr,i
  161. character(len=128)::msg
  162. namelist/emissions/ compatible_chem_opt, printsums, &
  163. co, &
  164. ch4, &
  165. h2, &
  166. no, &
  167. no2, &
  168. so2, &
  169. nh3, &
  170. p25, &
  171. p25i, &
  172. p25j, &
  173. oc1, &
  174. oc2, &
  175. bc1, &
  176. bc2, &
  177. ald, &
  178. csl, &
  179. eth, &
  180. hc3, &
  181. hc5, &
  182. hcho, &
  183. iso, &
  184. ket, &
  185. mgly, &
  186. ol2, &
  187. olt, &
  188. oli, &
  189. ora2,&
  190. tol, &
  191. xyl, &
  192. bigalk, &
  193. bigene, &
  194. c10h16, &
  195. c2h4, &
  196. c2h5oh, &
  197. c2h6, &
  198. c3h6, &
  199. c3h8, &
  200. ch3cooh, &
  201. ch3oh, &
  202. cres, &
  203. glyald, &
  204. ! hyac, &
  205. isopr, &
  206. macr, &
  207. mek, &
  208. mvk, &
  209. smoke, &
  210. tr17_1, &
  211. tr17_2, &
  212. tr17_3, &
  213. tr17_4, &
  214. tr17_5, &
  215. tr17_6, &
  216. tr17_7, &
  217. tr17_8
  218. !$ if (OMP_GET_THREAD_NUM() .ne. 0)then
  219. !$ call crash('read_emissions_table: must be called from master thread')
  220. !$ endif
  221. IF ( wrf_dm_on_monitor() ) THEN
  222. ! we are the master task
  223. iounit=open_text_file('namelist.fire_emissions','read')
  224. compatible_chem_opt=0
  225. read(iounit,emissions,iostat=ierr)
  226. if(ierr.ne.0)call crash('read_emissions_table: error reading namelist emissions in file namelist.fire_emissions')
  227. CLOSE(iounit)
  228. write(msg,'(a,i3,a)')'reading emissions table for',nfuelcats,' fuel categories'
  229. call message(msg,level=0)
  230. if (.not.any(compatible_chem_opt.eq.chem_opt))then
  231. write(msg,'(a,i4,a)')'read_emissions_table: chem_opt=',chem_opt,' not between given compatible_chem_opt in namelist.fire_emissions'
  232. call message(msg,level=0)
  233. write(msg,'(a,10i4)')'compatible_chem_opt=', compatible_chem_opt
  234. call message(msg,level=0)
  235. call crash('chem_opt in namelist.input is not consistent with namelist.fire_emissions')
  236. endif
  237. ENDIF
  238. call wrf_dm_bcast_integer(printsums, 1)
  239. call wrf_dm_bcast_real(co, nfuelcats)
  240. call wrf_dm_bcast_real(ch4, nfuelcats)
  241. call wrf_dm_bcast_real(h2, nfuelcats)
  242. call wrf_dm_bcast_real(no, nfuelcats)
  243. call wrf_dm_bcast_real(no2, nfuelcats)
  244. call wrf_dm_bcast_real(so2, nfuelcats)
  245. call wrf_dm_bcast_real(nh3, nfuelcats)
  246. call wrf_dm_bcast_real(p25, nfuelcats)
  247. call wrf_dm_bcast_real(p25i, nfuelcats)
  248. call wrf_dm_bcast_real(p25j, nfuelcats)
  249. call wrf_dm_bcast_real(oc1, nfuelcats)
  250. call wrf_dm_bcast_real(oc2, nfuelcats)
  251. call wrf_dm_bcast_real(bc1, nfuelcats)
  252. call wrf_dm_bcast_real(bc2, nfuelcats)
  253. call wrf_dm_bcast_real(ald, nfuelcats)
  254. call wrf_dm_bcast_real(csl, nfuelcats)
  255. call wrf_dm_bcast_real(eth, nfuelcats)
  256. call wrf_dm_bcast_real(hc3, nfuelcats)
  257. call wrf_dm_bcast_real(hc5, nfuelcats)
  258. call wrf_dm_bcast_real(hcho, nfuelcats)
  259. call wrf_dm_bcast_real(iso, nfuelcats)
  260. call wrf_dm_bcast_real(ket, nfuelcats)
  261. call wrf_dm_bcast_real(mgly, nfuelcats)
  262. call wrf_dm_bcast_real(ol2, nfuelcats)
  263. call wrf_dm_bcast_real(olt, nfuelcats)
  264. call wrf_dm_bcast_real(oli, nfuelcats)
  265. call wrf_dm_bcast_real(ora2,nfuelcats)
  266. call wrf_dm_bcast_real(tol, nfuelcats)
  267. call wrf_dm_bcast_real(xyl, nfuelcats)
  268. call wrf_dm_bcast_real(bigalk, nfuelcats)
  269. call wrf_dm_bcast_real(bigene, nfuelcats)
  270. call wrf_dm_bcast_real(c10h16, nfuelcats)
  271. call wrf_dm_bcast_real(c2h4, nfuelcats)
  272. call wrf_dm_bcast_real(c2h5oh, nfuelcats)
  273. call wrf_dm_bcast_real(c2h6, nfuelcats)
  274. call wrf_dm_bcast_real(c3h6, nfuelcats)
  275. call wrf_dm_bcast_real(c3h8, nfuelcats)
  276. call wrf_dm_bcast_real(ch3cooh, nfuelcats)
  277. call wrf_dm_bcast_real(ch3oh, nfuelcats)
  278. call wrf_dm_bcast_real(cres, nfuelcats)
  279. call wrf_dm_bcast_real(glyald, nfuelcats)
  280. ! call wrf_dm_bcast_real(hyac, nfuelcats)
  281. call wrf_dm_bcast_real(isopr, nfuelcats)
  282. call wrf_dm_bcast_real(macr, nfuelcats)
  283. call wrf_dm_bcast_real(mek, nfuelcats)
  284. call wrf_dm_bcast_real(mvk, nfuelcats)
  285. call wrf_dm_bcast_real(smoke, nfuelcats)
  286. call wrf_dm_bcast_real(tr17_1, nfuelcats)
  287. call wrf_dm_bcast_real(tr17_2, nfuelcats)
  288. call wrf_dm_bcast_real(tr17_3, nfuelcats)
  289. call wrf_dm_bcast_real(tr17_4, nfuelcats)
  290. call wrf_dm_bcast_real(tr17_5, nfuelcats)
  291. call wrf_dm_bcast_real(tr17_6, nfuelcats)
  292. call wrf_dm_bcast_real(tr17_7, nfuelcats)
  293. call wrf_dm_bcast_real(tr17_8, nfuelcats)
  294. if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
  295. ! should be stored in the registry future because of restarts
  296. write(msg,'(3(a,i3,1x))')'allocating c_chem size',num_chem,'c_tracer size',num_tracer,'c_fuel size',nfuelcats
  297. call message(msg,level=2)
  298. if(num_chem>0)then
  299. allocate(c_chem(num_chem))
  300. c_chem=0. ! cumulative burnt
  301. endif
  302. if(num_tracer>0)then
  303. allocate(c_tracer(num_tracer))
  304. c_tracer=0. ! cumulative burnt
  305. endif
  306. allocate(c_fuel(nfuelcats))
  307. c_fuel=0. ! total per timestep, rate burnt, cumulative burnt
  308. write(msg,'(a,i3,a,i3)')'allocated c_chem size',size(c_chem),' c_fuel size',size(c_fuel)
  309. call message(msg,level=2)
  310. endif
  311. emis_read=.true.
  312. end subroutine read_emissions_table
  313. subroutine add_fire_emissions(chem_opt,tracer_opt,dt,dx,dy, &
  314. ifms,ifme,jfms,jfme, &
  315. ifts,ifte,jtfs,jfte, &
  316. ids,ide,kds,kde,jds,jde, &
  317. ims,ime,kms,kme,jms,jme, &
  318. its,ite,kts,kte,jts,jte, &
  319. rho,dz8w, & ! input on atmosphere mesh
  320. fgip, fuel_frac_burnt, nfuel_cat, & ! input on fire mesh
  321. chem,tracer) ! output
  322. implicit none
  323. !*** purpose
  324. ! average fire emissions from fire mesh to coarser atmosphereic mesh and add to chemistry arrays
  325. !*** arguments
  326. ! the dimensions are in cells, not nodes!
  327. ! input
  328. integer, intent(in)::chem_opt,tracer_opt
  329. real, intent(in):: dt,dx,dy ! time step & mesh spacing
  330. integer, intent(in)::its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme &! atm grid dims
  331. ,ids,ide,kds,kde,jds,jde
  332. integer, intent(in)::ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme ! fire grid dims
  333. real, intent(in)::rho(ims:ime,kms:kme,jms:jme), & ! air density kg/m^3
  334. dz8w(ims:ime,kms:kme,jms:jme) ! layer height
  335. real, intent(in), dimension(ifms:ifme,jfms:jfme):: fgip, & ! initial fuel load kg/m^2
  336. fuel_frac_burnt, & ! fuel fraction burned this step kg/kg
  337. nfuel_cat ! fuel category (Anderson= 1 to 13)
  338. ! update
  339. real, intent(inout)::chem(ims:ime,kms:kme,jms:jme,num_chem),tracer(ims:ime,kms:kme,jms:jme,num_tracer)
  340. !*** local
  341. integer:: i,i_f,j,j_f,ir,jr,isz1,isz2,jsz1,jsz2,ioff,joff,ibase,jbase,cat,k1,areaw,m,k,k_p,errors
  342. real::fuel_burnt,vol,air,conv, avgw,emis
  343. character(len=128)msg
  344. real, dimension(mfuelcats)::s_fuel,t_fuel,r_fuel ! total per timestep, rate burnt
  345. #ifdef WRF_CHEM
  346. real, dimension(num_chem) ::s_chem,t_chem,r_chem ! total per timestep, rate burnt
  347. real, dimension(num_chem) ::a_chem,g_chem ! concentration in ground level 1
  348. integer, parameter:: chem_np=46
  349. integer:: chem_pointers(chem_np)
  350. character(len=8)::chem_names(chem_np)
  351. #endif
  352. real, dimension(num_tracer) ::s_tracer,t_tracer,r_tracer ! total per timestep, rate burnt
  353. integer, parameter:: tracer_np=8
  354. integer:: tracer_pointers(tracer_np)
  355. character(len=8)::tracer_names(tracer_np)
  356. !*** executable
  357. !check mesh dimensions and domain dimensions
  358. call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
  359. call check_mesh_2dim(ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme)
  360. if(.not.emis_read)call crash('add_fire_emissions: read_emissions_table must be called first')
  361. write(msg,'(a,i3,a,i3,a,i3)')'add_fire_emissions: chem_opt=',chem_opt,' species ',num_chem,' tracers',num_tracer
  362. call message(msg)
  363. #ifdef WRF_CHEM
  364. chem_pointers= (/ &
  365. p_co, &
  366. p_ch4, &
  367. p_h2, &
  368. p_no, &
  369. p_no2, &
  370. p_so2, &
  371. p_nh3, &
  372. p_p25, &
  373. p_p25i, &
  374. p_p25j, &
  375. p_oc1, &
  376. p_oc2, &
  377. p_bc1, &
  378. p_bc2, &
  379. p_ald, &
  380. p_csl, &
  381. p_eth, &
  382. p_hc3, &
  383. p_hc5, &
  384. p_hcho, &
  385. p_iso, &
  386. p_ket, &
  387. p_mgly, &
  388. p_ol2, &
  389. p_olt, &
  390. p_oli, &
  391. p_ora2,&
  392. p_tol, &
  393. p_xyl, &
  394. p_bigalk, &
  395. p_bigene, &
  396. p_c10h16, &
  397. p_c2h4, &
  398. p_c2h5oh, &
  399. p_c2h6, &
  400. p_c3h6, &
  401. p_c3h8, &
  402. p_ch3cooh, &
  403. p_ch3oh, &
  404. p_cres, &
  405. p_glyald, &
  406. ! p_hyac, &
  407. p_isopr, &
  408. p_macr, &
  409. p_mek, &
  410. p_mvk, &
  411. p_smoke /)
  412. chem_names= (/ &
  413. 'co ', &
  414. 'ch4 ', &
  415. 'h2 ', &
  416. 'no ', &
  417. 'no2 ', &
  418. 'so2 ', &
  419. 'nh3 ', &
  420. 'p25 ', &
  421. 'p25i ', &
  422. 'p25j ', &
  423. 'oc1 ', &
  424. 'oc2 ', &
  425. 'bc1 ', &
  426. 'bc2 ', &
  427. 'ald ', &
  428. 'csl ', &
  429. 'eth ', &
  430. 'hc3 ', &
  431. 'hc5 ', &
  432. 'hcho ', &
  433. 'iso ', &
  434. 'ket ', &
  435. 'mgly ', &
  436. 'ol2 ', &
  437. 'olt ', &
  438. 'oli ', &
  439. 'ora2 ',&
  440. 'tol ', &
  441. 'xyl ', &
  442. 'bigalk ', &
  443. 'bigene ', &
  444. 'c10h16 ', &
  445. 'c2h4 ', &
  446. 'c2h5oh ', &
  447. 'c2h6 ', &
  448. 'c3h6 ', &
  449. 'c3h8 ', &
  450. 'ch3cooh ', &
  451. 'ch3oh ', &
  452. 'cres ', &
  453. 'glyald ', &
  454. ! 'hyac ', &
  455. 'isopr ', &
  456. 'macr ', &
  457. 'mek ', &
  458. 'mvk ', &
  459. 'smoke ' /)
  460. call check_pointers('chem',chem,chem_names,chem_pointers)
  461. #endif
  462. tracer_pointers= (/ &
  463. p_tr17_1, &
  464. p_tr17_2, &
  465. p_tr17_3, &
  466. p_tr17_4, &
  467. p_tr17_5, &
  468. p_tr17_6, &
  469. p_tr17_7, &
  470. p_tr17_8 /)
  471. tracer_names= (/ &
  472. 'tr17_1 ', &
  473. 'tr17_2 ', &
  474. 'tr17_3 ', &
  475. 'tr17_4 ', &
  476. 'tr17_5 ', &
  477. 'tr17_6 ', &
  478. 'tr17_7 ', &
  479. 'tr17_8 ' /)
  480. call check_pointers('tracer',tracer,tracer_names,tracer_pointers)
  481. ! compute mesh sizes
  482. isz1 = ite-its+1
  483. jsz1 = jte-jts+1
  484. isz2 = ifte-ifts+1
  485. jsz2 = jfte-jtfs+1
  486. ! check mesh sizes
  487. if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)then
  488. call message('all mesh sizes must be positive',level=0)
  489. goto 9
  490. endif
  491. ! compute mesh ratios
  492. ir=isz2/isz1
  493. jr=jsz2/jsz1
  494. if(isz2.ne.isz1*ir .or. jsz2.ne.jsz1*jr)then
  495. call message('input mesh size must be multiple of output mesh size',level=0)
  496. goto 9
  497. endif
  498. avgw = 1.0/(ir*jr) ! averaging weight = 1/number of fire cells per atm cell
  499. ! initialize emissions statistics per timestep
  500. #ifdef WRF_CHEM
  501. t_chem = 0.
  502. #endif
  503. t_fuel = 0.
  504. do i=1,num_tracer
  505. t_tracer(i)=0.
  506. enddo
  507. ! conversion fuel_burnt kg/m^2 -> chem_X 1e6*mol/mol
  508. ! emis_X(g/kg)*fuel_burnt(kg/m^2)/mw_X(g/mol) = emissions (mol/m^2)
  509. ! rho(kg/m^3)*dz8w(m))/mw_air(28.97e-3 kg/mol) = dry air in the 1st layer (mol/m^2)
  510. k1 = kts
  511. write(msg,'(a,i3)')'Fire emissions inserted into atmosphere level',k1
  512. call message(msg,level=msglevel)
  513. #ifdef WRF_CHEM
  514. if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
  515. ! sum ground concentrations and check for nans
  516. a_chem=0.0
  517. g_chem=0.0
  518. errors=0
  519. do j=jts,jte
  520. do k=1,chem_np
  521. k_p=chem_pointers(k)
  522. do i=its,ite
  523. if(chem(i,k1,j,k_p ).ne.chem(i,k1,j,k_p ))errors=errors+1
  524. a_chem(k_p)=a_chem(k_p)+chem(i,k1,j,k_p )
  525. enddo
  526. enddo
  527. enddo
  528. if(errors>0)call crash('NaN before chem update')
  529. call wrf_dm_sum_reals(a_chem,g_chem)
  530. call message('Layer1 raw sums before adding fire emissions',level=msglevel)
  531. do i=1,chem_np,line
  532. m=min(i+line-1,chem_np)
  533. write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
  534. call message(msg,level=msglevel)
  535. write(msg,81)'Layer1 beg',(g_chem(chem_pointers(j)),j=i,m)
  536. call message(msg,level=msglevel)
  537. call message(' ',level=msglevel)
  538. enddo
  539. endif
  540. #endif
  541. do j=max(jds+1,jts),min(jte,jde-1) ! safe distance from domain boundary
  542. jbase=jtfs+jr*(j-jts) ! indexing
  543. do i=max(ids+1,its),min(ite,ide-1)
  544. ibase=ifts+ir*(i-its) ! indexing
  545. !air = 1e6*mw_air/rho(i,kds,j) ! 1e6*mw_air/air density
  546. !vol = avgw/dz8w(i,kds,j) ! averaging volume factor / 1st layer depth
  547. do joff=0,jr-1
  548. j_f=joff+jbase
  549. do ioff=0,ir-1
  550. i_f=ioff+ibase
  551. !*** fire cell (i_f,j_f) contributes to atmosphere cell (i,j) at ground level
  552. fuel_burnt = fgip(i_f,j_f) * fuel_frac_burnt(i_f,j_f) ! kg/m^2
  553. cat = nfuel_cat(i_f, j_f) ! usually 1 to 13
  554. if(cat.lt.no_fuel_cat)t_fuel(cat)=t_fuel(cat) + fuel_burnt
  555. !*** chem compounds emissions given in g/kg
  556. ! fuel_burnt kg/m^2 * table g/kg -> ppmv = 1e6*mol/mol in 1st layer
  557. !AK rho is in kg/m3 so the conversion factor must be scaled by a 1000 to match
  558. !emissions in grams
  559. ! conv = avgw*1e6*mw_air/(rho(i,k1,j)*dz8w(i,k1,j))
  560. conv = avgw*1e3*mw_air/(rho(i,k1,j)*dz8w(i,k1,j))
  561. #ifdef WRF_CHEM
  562. emis=co (cat)*fuel_burnt ! emission from fire cell in g/m^2
  563. t_chem(p_co) = t_chem(p_co) + emis ! add to total
  564. ! if(isnan(chem(i,k1,j,p_co )))call crash('NaN before')
  565. chem(i,k1,j,p_co )=chem(i,k1,j,p_co ) + emis*conv*imw_co ! add to chem
  566. ! if(isnan(chem(i,k1,j,p_co )))call crash('NaN after')
  567. emis=ch4 (cat)*fuel_burnt ! emission from fire cell in g/m^2
  568. t_chem(p_ch4) = t_chem(p_ch4) + emis ! add to total
  569. chem(i,k1,j,p_ch4 )=chem(i,k1,j,p_ch4 ) + emis*conv*imw_ch4 ! add to chem
  570. emis=h2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
  571. t_chem(p_h2) = t_chem(p_h2) + emis ! add to total
  572. chem(i,k1,j,p_h2 )=chem(i,k1,j,p_h2 ) + emis*conv*imw_h2 ! add to chem
  573. emis=no (cat)*fuel_burnt ! emission from fire cell in g/m^2
  574. t_chem(p_no) = t_chem(p_no) + emis ! add to total
  575. chem(i,k1,j,p_no )=chem(i,k1,j,p_no ) + emis*conv*imw_no ! add to chem
  576. emis=no2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
  577. t_chem(p_no2) = t_chem(p_no2) + emis ! add to total
  578. chem(i,k1,j,p_no2 )=chem(i,k1,j,p_no2 ) + emis*conv*imw_no2 ! add to chem
  579. emis=so2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
  580. t_chem(p_so2) = t_chem(p_so2) + emis ! ads to total
  581. chem(i,k1,j,p_so2 )=chem(i,k1,j,p_so2 ) + emis*conv*imw_so2 ! add to chem
  582. emis=nh3 (cat)*fuel_burnt ! emission from fire cell in g/m^2
  583. t_chem(p_nh3) = t_chem(p_nh3) + emis ! add to total
  584. chem(i,k1,j,p_nh3 )=chem(i,k1,j,p_nh3 ) + emis*conv*imw_nh3 ! add to chem
  585. !*** other emissions already given in mol/kg
  586. ! fuel_burnt kg/m^2 * table mol/kg -> ppmv = 1e6*mol/mol in 1st layer dry air in 1st layer
  587. ! same conversion factor but we will not divide by the molecular weight of the compound
  588. ! conv = avgw*1e6*mw_air/(rho(i,kds,j)*dz8w(i,kds,j))
  589. emis=ald (cat)*fuel_burnt ! emission from fire cell
  590. t_chem(p_ald) = t_chem(p_ald) + emis ! add to total
  591. chem(i,k1,j,p_ald )=chem(i,k1,j,p_ald )+emis*conv
  592. emis=csl (cat)*fuel_burnt ! emission from fire cell
  593. t_chem(p_csl) = t_chem(p_csl) + emis ! add to total
  594. chem(i,k1,j,p_csl )=chem(i,k1,j,p_csl )+emis*conv
  595. emis=eth (cat)*fuel_burnt ! emission from fire cell
  596. t_chem(p_eth) = t_chem(p_eth) + emis ! add to total
  597. chem(i,k1,j,p_eth )=chem(i,k1,j,p_eth )+emis*conv
  598. emis=hc3 (cat)*fuel_burnt ! emission from fire cell
  599. t_chem(p_hc3) = t_chem(p_hc3) + emis ! add to total
  600. chem(i,k1,j,p_hc3 )=chem(i,k1,j,p_hc3 )+emis*conv
  601. emis=hc5 (cat)*fuel_burnt ! emission from fire cell
  602. t_chem(p_hc5) = t_chem(p_hc5) + emis ! add to total
  603. chem(i,k1,j,p_hc5 )=chem(i,k1,j,p_hc5 )+emis*conv
  604. emis=hcho (cat)*fuel_burnt ! emission from fire cell
  605. t_chem(p_hcho) = t_chem(p_hcho) + emis ! add to total
  606. chem(i,k1,j,p_hcho)=chem(i,k1,j,p_hcho)+emis*conv
  607. emis=iso (cat)*fuel_burnt ! emission from fire cell
  608. t_chem(p_iso) = t_chem(p_iso) + emis ! add to total
  609. chem(i,k1,j,p_iso )=chem(i,k1,j,p_iso )+emis*conv
  610. emis=ket (cat)*fuel_burnt ! emission from fire cell
  611. t_chem(p_ket) = t_chem(p_ket) + emis ! add to total
  612. chem(i,k1,j,p_ket )=chem(i,k1,j,p_ket )+emis*conv
  613. emis=mgly (cat)*fuel_burnt ! emission from fire cell
  614. t_chem(p_mgly) = t_chem(p_mgly) + emis ! add to total
  615. chem(i,k1,j,p_mgly)=chem(i,k1,j,p_mgly)+emis*conv
  616. emis=ol2 (cat)*fuel_burnt ! emission from fire cell
  617. t_chem(p_ol2) = t_chem(p_ol2) + emis ! add to total
  618. chem(i,k1,j,p_ol2 )=chem(i,k1,j,p_ol2 )+emis*conv
  619. emis=olt (cat)*fuel_burnt ! emission from fire cell
  620. t_chem(p_olt) = t_chem(p_olt) + emis ! add to total
  621. chem(i,k1,j,p_olt )=chem(i,k1,j,p_olt )+emis*conv
  622. emis=oli (cat)*fuel_burnt ! emission from fire cell
  623. t_chem(p_oli) = t_chem(p_oli) + emis ! add to total
  624. chem(i,k1,j,p_oli )=chem(i,k1,j,p_oli )+emis*conv
  625. emis=ora2 (cat)*fuel_burnt ! emission from fire cell
  626. t_chem(p_ora2) = t_chem(p_ora2) + emis ! add to total
  627. chem(i,k1,j,p_ora2)=chem(i,k1,j,p_ora2)+emis*conv
  628. emis=tol (cat)*fuel_burnt ! emission from fire cell
  629. t_chem(p_tol) = t_chem(p_tol) + emis ! add to total
  630. chem(i,k1,j,p_tol )=chem(i,k1,j,p_tol )+emis*conv
  631. emis=xyl (cat)*fuel_burnt ! emission from fire cell
  632. t_chem(p_xyl) = t_chem(p_xyl) + emis ! add to total
  633. chem(i,k1,j,p_xyl )=chem(i,k1,j,p_xyl )+emis*conv
  634. emis=bigalk (cat)*fuel_burnt ! emission from fire cell
  635. t_chem(p_bigalk) = t_chem(p_bigalk) + emis ! add to total
  636. chem(i,k1,j,p_bigalk )=chem(i,k1,j,p_bigalk )+emis*conv
  637. emis=bigene (cat)*fuel_burnt ! emission from fire cell
  638. t_chem(p_bigene) = t_chem(p_bigene) + emis ! add to total
  639. chem(i,k1,j,p_bigene )=chem(i,k1,j,p_bigene )+emis*conv
  640. emis=c10h16 (cat)*fuel_burnt ! emission from fire cell
  641. t_chem(p_c10h16) = t_chem(p_c10h16) + emis ! add to total
  642. chem(i,k1,j,p_c10h16 )=chem(i,k1,j,p_c10h16 )+emis*conv
  643. emis=c2h4 (cat)*fuel_burnt ! emission from fire cell
  644. t_chem(p_c2h4) = t_chem(p_c2h4) + emis ! add to total
  645. chem(i,k1,j,p_c2h4 )=chem(i,k1,j,p_c2h4 )+emis*conv
  646. emis=c2h5oh (cat)*fuel_burnt ! emission from fire cell
  647. t_chem(p_c2h5oh) = t_chem(p_c2h5oh) + emis ! add to total
  648. chem(i,k1,j,p_c2h5oh )=chem(i,k1,j,p_c2h5oh )+emis*conv
  649. emis=c2h6 (cat)*fuel_burnt ! emission from fire cell
  650. t_chem(p_c2h6) = t_chem(p_c2h6) + emis ! add to total
  651. chem(i,k1,j,p_c2h6 )=chem(i,k1,j,p_c2h6 )+emis*conv
  652. emis=c3h6 (cat)*fuel_burnt ! emission from fire cell
  653. t_chem(p_c3h6) = t_chem(p_c3h6) + emis ! add to total
  654. chem(i,k1,j,p_c3h6 )=chem(i,k1,j,p_c3h6 )+emis*conv
  655. emis=c3h8 (cat)*fuel_burnt ! emission from fire cell
  656. t_chem(p_c3h8) = t_chem(p_c3h8) + emis ! add to total
  657. chem(i,k1,j,p_c3h8 )=chem(i,k1,j,p_c3h8 )+emis*conv
  658. emis=ch3cooh (cat)*fuel_burnt ! emission from fire cell
  659. t_chem(p_ch3cooh) = t_chem(p_ch3cooh) + emis ! add to total
  660. chem(i,k1,j,p_ch3cooh )=chem(i,k1,j,p_ch3cooh )+emis*conv
  661. emis=ch3oh (cat)*fuel_burnt ! emission from fire cell
  662. t_chem(p_ch3oh) = t_chem(p_ch3oh) + emis ! add to total
  663. chem(i,k1,j,p_ch3oh )=chem(i,k1,j,p_ch3oh )+emis*conv
  664. emis=cres (cat)*fuel_burnt ! emission from fire cell
  665. t_chem(p_cres) = t_chem(p_cres) + emis ! add to total
  666. chem(i,k1,j,p_cres )=chem(i,k1,j,p_cres )+emis*conv
  667. emis=glyald (cat)*fuel_burnt ! emission from fire cell
  668. t_chem(p_glyald) = t_chem(p_glyald) + emis ! add to total
  669. chem(i,k1,j,p_glyald )=chem(i,k1,j,p_glyald )+emis*conv
  670. emis=isopr (cat)*fuel_burnt ! emission from fire cell
  671. t_chem(p_isopr) = t_chem(p_isopr) + emis ! add to total
  672. chem(i,k1,j,p_isopr )=chem(i,k1,j,p_isopr )+emis*conv
  673. emis=macr (cat)*fuel_burnt ! emission from fire cell
  674. t_chem(p_macr) = t_chem(p_macr) + emis ! add to total
  675. chem(i,k1,j,p_macr )=chem(i,k1,j,p_macr )+emis*conv
  676. emis=mek (cat)*fuel_burnt ! emission from fire cell
  677. t_chem(p_mek) = t_chem(p_mek) + emis ! add to total
  678. chem(i,k1,j,p_mek )=chem(i,k1,j,p_mek )+emis*conv
  679. emis=mvk (cat)*fuel_burnt ! emission from fire cell
  680. t_chem(p_mvk) = t_chem(p_mvk) + emis ! add to total
  681. chem(i,k1,j,p_mvk )=chem(i,k1,j,p_mvk )+emis*conv
  682. ! aerosols
  683. ! fuel_burnt kg/m^2 * table g/kg -> ug/kg dry air in 1st layer
  684. ! see also chem/emissions_driver.F line 515
  685. conv = avgw*1e6/(rho(i,k1,j)*dz8w(i,k1,j))
  686. emis=p25 (cat)*fuel_burnt ! emission from fire cell
  687. t_chem(p_p25) = t_chem(p_p25) + emis ! add to total
  688. chem(i,k1,j,p_p25 )=chem(i,k1,j,p_p25 )+emis*conv
  689. emis=p25i (cat)*fuel_burnt ! emission from fire cell
  690. t_chem(p_p25i) = t_chem(p_p25i) + emis ! add to total
  691. chem(i,k1,j,p_p25i )=chem(i,k1,j,p_p25i )+emis*conv
  692. emis=p25j (cat)*fuel_burnt ! emission from fire cell
  693. t_chem(p_p25j) = t_chem(p_p25j) + emis ! add to total
  694. chem(i,k1,j,p_p25j )=chem(i,k1,j,p_p25j )+emis*conv
  695. emis=oc1 (cat)*fuel_burnt ! emission from fire cell
  696. t_chem(p_oc1 ) = t_chem(p_oc1 ) + emis ! add to total
  697. chem(i,k1,j,p_oc1 )=chem(i,k1,j,p_oc1 )+emis*conv
  698. emis=oc2 (cat)*fuel_burnt ! emission from fire cell
  699. t_chem(p_oc2 ) = t_chem(p_oc2 ) + emis ! add to total
  700. chem(i,k1,j,p_oc2 )=chem(i,k1,j,p_oc2 )+emis*conv
  701. emis=bc1 (cat)*fuel_burnt ! emission from fire cell
  702. t_chem(p_bc1 ) = t_chem(p_bc1 ) + emis ! add to total
  703. chem(i,k1,j,p_bc1 )=chem(i,k1,j,p_bc1 )+emis*conv
  704. emis=bc2 (cat)*fuel_burnt ! emission from fire cell
  705. t_chem(p_bc2 ) = t_chem(p_bc2 ) + emis ! add to total
  706. chem(i,k1,j,p_bc2 )=chem(i,k1,j,p_bc2 )+emis*conv
  707. #endif
  708. if (num_tracer >0)then
  709. ! treat tracers exactly the same as aerosols, emissions g/kg fuel burned, tracer concentration ug/kg dry air
  710. conv = avgw*1e6/(rho(i,k1,j)*dz8w(i,k1,j))
  711. emis=tr17_1 (cat)*fuel_burnt ! emission from fire cell
  712. t_tracer(p_tr17_1) = t_tracer(p_tr17_1) + emis ! add to total
  713. tracer(i,k1,j,p_tr17_1 )=tracer(i,k1,j,p_tr17_1 )+emis*conv
  714. emis=tr17_2 (cat)*fuel_burnt ! emission from fire cell
  715. t_tracer(p_tr17_2) = t_tracer(p_tr17_2) + emis ! add to total
  716. tracer(i,k1,j,p_tr17_2 )=tracer(i,k1,j,p_tr17_2 )+emis*conv
  717. emis=tr17_3 (cat)*fuel_burnt ! emission from fire cell
  718. t_tracer(p_tr17_3) = t_tracer(p_tr17_3) + emis ! add to total
  719. tracer(i,k1,j,p_tr17_3 )=tracer(i,k1,j,p_tr17_3 )+emis*conv
  720. emis=tr17_4 (cat)*fuel_burnt ! emission from fire cell
  721. t_tracer(p_tr17_4) = t_tracer(p_tr17_4) + emis ! add to total
  722. tracer(i,k1,j,p_tr17_4 )=tracer(i,k1,j,p_tr17_4 )+emis*conv
  723. emis=tr17_5 (cat)*fuel_burnt ! emission from fire cell
  724. t_tracer(p_tr17_5) = t_tracer(p_tr17_5) + emis ! add to total
  725. tracer(i,k1,j,p_tr17_5 )=tracer(i,k1,j,p_tr17_5 )+emis*conv
  726. emis=tr17_6 (cat)*fuel_burnt ! emission from fire cell
  727. t_tracer(p_tr17_6) = t_tracer(p_tr17_6) + emis ! add to total
  728. tracer(i,k1,j,p_tr17_6 )=tracer(i,k1,j,p_tr17_6 )+emis*conv
  729. emis=tr17_7 (cat)*fuel_burnt ! emission from fire cell
  730. t_tracer(p_tr17_7) = t_tracer(p_tr17_7) + emis ! add to total
  731. tracer(i,k1,j,p_tr17_7 )=tracer(i,k1,j,p_tr17_7 )+emis*conv
  732. emis=tr17_8 (cat)*fuel_burnt ! emission from fire cell
  733. t_tracer(p_tr17_8) = t_tracer(p_tr17_8) + emis ! add to total
  734. tracer(i,k1,j,p_tr17_8 )=tracer(i,k1,j,p_tr17_8 )+emis*conv
  735. endif
  736. enddo
  737. enddo
  738. enddo
  739. enddo
  740. #ifdef WRF_CHEM
  741. if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
  742. ! sum ground concentrations and check for nans
  743. a_chem=0.0
  744. g_chem=0.0
  745. errors=0
  746. do j=jts,jte
  747. do k=1,chem_np
  748. k_p=chem_pointers(k)
  749. do i=its,ite
  750. if(chem(i,k1,j,k_p ).ne.chem(i,k1,j,k_p ))errors=errors+1
  751. a_chem(k_p)=a_chem(k_p)+chem(i,k1,j,k_p )
  752. enddo
  753. enddo
  754. enddo
  755. if(errors>0)call crash('NaN after chem update')
  756. call wrf_dm_sum_reals(a_chem,g_chem)
  757. call message('Layer1 raw sums after adding fire emissions',level=msglevel)
  758. do i=1,chem_np,line
  759. m=min(i+line-1,chem_np)
  760. write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
  761. call message(msg,level=msglevel)
  762. write(msg,81)'Layer1 end',(g_chem(chem_pointers(j)),j=i,m)
  763. call message(msg,level=msglevel)
  764. call message(' ',level=msglevel)
  765. enddo
  766. endif
  767. #endif
  768. if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
  769. ! sum over processes and add to cumulative sums
  770. ! fuel burned
  771. call wrf_dm_sum_reals(t_fuel,s_fuel)
  772. ! scale
  773. s_fuel = s_fuel*dx*dy
  774. ! get rates
  775. r_fuel = s_fuel/dt
  776. ! add to cumulative totals
  777. if(size(c_fuel).ne.nfuelcats)call crash('add_fire_emissions: bad size c_fuel')
  778. c_fuel = c_fuel + s_fuel
  779. #ifdef WRF_CHEM
  780. call wrf_dm_sum_reals(a_chem,g_chem)
  781. ! chem
  782. call wrf_dm_sum_reals(t_chem,s_chem)
  783. s_chem = s_chem*dx*dy
  784. r_chem = s_chem/dt
  785. if(size(c_chem).ne.num_chem)call crash('add_fire_emissions: bad size c_chem')
  786. c_chem = c_chem + s_chem
  787. call message('Total emissions in g or mol per the table',level=msglevel)
  788. do i=1,chem_np,line
  789. m=min(i+line-1,chem_np)
  790. write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
  791. call message(msg,level=msglevel)
  792. write(msg,81)'Cumulative',(c_chem(chem_pointers(j)),j=i,m)
  793. call message(msg,level=msglevel)
  794. write(msg,81)'Rate per s',(r_chem(chem_pointers(j)),j=i,m)
  795. call message(msg,level=msglevel)
  796. call message(' ',level=msglevel)
  797. enddo
  798. #endif
  799. if(num_tracer >0)then
  800. ! tracer
  801. call wrf_dm_sum_reals(t_tracer,s_tracer)
  802. s_tracer = s_tracer*dx*dy
  803. r_tracer = s_tracer/dt
  804. if(size(c_tracer).ne.num_tracer)call crash('add_fire_emissions: bad size c_tracer')
  805. c_tracer = c_tracer + s_tracer
  806. call message('Total emissions in g',level=msglevel)
  807. do i=1,tracer_np,line
  808. m=min(i+line-1,tracer_np)
  809. write(msg,80)'Emissions ',(trim(tracer_names(j)),j=i,m)
  810. call message(msg,level=msglevel)
  811. write(msg,81)'Cumulative',(c_tracer(tracer_pointers(j)),j=i,m)
  812. call message(msg,level=msglevel)
  813. write(msg,81)'Rate per s',(r_tracer(tracer_pointers(j)),j=i,m)
  814. call message(msg,level=msglevel)
  815. call message(' ',level=msglevel)
  816. enddo
  817. endif
  818. do cat=1,nfuelcats
  819. if(c_fuel(cat) > 0.)then
  820. write(msg,83)fuel_name(cat),' burned',c_fuel(cat),'kg, rate',r_fuel(cat),' kg/s'
  821. call message(msg,level=msglevel)
  822. endif
  823. enddo
  824. write(msg,83)'Total fuel',' burned',sum(c_fuel),'kg, rate',sum(r_fuel),' kg/s'
  825. call message(msg,level=msglevel)
  826. endif
  827. 80 format(a,8a11)
  828. 81 format(a,8e11.3)
  829. 83 format(a30,a,g14.4,a,g14.4,a,a)
  830. return
  831. 9 continue
  832. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  833. write(msg,91)ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme
  834. call message(msg,level=0)
  835. write(msg,91)its,ite,jts,jte,ims,ime,jms,jme
  836. call message(msg,level=0)
  837. write(msg,92)'input mesh size:',isz2,jsz2
  838. call message(msg,level=0)
  839. 91 format('dimensions: ',8i8)
  840. write(msg,92)'output mesh size:',isz1,jsz1
  841. call message(msg,level=0)
  842. 92 format(a,2i8)
  843. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  844. call crash('add_fire_emissions: bad mesh sizes')
  845. end subroutine add_fire_emissions
  846. !
  847. !***
  848. !
  849. subroutine check_pointers(array_name,array,pointer_names,pointers)
  850. implicit none
  851. !*** arguments
  852. character(len=*)::array_name
  853. real, dimension(:,:,:,:)::array
  854. character(len=*), dimension(:)::pointer_names
  855. integer, dimension(:)::pointers
  856. !*** local
  857. integer::np,i,m,j
  858. character(len=256)::msg
  859. !** executable
  860. np=ubound(pointers,1)
  861. 993 format(3a,4(1x,i3,':',i3))
  862. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  863. write(msg,993)'array ',array_name,' has dimensions ',&
  864. lbound(array,1),ubound(array,1), &
  865. lbound(array,2),ubound(array,2), &
  866. lbound(array,3),ubound(array,3), &
  867. lbound(array,4),ubound(array,4)
  868. call message(msg)
  869. do i=1,np,line
  870. m=min(i+line-1,np)
  871. write(msg,'(a,8(1x,a8))')'Species',(trim(pointer_names(j)),j=i,m)
  872. call message(msg,level=msglevel)
  873. write(msg,'(a,8i9)') 'Pointer',(pointers(j),j=i,m)
  874. call message(msg,level=msglevel)
  875. call message(' ')
  876. enddo
  877. if(maxval(pointers) > ubound(array,4) .or. minval(pointers) < lbound(array,4))then
  878. write(msg,'(3a)')'add_fire_emissions: a ',array_name,' pointer is out of bounds'
  879. call crash(msg)
  880. endif
  881. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  882. end subroutine check_pointers
  883. !
  884. !***
  885. !
  886. SUBROUTINE fire_tendency( &
  887. ids,ide, kds,kde, jds,jde, & ! dimensions
  888. ims,ime, kms,kme, jms,jme, &
  889. its,ite, kts,kte, jts,jte, &
  890. grnhfx,grnqfx,canhfx,canqfx, & ! heat fluxes summed up to atm grid
  891. alfg,alfc,z1can, & ! coeffients, properties, geometry
  892. zs,z_at_w,dz8w,mu,rho, &
  893. rthfrten,rqvfrten) ! theta and Qv tendencies
  894. ! This routine is atmospheric physics
  895. ! it does NOT go into module_fr_sfire_phys because it is not fire physics
  896. ! taken from the code by Ned Patton, only order of arguments change to the convention here
  897. ! --- this routine takes fire generated heat and moisture fluxes and
  898. ! calculates their influence on the theta and water vapor
  899. ! --- note that these tendencies are valid at the Arakawa-A location
  900. IMPLICIT NONE
  901. ! --- incoming variables
  902. INTEGER , INTENT(in) :: ids,ide, kds,kde, jds,jde, &
  903. ims,ime, kms,kme, jms,jme, &
  904. its,ite, kts,kte, jts,jte
  905. REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: grnhfx,grnqfx ! W/m^2
  906. REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: canhfx,canqfx ! W/m^2
  907. REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: zs ! topography (m abv sealvl)
  908. REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: mu ! dry air mass (Pa)
  909. REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: z_at_w ! m abv sealvl
  910. REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: dz8w ! dz across w-lvl
  911. REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: rho ! density
  912. REAL, INTENT(in) :: alfg ! extinction depth ground fire heat (m)
  913. REAL, INTENT(in) :: alfc ! extinction depth crown fire heat (m)
  914. REAL, INTENT(in) :: z1can ! height of crown fire heat release (m)
  915. ! --- outgoing variables
  916. REAL, INTENT(out), DIMENSION( ims:ime,kms:kme,jms:jme ) :: &
  917. rthfrten, & ! theta tendency from fire (in mass units)
  918. rqvfrten ! Qv tendency from fire (in mass units)
  919. ! --- local variables
  920. INTEGER :: i,j,k
  921. INTEGER :: i_st,i_en, j_st,j_en, k_st,k_en
  922. REAL :: cp_i
  923. REAL :: rho_i
  924. REAL :: xlv_i
  925. REAL :: z_w
  926. REAL :: fact_g, fact_c
  927. REAL :: alfg_i, alfc_i
  928. REAL, DIMENSION( its:ite,kts:kte,jts:jte ) :: hfx,qfx
  929. !! character(len=128)::msg
  930. do j=jts,jte
  931. do k=kts,min(kte+1,kde)
  932. do i=its,ite
  933. rthfrten(i,k,j)=0.
  934. rqvfrten(i,k,j)=0.
  935. enddo
  936. enddo
  937. enddo
  938. ! --- set some local constants
  939. cp_i = 1./cp ! inverse of specific heat
  940. xlv_i = 1./xlv ! inverse of latent heat
  941. alfg_i = 1./alfg
  942. alfc_i = 1./alfc
  943. !!write(msg,'(8e11.3)')cp,cp_i,xlv,xlv_i,alfg,alfc,z1can
  944. !!call message(msg)
  945. call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,grnhfx,'fire_tendency:grnhfx')
  946. call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,grnqfx,'fire_tendency:grnqfx')
  947. ! --- set loop indicies : note that
  948. i_st = MAX(its,ids+1)
  949. i_en = MIN(ite,ide-1)
  950. k_st = kts
  951. k_en = MIN(kte,kde-1)
  952. j_st = MAX(jts,jds+1)
  953. j_en = MIN(jte,jde-1)
  954. ! --- distribute fluxes
  955. DO j = j_st,j_en
  956. DO k = k_st,k_en
  957. DO i = i_st,i_en
  958. ! --- set z (in meters above ground)
  959. z_w = z_at_w(i,k,j) - zs(i,j) ! should be zero when k=k_st
  960. ! --- heat flux
  961. fact_g = cp_i * EXP( - alfg_i * z_w )
  962. IF ( z_w < z1can ) THEN
  963. fact_c = cp_i
  964. ELSE
  965. fact_c = cp_i * EXP( - alfc_i * (z_w - z1can) )
  966. END IF
  967. hfx(i,k,j) = fact_g * grnhfx(i,j) + fact_c * canhfx(i,j)
  968. !! write(msg,2)i,k,j,z_w,grnhfx(i,j),hfx(i,k,j)
  969. !!2 format('hfx:',3i4,6e11.3)
  970. !! call message(msg)
  971. ! --- vapor flux
  972. fact_g = xlv_i * EXP( - alfg_i * z_w )
  973. IF (z_w < z1can) THEN
  974. fact_c = xlv_i
  975. ELSE
  976. fact_c = xlv_i * EXP( - alfc_i * (z_w - z1can) )
  977. END IF
  978. qfx(i,k,j) = fact_g * grnqfx(i,j) + fact_c * canqfx(i,j)
  979. !! if(hfx(i,k,j).ne.0. .or. qfx(i,k,j) .ne. 0.)then
  980. !! write(msg,1)i,k,j,hfx(i,k,j),qfx(i,k,j)
  981. !!1 format('tend:',3i6,2e11.3)
  982. !! call message(msg)
  983. ! endif
  984. END DO
  985. END DO
  986. END DO
  987. ! --- add flux divergence to tendencies
  988. !
  989. ! multiply by dry air mass (mu) to eliminate the need to
  990. ! call sr. calculate_phy_tend (in dyn_em/module_em.F)
  991. ! print *,'fire_tendency:',i_st,i_en,j_st,j_en
  992. DO j = j_st,j_en
  993. DO k = k_st,k_en-1
  994. DO i = i_st,i_en
  995. rho_i = 1./rho(i,k,j)
  996. rthfrten(i,k,j) = - mu(i,j) * rho_i * (hfx(i,k+1,j)-hfx(i,k,j)) / dz8w(i,k,j)
  997. rqvfrten(i,k,j) = - mu(i,j) * rho_i * (qfx(i,k+1,j)-qfx(i,k,j)) / dz8w(i,k,j)
  998. ! print *,i,j,k,rthfrten(i,k,j)
  999. END DO
  1000. END DO
  1001. END DO
  1002. call print_3d_stats(its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme,rthfrten,'fire_tendency:rthfrten')
  1003. call print_3d_stats(its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme,rqvfrten,'fire_tendency:rqvfrten')
  1004. RETURN
  1005. END SUBROUTINE fire_tendency
  1006. !
  1007. !***
  1008. !
  1009. subroutine interpolate_atm2fire(id, & ! for debug output, <= 0 no output
  1010. ids,ide, kds,kde, jds,jde, & ! atm grid dimensions
  1011. ims,ime, kms,kme, jms,jme, &
  1012. ips,ipe,jps,jpe, &
  1013. its,ite,jts,jte, &
  1014. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  1015. ifms, ifme, jfms, jfme, &
  1016. ifps, ifpe, jfps, jfpe, & ! fire patch bounds
  1017. ifts,ifte,jfts,jfte, &
  1018. ir,jr, & ! atm/fire grid ratio
  1019. u_frame, v_frame, & ! velocity frame correction
  1020. u,v, & ! atm grid arrays in
  1021. ph,phb, &
  1022. z0,zs, &
  1023. uah,vah, &
  1024. uf,vf) ! fire grid arrays out
  1025. implicit none
  1026. ! Jan Mandel, October 2010
  1027. !*** purpose: interpolate winds and height
  1028. !*** arguments
  1029. integer, intent(in)::id
  1030. integer, intent(in):: &
  1031. ids,ide, kds,kde, jds,jde, & ! atm domain bounds
  1032. ims,ime, kms,kme, jms,jme, & ! atm memory bounds
  1033. ips,ipe,jps,jpe, &
  1034. its,ite,jts,jte, & ! atm tile bounds
  1035. ifds, ifde, jfds, jfde, & ! fire domain bounds
  1036. ifms, ifme, jfms, jfme, & ! fire memory bounds
  1037. ifps, ifpe, jfps, jfpe, & ! fire patch bounds
  1038. ifts,ifte,jfts,jfte, & ! fire tile bounds
  1039. ir,jr ! atm/fire grid refinement ratio
  1040. real, intent(in):: u_frame, v_frame ! velocity frame correction
  1041. real,intent(in),dimension(ims:ime,kms:kme,jms:jme)::&
  1042. u,v, & ! atm wind velocity, staggered
  1043. ph,phb ! geopotential
  1044. real,intent(in),dimension(ims:ime,jms:jme)::&
  1045. z0, & ! roughness height
  1046. zs ! terrain height
  1047. real,intent(out),dimension(ims:ime,jms:jme)::&
  1048. uah, & ! atm wind at fire_wind_height, diagnostics
  1049. vah !
  1050. real,intent(out), dimension(ifms:ifme,jfms:jfme)::&
  1051. uf,vf ! wind velocity fire grid nodes
  1052. !*** local
  1053. character(len=256)::msg
  1054. #define TDIMS its-2,ite+2,jts-2,jte+2
  1055. real, dimension(its-2:ite+2,jts-2:jte+2):: ua,va ! atm winds, interpolated over height, still staggered grid
  1056. real, dimension(its-2:ite+2,kds:kde,jts-2:jte+2):: altw,altub,altvb,hgtu,hgtv ! altitudes
  1057. integer:: i,j,k,ifts1,ifte1,jfts1,jfte1,ite1,jte1
  1058. integer::itst,itet,jtst,jtet,itsu,iteu,jtsu,jteu,itsv,itev,jtsv,jtev
  1059. integer::kdmax,its1,jts1,ips1,jps1
  1060. integer::itsou,iteou,jtsou,jteou,itsov,iteov,jtsov,jteov
  1061. real:: ground,loght,loglast,logz0,logfwh,ht,zr
  1062. real::r_nan
  1063. integer::i_nan
  1064. equivalence (i_nan,r_nan)
  1065. !*** executable
  1066. ! debug init local arrays
  1067. i_nan=2147483647
  1068. ua=r_nan
  1069. va=r_nan
  1070. altw=r_nan
  1071. altub=r_nan
  1072. hgtu=r_nan
  1073. hgtv=r_nan
  1074. if(kds.ne.1)then
  1075. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1076. write(msg,*)'WARNING: bottom index kds=',kds,' should be 1?'
  1077. call message(msg)
  1078. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1079. endif
  1080. ! ^ j
  1081. ! ------------ |
  1082. ! | | ----> i
  1083. ! u p |
  1084. ! | | nodes in cell (i,j)
  1085. ! ------v----- view from top
  1086. !
  1087. ! v(ide,jde+1)
  1088. ! -------x------
  1089. ! | |
  1090. ! | |
  1091. ! u(ide,jde) x x x u(ide+1,jde)
  1092. ! | p(ide,hde) |
  1093. ! | | p=ph,phb,z0,...
  1094. ! -------x------
  1095. ! v(ide,jde)
  1096. !
  1097. ! staggered values set u(ids:ide+1,jds:jde) v(ids:ide,jds:jde+1)
  1098. ! p=ph+phb set at (ids:ide,jds:jde)
  1099. ! location of u(i,j) needs p(i-1,j) and p(i,j)
  1100. ! location of v(i,j) needs p(i,j-1) and p(i,j)
  1101. ! *** NOTE need HALO in ph, phb
  1102. ! so we can compute only u(ids+1:ide,jds:jde) v(ids:ide,jds+1,jde)
  1103. ! unless we extend p at the boundary
  1104. ! but because we care about the fire way in the inside it does not matter
  1105. ! if the fire gets close to domain boundary the simulation is over anyway
  1106. ite1=snode(ite,ide,1)
  1107. jte1=snode(jte,jde,1)
  1108. ! do this in any case to check for nans
  1109. call print_3d_stats(its,ite1,kds,kde,jts,jte,ims,ime,kms,kme,jms,jme,u,'wind U in')
  1110. call print_3d_stats(its,ite,kds,kde,jts,jte1,ims,ime,kms,kme,jms,jme,v,'wind V in')
  1111. if(fire_print_msg.gt.0)then
  1112. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1113. write(msg,'(a,f7.2,a)')'interpolate_atm2fire: log-interpolation of wind to',fire_wind_height,' m'
  1114. call message(msg)
  1115. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1116. endif
  1117. ! indexing
  1118. ! for w
  1119. itst=ifval(ids.eq.its,its,its-1)
  1120. itet=ifval(ide.eq.ite,ite,ite+1)
  1121. jtst=ifval(jds.ge.jts,jts,jts-1)
  1122. jtet=ifval(jde.eq.jte,jte,jte+1)
  1123. ! for u
  1124. itsu=ifval(ids.eq.its,its+1,its) ! staggered direction
  1125. iteu=ifval(ide.eq.ite,ite,ite+1) ! staggered direction
  1126. jtsu=ifval(jds.ge.jts,jts,jts-1)
  1127. jteu=ifval(jde.eq.jte,jte,jte+1)
  1128. ! for v
  1129. jtsv=ifval(jds.eq.jts,jts+1,jts) ! staggered direction
  1130. jtev=ifval(jde.eq.jte,jte,jte+1) ! staggered direction
  1131. itsv=ifval(ids.ge.its,its,its-1)
  1132. itev=ifval(ide.eq.ite,ite,ite+1)
  1133. if(fire_print_msg.ge.1)then
  1134. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1135. write(msg,7001)'atm input ','tile',its,ite,jts,jte
  1136. call message(msg)
  1137. write(msg,7001)'altw ','tile',itst,itet,jtst,jtet
  1138. call message(msg)
  1139. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1140. endif
  1141. 7001 format(a,' dimensions ',a4,':',i6,' to ',i6,' by ',i6,' to ',i6)
  1142. !**********************************************************
  1143. !* *
  1144. !* find the altitude of the w points *
  1145. !* *
  1146. !**********************************************************
  1147. !! in future, replace by z8w & test if the same
  1148. kdmax=kde-1 ! max layer to interpolate from, can be less
  1149. do j = jtst,jtet
  1150. do k=kds,kdmax+1
  1151. do i = itst,itet
  1152. altw(i,k,j) = (ph(i,k,j)+phb(i,k,j))/g ! altitude of the bottom w-point
  1153. enddo
  1154. enddo
  1155. enddo
  1156. ! values at u points
  1157. if(fire_print_msg.ge.1)then
  1158. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1159. write(msg,7001)'u interp at','tile',itsu,iteu,jtsu,jteu
  1160. call message(msg)
  1161. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1162. endif
  1163. !**********************************************************
  1164. !* *
  1165. !* interpolate the altitude from w points to u points *
  1166. !* *
  1167. !**********************************************************
  1168. do j = jtsu,jteu
  1169. do k=kds,kdmax+1
  1170. do i = itsu,iteu
  1171. altub(i,k,j)= 0.5*(altw(i-1,k,j)+altw(i,k,j)) ! altitude of the bottom point under u-point
  1172. enddo
  1173. enddo
  1174. do k=kds,kdmax
  1175. do i = itsu,iteu
  1176. hgtu(i,k,j) = 0.5*(altub(i,k,j)+altub(i,k+1,j)) - altub(i,kds,j) ! height of the u-point above the ground
  1177. enddo
  1178. enddo
  1179. enddo
  1180. ! values at v points
  1181. if(fire_print_msg.ge.1)then
  1182. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1183. write(msg,7001)'v interp at','tile',itsv,itev,jtsv,jtev
  1184. call message(msg)
  1185. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1186. endif
  1187. !**********************************************************
  1188. !* *
  1189. !* interpolate the altitude from w points to v points *
  1190. !* *
  1191. !**********************************************************
  1192. do j = jtsv,jtev
  1193. do k=kds,kdmax+1
  1194. do i = itsv,itev
  1195. altvb(i,k,j)= 0.5*(altw(i,k,j-1)+altw(i,k,j)) ! altitude of the bottom point under v-point
  1196. enddo
  1197. enddo
  1198. do k=kds,kdmax
  1199. do i = itsv,itev
  1200. hgtv(i,k,j) = 0.5*(altvb(i,k,j)+altvb(i,k+1,j)) - altvb(i,kds,j) ! height of the v-point above the ground
  1201. enddo
  1202. enddo
  1203. enddo
  1204. #ifdef DEBUG_OUT
  1205. call write_array_m3(itsu,iteu,kds,kdmax,jtsu,jteu,its-2,ite+2,kds,kde,jts-2,jte+2,altub,'altub',id)
  1206. call write_array_m3(itsv,itev,kds,kdmax,jtsv,jtev,its-2,ite+2,kds,kde,jts-2,jte+2,altvb,'altvb',id)
  1207. call write_array_m3(itsu,iteu,kds,kdmax,jtsu,jteu,its-2,ite+2,kds,kde,jts-2,jte+2,hgtu,'hgtu',id)
  1208. call write_array_m3(itsv,itev,kds,kdmax,jtsv,jtev,its-2,ite+2,kds,kde,jts-2,jte+2,hgtv,'hgtv',id)
  1209. #endif
  1210. logfwh = log(fire_wind_height)
  1211. !**********************************************************
  1212. !* *
  1213. !* interpolate u vertically to fire_wind_height *
  1214. !* *
  1215. !**********************************************************
  1216. ! interpolate u, staggered in X
  1217. do j = jtsu,jteu ! compute on domain by 1 smaller, otherwise z0 and ph not available
  1218. do i = itsu,iteu ! compute with halo 2
  1219. zr = 0.5*(z0(i,j)+z0(i-1,j)) ! interpolated roughness length under this u point
  1220. if(fire_wind_height > zr)then !
  1221. do k=kds,kdmax
  1222. ht = hgtu(i,k,j) ! height of this u point above the ground
  1223. if( .not. ht < fire_wind_height) then ! found layer k this point is in
  1224. loght = log(ht)
  1225. if(k.eq.kds)then ! first layer, log linear interpolation from 0 at zr
  1226. logz0 = log(zr)
  1227. ua(i,j)= u(i,k,j)*(logfwh-logz0)/(loght-logz0)
  1228. else ! log linear interpolation
  1229. loglast=log(hgtu(i,k-1,j))
  1230. ua(i,j)= u(i,k-1,j) + (u(i,k,j) - u(i,k-1,j)) * ( logfwh - loglast) / (loght - loglast)
  1231. endif
  1232. goto 10
  1233. endif
  1234. if(k.eq.kdmax)then ! last layer, still not high enough
  1235. ua(i,j)=u(i,k,j)
  1236. endif
  1237. enddo
  1238. 10 continue
  1239. else ! roughness higher than the fire wind height
  1240. ua(i,j)=0.
  1241. endif
  1242. enddo
  1243. enddo
  1244. !**********************************************************
  1245. !* *
  1246. !* interpolate v vertically to fire_wind_height *
  1247. !* *
  1248. !**********************************************************
  1249. ! interpolate v, staggered in Y
  1250. do j = jtsv,jtev
  1251. do i = itsv,itev
  1252. zr = 0.5*(z0(i,j-1)+z0(i,j)) ! roughness length under this v point
  1253. if(fire_wind_height > zr)then !
  1254. do k=kds,kdmax
  1255. ht = hgtv(i,k,j) ! height of this u point above the ground
  1256. if( .not. ht < fire_wind_height) then ! found layer k this point is in
  1257. loght = log(ht)
  1258. if(k.eq.kds)then ! first layer, log linear interpolation from 0 at zr
  1259. logz0 = log(zr)
  1260. va(i,j)= v(i,k,j)*(logfwh-logz0)/(loght-logz0)
  1261. else ! log linear interpolation
  1262. loglast=log(hgtv(i,k-1,j))
  1263. va(i,j)= v(i,k-1,j) + (v(i,k,j) - v(i,k-1,j)) * ( logfwh - loglast) / (loght - loglast)
  1264. endif
  1265. goto 11
  1266. endif
  1267. if(k.eq.kdmax)then ! last layer, still not high enough
  1268. va(i,j)=v(i,k,j)
  1269. endif
  1270. enddo
  1271. 11 continue
  1272. else ! roughness higher than the fire wind height
  1273. va(i,j)=0.
  1274. endif
  1275. enddo
  1276. enddo
  1277. #ifdef DEBUG_OUT
  1278. ! store the output for diagnostics
  1279. do j = jts,jte1
  1280. do i = its,ite1
  1281. uah(i,j)=ua(i,j)
  1282. vah(i,j)=va(i,j)
  1283. enddo
  1284. enddo
  1285. call write_array_m(its,ite1,jts,jte,ims,ime,jms,jme,uah,'uah_n',id) ! no reflection
  1286. call write_array_m(its,ite,jts,jte1,ims,ime,jms,jme,vah,'vah_n',id)
  1287. #endif
  1288. !**********************************************************
  1289. !* *
  1290. !* interpolate ua,va vertically to the fire mesh *
  1291. !* *
  1292. !**********************************************************
  1293. ips1 = ifval(ips.eq.ids,ips+1,ips)
  1294. call continue_at_boundary(1,1,0., & ! x direction
  1295. TDIMS, &! memory dims atm grid tile
  1296. ids+1,ide,jds,jde, & ! domain dims - where u defined
  1297. ips1,ipe,jps,jpe, & ! patch dims
  1298. itsu,iteu,jtsu,jteu, & ! tile dims - in nonextended direction one beyond if at patch boundary but not domain
  1299. itsou,iteou,jtsou,jteou, & ! out, where set
  1300. ua) ! array
  1301. jps1 = ifval(jps.eq.jds,jps+1,jps)
  1302. call continue_at_boundary(1,1,0., & ! y direction
  1303. TDIMS, & ! memory dims atm grid tile
  1304. ids,ide,jds+1,jde, & ! domain dims - where v wind defined
  1305. ips,ipe,jps1,jpe, & ! patch dims
  1306. itsv,itev,jtsv,jtev, & ! tile dims
  1307. itsov,iteov,jtsov,jteov, & ! where set
  1308. va) ! array
  1309. ! store the output for diagnostics
  1310. do j = jts,jte1
  1311. do i = its,ite1
  1312. uah(i,j)=ua(i,j)
  1313. vah(i,j)=va(i,j)
  1314. enddo
  1315. enddo
  1316. #ifdef DEBUG_OUT
  1317. call write_array_m(itsou,iteou,jtsou,jteou,TDIMS,ua,'ua',id)
  1318. call write_array_m(itsov,iteov,jtsov,jteov,TDIMS,va,'va',id)
  1319. #endif
  1320. !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
  1321. ! don't have all values valid, don't check
  1322. write(msg,12)'atm mesh wind U at',fire_wind_height,' m'
  1323. call print_2d_stats(itsou,iteou,jtsou,jteou,TDIMS,ua,msg)
  1324. write(msg,12)'atm mesh wind V at',fire_wind_height,' m'
  1325. call print_2d_stats(itsov,iteov,jtsov,jteov,TDIMS,va,msg)
  1326. 12 format(a,f6.2,a)
  1327. call print_2d_stats(its,ite1,jts,jte,ims,ime,jms,jme,uah,'UAH')
  1328. call print_2d_stats(its,ite,jts,jte1,ims,ime,jms,jme,vah,'VAH')
  1329. !call write_array_m(its,ite1,jts,jte,ims,ime,jms,jme,uah,'uah',id)
  1330. !call write_array_m(its,ite,jts,jte1,ims,ime,jms,jme,vah,'vah',id)
  1331. !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
  1332. ! ---------------
  1333. ! | F | F | F | F | Example of atmospheric and fire grid with
  1334. ! |-------|-------| ir=jr=4.
  1335. ! | F | F | F | F | Winds are given at the midpoints of the sides of the atmosphere grid,
  1336. ! ua------z-------| interpolated to midpoints of the cells of the fine fire grid F.
  1337. ! | F | F | F | F | This is (1,1) cell of atmosphere grid, and [*] is the (1,1) cell of the fire grid.
  1338. ! |---------------| ua(1,1) <--> uf(0.5,2.5)
  1339. ! | * | F | F | F | va(1,1) <--> vf(2.5,0.5)
  1340. ! -------va------ za(1,1) <--> zf(2.5,2.5)
  1341. !
  1342. ! ^ x2
  1343. ! | --------va(1,2)---------
  1344. ! | | | | Example of atmospheric and fire grid with
  1345. ! | | | | ir=jr=1.
  1346. ! | | za,zf | Winds are given at the midpoints of the sides of the atmosphere grid,
  1347. ! | ua(1,1)----uf,vf-----ua(2,1) interpolated to midpoints of the cells of the (the same) fire grid
  1348. ! | | (1,1) | ua(1,1) <--> uf(0.5,1)
  1349. ! | | | | va(1,1) <--> vf(1,0.5)
  1350. ! | | | | za(1,1) <--> zf(1,1)
  1351. ! | --------va(1,1)---------
  1352. ! |--------------------> x1
  1353. !
  1354. ! Meshes are aligned by the lower left cell of the domain. Then in the above figure
  1355. ! u = node with the ua component of the wind at (ids,jds), midpoint of side
  1356. ! v = node with the va component of the wind at (ids,jds), midpoint of side
  1357. ! * = fire grid node at (ifds,jfds)
  1358. ! z = node with height, midpoint of cell
  1359. !
  1360. ! ua(ids,jds)=uf(ifds-0.5,jfds+jr*0.5-0.5) = uf(ifds-0.5,jfds+(jr-1)*0.5)
  1361. ! va(ids,jds)=vf(ifds+ir*0.5-0.5,jfds-0.5) = vf(ifds+(ir-1)*0.5,jfds-0.5)
  1362. ! za(ids,jds)=zf(ifds+ir*0.5-0.5,jfds+jr*0.5-0.5) = zf(ifds+(ir-1)*0.5,jfds+(jr-1)*0.5)
  1363. ! ifts1=max(snode(ifts,ifps,-1),ifds) ! go 1 beyond patch boundary but not at domain boundary
  1364. ! ifte1=min(snode(ifte,ifpe,+1),ifde)
  1365. ! jfts1=max(snode(jfts,jfps,-1),jfds)
  1366. ! jfte1=min(snode(jfte,jfpe,+1),jfde)
  1367. call interpolate_2d( &
  1368. TDIMS, & ! memory dims atm grid tile
  1369. itsou,iteou,jtsou,jteou,& ! where set
  1370. ifms,ifme,jfms,jfme, & ! array dims fire grid
  1371. ifts,ifte,jfts,jfte,& ! dimensions on the fire grid to interpolate to
  1372. ir,jr, & ! refinement ratio
  1373. real(ids),real(jds),ifds-0.5,jfds+(jr-1)*0.5, & ! line up by lower left corner of domain
  1374. ua, & ! in atm grid
  1375. uf) ! out fire grid
  1376. call interpolate_2d( &
  1377. TDIMS, & ! memory dims atm grid tile
  1378. itsov,iteov,jtsov,jteov,& ! where set
  1379. ifms,ifme,jfms,jfme, & ! array dims fire grid
  1380. ifts,ifte,jfts,jfte,& ! dimensions on the fire grid to interpolate to
  1381. ir,jr, & ! refinement ratio
  1382. real(ids),real(jds),ifds+(ir-1)*0.5,jfds-0.5, & ! line up by lower left corner of domain
  1383. va, & ! in atm grid
  1384. vf) ! out fire grid
  1385. call print_2d_stats_vec(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,uf,vf,'fire wind (m/s)')
  1386. ! call print_2d_stats_vec(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,uf,vf,'fire wind extended')
  1387. #ifdef DEBUG_OUT
  1388. call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,uf,'uf1',id)
  1389. call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,vf,'vf1',id)
  1390. ! call write_array_m(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,uf,'uf1',id)
  1391. ! call write_array_m(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,vf,'vf1',id)
  1392. #endif
  1393. return
  1394. end subroutine interpolate_atm2fire
  1395. subroutine apply_windrf( &
  1396. ifms,ifme,jfms,jfme, &
  1397. ifts,ifte,jfts,jfte, &
  1398. nfuel_cat,uf,vf)
  1399. integer:: &
  1400. ifms, ifme, jfms, jfme, & ! fire memory bounds
  1401. ifts, ifte, jfts, jfte ! fire tile bounds
  1402. real,intent(in),dimension(ifms:ifme,jfms:jfme)::nfuel_cat
  1403. real,intent(inout),dimension(ifms:ifme,jfms:jfme)::uf,vf
  1404. !*** local
  1405. integer::i,j,k
  1406. !*** executable
  1407. do j = jfts,jfte
  1408. do i = ifts,ifte
  1409. k=int( nfuel_cat(i,j) )
  1410. if(k.lt.no_fuel_cat)then
  1411. uf(i,j)=uf(i,j)*windrf(k)
  1412. vf(i,j)=vf(i,j)*windrf(k)
  1413. else
  1414. uf(i,j)=0.
  1415. vf(i,j)=0.
  1416. endif
  1417. enddo
  1418. enddo
  1419. end subroutine apply_windrf
  1420. !
  1421. !***
  1422. !
  1423. subroutine setup_wind_log_interpolation( &
  1424. ids,ide, jds,jde, & ! atm grid dimensions
  1425. ims,ime, jms,jme, &
  1426. ips,ipe,jps,jpe, &
  1427. its,ite,jts,jte, &
  1428. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  1429. ifms, ifme, jfms, jfme, &
  1430. ifts, ifte, jfts, jfte, &
  1431. ir,jr, & ! atm/fire grid ratio
  1432. z0, & ! atm grid arrays in
  1433. nfuel_cat, & ! fire array in
  1434. fz0,fwh) ! fire arrays out
  1435. !*** arguments
  1436. integer, intent(in):: &
  1437. ids,ide, jds,jde, & ! atm domain bounds
  1438. ims,ime, jms,jme, & ! atm memory bounds
  1439. ips,ipe,jps,jpe, &
  1440. its,ite,jts,jte, & ! atm tile bounds
  1441. ifds, ifde, jfds, jfde, & ! fire domain bounds
  1442. ifms, ifme, jfms, jfme, & ! fire memory bounds
  1443. ifts, ifte, jfts, jfte, & ! fire tile bounds
  1444. ir,jr ! atm/fire grid refinement ratio
  1445. real,intent(in),dimension(ims:ime,jms:jme)::z0 ! landuse roughness length
  1446. real,intent(in),dimension(ifms:ifme,jfms:jfme)::nfuel_cat ! fuel category
  1447. real,intent(out),dimension(ifms:ifme,jfms:jfme)::&
  1448. fz0, & ! roughness height
  1449. fwh ! height to read the wind from
  1450. !*** local
  1451. integer::i,j,ii,jj,k,id=0
  1452. character(len=128)::msg
  1453. real::r
  1454. !*** executable
  1455. if(.not.have_fuel_cats)call crash('setup_wind_log_interpolation: fuel categories not yet set')
  1456. select case(fire_wind_log_interp)
  1457. case(1)
  1458. call message('fire_wind_log_interp=1: log interpolation on fire mesh, roughness and wind height from fuel categories')
  1459. do j=jfts,jfte
  1460. do i=ifts,ifte
  1461. k = int(nfuel_cat(i,j))
  1462. if(k.ge.no_fuel_cat.and.k.le.no_fuel_cat2)then ! no fuel
  1463. fz0(i,j)=-1.
  1464. fwh(i,j)=-1.
  1465. elseif(k < 1 .or. k > nfuelcats) then
  1466. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1467. write(msg,*)'i,j,nfuel_cat,nfuelcats=',i,j,k,nfuelcats
  1468. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1469. call message(msg)
  1470. call crash('setup_wind_log_interpolation: fuel category out of bounds')
  1471. else
  1472. fz0(i,j)=fcz0(k)
  1473. fwh(i,j)=fcwh(k)
  1474. endif
  1475. enddo
  1476. enddo
  1477. case(2)
  1478. call message('fire_wind_log_interp=2: log interpolation on fire mesh' // &
  1479. 'piecewise constant roughness from landuse, constant fire_wind_height')
  1480. do j=jts,jte
  1481. do i=its,ite
  1482. do jj=(j-1)*jr+1,(j-1)*jr+jr
  1483. do ii=(i-1)*ir+1,(i-1)*ir+ir
  1484. fz0(ii,jj)=z0(i,j)
  1485. enddo
  1486. enddo
  1487. enddo
  1488. enddo
  1489. do j=jfts,jfte
  1490. do i=ifts,ifte
  1491. k = int(nfuel_cat(i,j))
  1492. if(k.lt.no_fuel_cat)then ! no fuel, interpolation does not matter
  1493. fwh(i,j)=fcwh(k)
  1494. else
  1495. fz0(i,j)=-1.
  1496. fwh(i,j)=-1.
  1497. endif
  1498. enddo
  1499. enddo
  1500. case(3)
  1501. call message('fire_wind_log_interp=3: log interpolation on fire mesh,' // &
  1502. ' interpolated roughness from landuse, constant fire_wind_height')
  1503. call interpolate_z2fire(id,1, & ! for debug output, <= 0 no output
  1504. ids,ide, jds,jde, & ! atm grid dimensions
  1505. ims,ime, jms,jme, &
  1506. ips,ipe,jps,jpe, &
  1507. its,ite,jts,jte, &
  1508. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  1509. ifms, ifme, jfms, jfme, &
  1510. ifts,ifte,jfts,jfte, &
  1511. ir,jr, & ! atm/fire grid ratio
  1512. z0, & ! atm grid arrays in
  1513. fz0) ! fire grid arrays out
  1514. do j=jfts,jfte
  1515. do i=ifts,ifte
  1516. k = int(nfuel_cat(i,j))
  1517. if(k.ne.no_fuel_cat)then ! no fuel, interpolation does not matter
  1518. fwh(i,j)=fcwh(k)
  1519. else
  1520. fz0(i,j)=-1.
  1521. fwh(i,j)=-1.
  1522. endif
  1523. enddo
  1524. enddo
  1525. case(4)
  1526. call message('fire_wind_log_interp=4: log interpolation on atmospheric' // &
  1527. ' mesh, roughness from landuse, constant fire_wind_height')
  1528. return
  1529. case default
  1530. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1531. write(msg,*)'setup_wind_log_interpolation: invalid fire_wind_log_interp=',fire_wind_log_interp
  1532. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1533. call crash('msg')
  1534. end select
  1535. select case(fire_use_windrf)
  1536. case(0)
  1537. call message('setup_wind_log_interpolation: not using wind reduction factors')
  1538. case(1)
  1539. call message('setup_wind_log_interpolation: multiplying wind by reduction factors')
  1540. case(2)
  1541. call message('setup_wind_log_interpolation: resetting wind interpolation height from wind reduction factors')
  1542. do j=jfts,jfte
  1543. do i=ifts,ifte
  1544. k = int(nfuel_cat(i,j))
  1545. if(k.ne.no_fuel_cat)then
  1546. fwh(i,j) = fz0(i,j) ** (1.-windrf(k)) * fire_wind_height ** windrf(k) ! GMD paper eq. (26)
  1547. if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
  1548. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1549. write(msg,*)'category ',k,'windrf=',windrf(k),' fire_wind_height=',fire_wind_height
  1550. call message(msg,level=-1)
  1551. write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
  1552. call message(msg,level=-1)
  1553. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1554. call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
  1555. endif
  1556. endif
  1557. enddo
  1558. enddo
  1559. case(3)
  1560. if(fire_wind_log_interp.eq.2.or.fire_wind_log_interp.eq.3)then
  1561. call message('setup_wind_log_interpolation: adjusting wind interpolation height for LANDUSE roughness height')
  1562. do j=jfts,jfte
  1563. do i=ifts,ifte
  1564. k = int(nfuel_cat(i,j))
  1565. if(k.lt.no_fuel_cat)then
  1566. r = log(fcwh(k)/fcz0(k))/log(fire_wind_height/fcz0(k))! GMD paper eq. (25)
  1567. fwh(i,j) = fz0(i,j) ** (1.-r) * fire_wind_height ** r ! GMD paper eq. (26)
  1568. if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
  1569. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1570. write(msg,*)'category ',k, 'roughness ',fcz0(k),' midflame height ',fcwh(k),' fire_wind_height=',fire_wind_height
  1571. call message(msg,level=-1)
  1572. write(msg,*)'computed wind reduction factor ',r
  1573. call message(msg,level=-1)
  1574. write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
  1575. call message(msg,level=-1)
  1576. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1577. call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
  1578. endif
  1579. endif
  1580. enddo
  1581. enddo
  1582. else
  1583. call message('setup_wind_log_interpolation: not using wind reduction factors')
  1584. endif
  1585. case default
  1586. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1587. write(msg,*)'setup_wind_log_interpolation: invalid fire_use_windrf=',fire_use_windrf
  1588. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1589. call crash('msg')
  1590. end select
  1591. ! consistency check
  1592. do j=jfts,jfte
  1593. do i=ifts,ifte
  1594. k = int(nfuel_cat(i,j))
  1595. if(k.lt.no_fuel_cat)then
  1596. if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
  1597. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1598. write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
  1599. call message(msg,level=-1)
  1600. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1601. call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
  1602. endif
  1603. else
  1604. if(.not.fwh(i,j)<0.)then
  1605. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1606. write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
  1607. call message(msg,level=-1)
  1608. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1609. call crash('setup_wind_log_interpolation: no fuel must be signalled by fwh<0')
  1610. endif
  1611. endif
  1612. enddo
  1613. enddo
  1614. have_wind_log_interpolation = .true.
  1615. call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fz0,'setup_wind_log:fz0')
  1616. call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fz0,'setup_wind_log:fwh')
  1617. end subroutine setup_wind_log_interpolation
  1618. !
  1619. !***
  1620. !
  1621. subroutine interpolate_wind2fire_height(id, & ! to identify debugging prints and files if needed
  1622. ids,ide, kds,kde, jds,jde, & ! atm grid dimensions
  1623. ims,ime, kms,kme, jms,jme, &
  1624. ips,ipe,jps,jpe, &
  1625. its,ite,jts,jte, &
  1626. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  1627. ifms, ifme, jfms, jfme, &
  1628. ifps, ifpe, jfps, jfpe, & ! fire patch bounds
  1629. ifts,ifte,jfts,jfte, &
  1630. ir,jr, & ! atm/fire grid ratio
  1631. u_frame, v_frame, & ! velocity frame correction
  1632. u,v,ph,phb, & ! input atmospheric arrays
  1633. fz0,fwh, & ! input fire arrays
  1634. uf,vf) ! output fire arrays
  1635. implicit none
  1636. !*** arguments
  1637. integer, intent(in):: id, & ! debug identification
  1638. ids,ide, kds,kde, jds,jde, & ! atm domain bounds
  1639. ims,ime, kms,kme, jms,jme, & ! atm memory bounds
  1640. ips,ipe,jps,jpe, &
  1641. its,ite,jts,jte, & ! atm tile bounds
  1642. ifds, ifde, jfds, jfde, & ! fire domain bounds
  1643. ifms, ifme, jfms, jfme, & ! fire memory bounds
  1644. ifps, ifpe, jfps, jfpe, & ! fire patch bounds
  1645. ifts,ifte,jfts,jfte, & ! fire tile bounds
  1646. ir,jr ! atm/fire grid refinement ratio
  1647. real, intent(in):: u_frame, v_frame ! velocity frame correction
  1648. real,intent(in),dimension(ims:ime,kms:kme,jms:jme)::&
  1649. u,v, & ! atm wind velocity, staggered
  1650. ph,phb ! geopotential
  1651. real,intent(in),dimension(ifms:ifme,jfms:jfme)::&
  1652. fz0, & ! roughness height
  1653. fwh ! height to read the wind from
  1654. real,intent(out),dimension(ifms:ifme,jfms:jfme)::&
  1655. uf, & ! atm wind at fire_wind_height, diagnostics
  1656. vf !
  1657. !*** local
  1658. integer:: i,j,k,jcb,jcm,icb,icm,kdmax,kmin,kmax
  1659. integer::itst,itet,jtst,jtet
  1660. integer::iftst,iftet,jftst,jftet
  1661. real:: wjcb,wjcm,wicb,wicm,ht,i_g,loght,zr,ht_last,logwh,wh,loght_last,uk,vk,uk1,vk1,z0,logz0
  1662. real, dimension (its-1:ite+1,kds:kde,jts-1:jte+1):: z
  1663. character(len=128)::msg
  1664. !*** executable
  1665. if(.not. have_wind_log_interpolation) call crash('interpolate_wind2fire_height: wind_log_interpolation must be set up first')
  1666. ! print *,'interpolate_wind2fire_height start, id=',id
  1667. kdmax=kde-1 ! max layer to use
  1668. ! find the altitude of atm cell centers
  1669. ! index bounds for cell centers - need to go one beyond if at end of tile but not domain
  1670. itst=ifval(ids.eq.its,its,its-1)
  1671. itet=ifval(ide.eq.ite,ite,ite+1)
  1672. jtst=ifval(jds.ge.jts,jts,jts-1)
  1673. jtet=ifval(jde.eq.jte,jte,jte+1)
  1674. ! print *,'its, ite, jts, jte =',its, ite, jts, jte
  1675. ! print *,'itst, itet, jtst, jtet=',itst, itet, jtst, jtet
  1676. ! get altitudes
  1677. i_g = 1./g
  1678. do j = jtst,jtet
  1679. do k=kds,kdmax+1
  1680. do i = itst,itet
  1681. z(i,k,j) = (ph(i,k,j)+phb(i,k,j))*i_g ! altitude of the bottom w-point
  1682. ! print *,'i,k,j=',i,k,j,'ph, phb, z=',ph(i,k,j),phb(i,k,j),z(i,k,j)
  1683. enddo
  1684. enddo
  1685. do k=kds,kdmax
  1686. do i = itst,itet
  1687. z(i,k,j) = (z(i,k,j)+z(i,k+1,j))*0.5 - z(i,kds,j) ! height of the cell center
  1688. enddo
  1689. enddo
  1690. enddo
  1691. ! index bounds for fire mesh cell centers
  1692. ! to prevent setting values from uninitialized memory
  1693. iftst=ifval(ifds.eq.ifts,ifts+ir/2,ifts)
  1694. iftet=ifval(ifde.eq.ifte,ifte-ir/2,ifte)
  1695. jftst=ifval(jfds.ge.jfts,jfts+jr/2,jfts)
  1696. jftet=ifval(jfde.eq.jfte,jfte-jr/2,jfte)
  1697. ! print *,'iftst, iftet, jftst, jftet=',iftst, iftet, jftst, jftet
  1698. ! zero out first, to prevent unitialized values on strips along domain boundaries
  1699. ! it would be faster but longer code to do just cleanup loop on the strips
  1700. do j = jfts,jfte
  1701. do i = ifts,ifte
  1702. uf(i,j)=0.
  1703. vf(i,j)=0.
  1704. enddo
  1705. enddo
  1706. ! vertical and horizontal interpolation
  1707. kmin=kde ! init stats
  1708. kmax=kds
  1709. loop_j: do j = jftst,jftet
  1710. call coarse(j,jr,-2,jcb,wjcb) ! get interpolation coefficients from the boundary
  1711. call coarse(j,jr,ir,jcm,wjcm) ! get interpolation coefficients from the midpoint
  1712. loop_i: do i = iftst,iftet
  1713. call coarse(i,ir,-2,icb,wicb) ! get interpolation coefficients from the boundary
  1714. call coarse(i,ir,ir,icm,wicm) ! get interpolation coefficients from the midpoint
  1715. z0 = fz0(i,j) ! roughness length
  1716. wh = fwh(i,j) ! wind height
  1717. ! print *,'i=',i,' j=',j,' icb=',icb,' jcb=',jcb,' z0=',z0,' wh=',wh
  1718. if( wh > z0 .and. z0 > 0)then
  1719. ht_last=z0 ! initialize starting height of this layer
  1720. loop_k: do k=kds,kdmax ! search for layer k such that ht(k-1)<=wh<ht(k), ht(0)=z0
  1721. ! interpolate height from atmospheric cell midpoints
  1722. ht=interpolate_h(its-1,ite+1,kds,kde,jts-1,jts+1,icm,k,jcm,wicm,wjcm,z)
  1723. ! print *,'i=',i,' j=',j,'k=',k,' ht=',ht
  1724. if(.not. ht < wh) exit loop_k ! found layer k this point is in
  1725. ht_last = ht
  1726. enddo loop_k
  1727. if(k .gt. kdmax) then
  1728. goto 91 ! run out of vertical levels, this must be wrong
  1729. endif
  1730. kmin=min(k,kmin)
  1731. kmax=max(k,kmax)
  1732. ! found layer k, ht_last < wh <= ht
  1733. logz0 = log(z0)
  1734. logwh= log(wh)
  1735. loght_last = log(ht_last)
  1736. loght = log(ht)
  1737. ! interpolate u at level k from staggered coarse grid: boundary in i, midpoints in j
  1738. uk=interpolate_h(ims,ime,kms,kme,jms,jme,icb,k,jcm,wicb,wjcm,u) - u_frame
  1739. ! print *,'i=',i,' j=',j,' uk=',uk
  1740. ! interpolate v at level k from staggered coarse grid: midpoints in i, boundary in j
  1741. vk=interpolate_h(ims,ime,kms,kme,jms,jme,icm,k,jcb,wicm,wjcb,v) - v_frame
  1742. ! print *,'i=',i,' j=',j,' vk=',vk
  1743. if(k.gt.kds)then ! interpolate u,v horizontaly at the previous layer, k-1
  1744. ! interpolate u at level k-1 from staggered coarse grid: boundary in i, midpoints in j
  1745. uk1=interpolate_h(ims,ime,kms,kme,jms,jme,icb,k-1,jcm,wicb,wjcm,u)
  1746. ! print *,'i=',i,' j=',j,' uk1=',uk1
  1747. ! interpolate v at level k-1 from staggered coarse grid: midpoints in i, boundary in j
  1748. vk1=interpolate_h(ims,ime,kms,kme,jms,jme,icm,k-1,jcb,wicm,wjcb,v)
  1749. ! print *,'i=',i,' j=',j,' uk1=',uk1
  1750. else ! there is no previous layer, wind at roughness is assumed 0
  1751. uk1=0.
  1752. vk1=0.
  1753. endif
  1754. ! log interpolate the wind to wh
  1755. uf(i,j)= uk1 + (uk - uk1) * ( logwh - loght_last) / (loght - loght_last)
  1756. vf(i,j)= vk1 + (vk - vk1) * ( logwh - loght_last) / (loght - loght_last)
  1757. ! print *,'i=',i,' j=',j,' uk=',uk,' vk=',vk,' uk1=',uk1,' vk1=',vk1,' uf=',uf(i,j),' vf=',vf(i,j)
  1758. else
  1759. ! no fuel, no wind
  1760. uf(i,j) = 0.
  1761. vf(i,j) = 0.
  1762. endif
  1763. enddo loop_i
  1764. enddo loop_j
  1765. ! print *,'interpolate_wind2fire_height complete, id=',id
  1766. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1767. write(msg,*)'wind interpolated from layers',kmin,' to ',kmax
  1768. call message(msg)
  1769. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1770. return
  1771. 91 call crash('interpolate_wind2fire_height: fire wind height too large, increase kdmax or atm height')
  1772. 92 continue
  1773. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1774. write(msg,*)'fz0(',i,j,')=',fz0(i,j),'fwh(',i,j,')=',fwh(i,j)
  1775. call message(msg)
  1776. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1777. call crash('interpolate_wind2fire_height: must have fire wind height > roughness height > 0')
  1778. contains
  1779. real function interpolate_h(ims,ime,kms,kme,jms,jme,ic,kc,jc,wic,wjc,a)
  1780. !*** purpose: bilinear interpolation from a(ic:ic+1,k,jc:jc+1) with weights wicm wjcm
  1781. implicit none
  1782. !*** arguments
  1783. integer, intent(in)::ims,ime,jms,kms,kme,jme,ic,kc,jc
  1784. real, intent(in)::wic,wjc,a(ims:ime,kms:kme,jms:jme)
  1785. !*** executable
  1786. interpolate_h = &
  1787. a(ic,kc,jc) *wic *wjc + &
  1788. a(ic,kc,jc+1) *wic *(1.-wjc) + &
  1789. a(ic+1,kc,jc) *(1.-wic)*wjc + &
  1790. a(ic+1,kc,jc+1)*(1.-wic)*(1.-wjc)
  1791. end function interpolate_h
  1792. subroutine coarse(ix,nr,ia,ic,w)
  1793. !*** find coarse mesh index and interpolation weight
  1794. !*** arguments
  1795. implicit none
  1796. integer, intent(in)::ix,nr,ia
  1797. integer, intent(out)::ic
  1798. real, intent(out)::w
  1799. !*** description
  1800. ! given fine mesh with nr cells for each coarse mesh cell and such that
  1801. ! coarse mesh node 1 is aligned with the fine mesh at (na+1)/2
  1802. ! for fine mesh node ix find its coarse mesh coordinate c and return
  1803. ! ic=floor(c), the index of the nearest coarse mesh node below
  1804. ! w =1-(c-ic), the interpolation weight from coarse mesh node ic to fine mesh node ix
  1805. !
  1806. ! Intended use:
  1807. ! fine mesh nodes are always at the middle of their cells
  1808. !
  1809. ! the alignment when the coarse nodes are on the boundary of coarse cells:
  1810. ! |---1---|---2---|.......|--nr---| fine mesh
  1811. ! 1-------------------------------2 coarse mesh
  1812. ! ia = -2 because coarse node 1 is aligned with the fine mesh at -1/2 = (-2 + 1)/2
  1813. !
  1814. ! the alignment when the coarse node is at the midpoint of coarse cell:
  1815. ! |---1---|---2---|---3---|---4---| fine mesh, here nr=4
  1816. ! |---------------1---------------| coarse mesh
  1817. ! ia = nr because coarse node 1 is aligned with the fine mesh at (nr + 1)/2
  1818. ! here, (4 + 1)/2 = 2.5
  1819. !
  1820. !*** local
  1821. real:: c,a
  1822. !*** executable
  1823. a = (ia + 1)*0.5 ! the location on the fine grid where coarse node 1 is aligned
  1824. c = 1 + (ix - a)/nr ! coarse mesh coordinate of ix
  1825. ic= floor(c) ! nearest coarse node to the left
  1826. w = (1 + ic) - c ! interpolation weight, 1-(c-ic)
  1827. end subroutine coarse
  1828. end subroutine interpolate_wind2fire_height
  1829. !#ifdef WRF_CHEM
  1830. subroutine fire_emission( &
  1831. tracer_opt, &
  1832. ids,ide, kds,kde, jds,jde, & ! domain dimensions
  1833. ims,ime, kms,kme, jms,jme, &
  1834. its,ite, kts,kte, jts,jte, &
  1835. rho,dz8w, &
  1836. grnhfx, & ! input variables from fire model
  1837. tracer ) ! output emissions array
  1838. use module_state_description , only: num_tracer, p_tr17_1
  1839. #ifdef WRF_CHEM
  1840. use module_state_description , only: p_smoke
  1841. #endif
  1842. integer, intent(in)::tracer_opt
  1843. INTEGER , INTENT(in) :: ids,ide, kds,kde, jds,jde, &
  1844. ims,ime, kms,kme, jms,jme, &
  1845. its,ite, kts,kte, jts,jte
  1846. real,intent(in),dimension( ims:ime,jms:jme ) :: grnhfx
  1847. real,intent(inout),dimension( ims:ime,kms:kme,jms:jme,num_tracer ) :: tracer
  1848. real,intent(in),dimension( ims:ime,kms:kme,jms:jme ) :: rho,dz8w
  1849. integer::i,j,k,l
  1850. character(len=128)::msg
  1851. real::t,s
  1852. ! just a dumb placeholder
  1853. k=kds ! dump into surface layer
  1854. select case(tracer_opt)
  1855. case(0)
  1856. return ! no tracers
  1857. case(1)
  1858. #ifdef WRF_CHEM
  1859. l=p_smoke
  1860. #else
  1861. call crash('fire_emission: tracer_opt=1 requires WRF-Chem')
  1862. #endif
  1863. case(2)
  1864. l=p_tr17_1
  1865. case default
  1866. call crash('fire_emission: tracer_opt not supported')
  1867. end select
  1868. if(num_tracer<l)call crash('fire_emission: num_tracer too small')
  1869. s=0
  1870. do j=jts,jte
  1871. do i=its,ite
  1872. t = grnhfx(i,j)/(rho(i,k,j)*dz8w(i,k,j))
  1873. tracer(i,k,j,l) = tracer(i,k,j,l) + t
  1874. s = s + t
  1875. enddo
  1876. enddo
  1877. !$OMP CRITICAL(SFIRE_ATM_CRIT)
  1878. if(fire_print_msg >= 1)then
  1879. write(msg,'(a,4i6,a,e13.4,a,i4)')'Tile ',its,ite,jts,jte,' added ',s,' total to tracer',l
  1880. call message(msg,level=0)
  1881. endif
  1882. !$OMP END CRITICAL(SFIRE_ATM_CRIT)
  1883. end subroutine fire_emission
  1884. !#endif
  1885. end module module_fr_sfire_atm