1 !WRF:MEDIATION_LAYER:FIRE_MODEL
3 !*** Jan Mandel August 2007 - February 2010
4 !*** email: Jan.Mandel@gmail.com
6 ! Routines dealing with the atmosphere
8 module module_fr_sfire_atm
10 use module_model_constants, only: cp,xlv,g
11 use module_fr_sfire_phys, only: fire_wind_height,have_fuel_cats,fcz0,fcwh,nfuelcats,no_fuel_cat,no_fuel_cat2,windrf
12 use module_fr_sfire_util
13 USE module_dm , only : wrf_dm_sum_reals
16 use module_fr_sfire_phys, only: mfuelcats, nfuelcats ! for emissions
17 USE module_state_description, only: num_tracer
18 use module_fr_sfire_phys, only: fuel_name
21 USE module_state_description, only: num_chem
22 USE module_configure, only: &
69 p_smoke, & ! tracer smoke exists only with CHEM
85 USE module_state_description, only: &
98 integer, parameter, private:: num_chem=0
101 logical, save :: have_wind_log_interpolation = .false. ! status
104 REAL, dimension(mfuelcats), save:: &
174 real, parameter:: & ! reciprocal molecular weights (mol/g)
179 imw_no2 = 1./46.006,&
180 imw_so2 = 1./64.066,&
183 real, parameter:: mw_air=28.97 ! molecular weight of air g/mol
185 ! should be declared in the registry and stored in the state in future because of restarts
187 real, pointer, save, dimension(:)::c_chem
188 real, pointer, save, dimension(:)::c_fuel
189 real, pointer, save, dimension(:)::c_tracer
190 logical, save:: emis_read = .false.
191 integer, save:: msglevel =1,printsums=0 ! when to print sums
192 integer, parameter:: line=5 ! number of species, emissions, etc. per line
196 ! chem arrays are chem tracer
197 ! indices p_species are generated in inc/scalar_indices.inc and included in frame/module_configure.F
199 subroutine read_emissions_table(chem_opt,tracer_opt)
201 integer, intent(in)::chem_opt,tracer_opt
202 logical, external:: wrf_dm_on_monitor
203 external::wrf_dm_bcast_integer , wrf_dm_bcast_real
204 integer, dimension(10)::compatible_chem_opt
205 integer:: iounit,ierr,i
206 character(len=128)::msg
207 namelist/emissions/ compatible_chem_opt, printsums, &
277 !$ if (OMP_GET_THREAD_NUM() .ne. 0)then
278 !$ call crash('read_emissions_table: must be called from master thread')
281 IF ( wrf_dm_on_monitor() ) THEN
282 ! we are the master task
284 iounit=open_text_file('namelist.fire_emissions','read')
285 compatible_chem_opt=0
286 read(iounit,emissions,iostat=ierr)
287 if(ierr.ne.0)call crash('read_emissions_table: error reading namelist emissions in file namelist.fire_emissions')
289 write(msg,'(a,i3,a)')'reading emissions table for',nfuelcats,' fuel categories'
290 call message(msg,level=0)
291 if (.not.any(compatible_chem_opt.eq.chem_opt))then
292 write(msg,'(a,i4,a)')'read_emissions_table: chem_opt=',chem_opt,' not between given compatible_chem_opt in namelist.fire_emissions'
293 call message(msg,level=0)
294 write(msg,'(a,10i4)')'compatible_chem_opt=', compatible_chem_opt
295 call message(msg,level=0)
296 call crash('chem_opt in namelist.input is not consistent with namelist.fire_emissions')
299 call wrf_dm_bcast_integer(printsums, 1)
300 call wrf_dm_bcast_real(co, nfuelcats)
301 call wrf_dm_bcast_real(ch4, nfuelcats)
302 call wrf_dm_bcast_real(h2, nfuelcats)
303 call wrf_dm_bcast_real(no, nfuelcats)
304 call wrf_dm_bcast_real(no2, nfuelcats)
305 call wrf_dm_bcast_real(so2, nfuelcats)
306 call wrf_dm_bcast_real(nh3, nfuelcats)
307 call wrf_dm_bcast_real(p25, nfuelcats)
308 call wrf_dm_bcast_real(p25i, nfuelcats)
309 call wrf_dm_bcast_real(p25j, nfuelcats)
310 call wrf_dm_bcast_real(oc1, nfuelcats)
311 call wrf_dm_bcast_real(oc2, nfuelcats)
312 call wrf_dm_bcast_real(bc1, nfuelcats)
313 call wrf_dm_bcast_real(bc2, nfuelcats)
314 call wrf_dm_bcast_real(ald, nfuelcats)
315 call wrf_dm_bcast_real(csl, nfuelcats)
316 call wrf_dm_bcast_real(eth, nfuelcats)
317 call wrf_dm_bcast_real(hc3, nfuelcats)
318 call wrf_dm_bcast_real(hc5, nfuelcats)
319 call wrf_dm_bcast_real(hcho, nfuelcats)
320 call wrf_dm_bcast_real(iso, nfuelcats)
321 call wrf_dm_bcast_real(ket, nfuelcats)
322 call wrf_dm_bcast_real(mgly, nfuelcats)
323 call wrf_dm_bcast_real(ol2, nfuelcats)
324 call wrf_dm_bcast_real(olt, nfuelcats)
325 call wrf_dm_bcast_real(oli, nfuelcats)
326 call wrf_dm_bcast_real(ora2,nfuelcats)
327 call wrf_dm_bcast_real(tol, nfuelcats)
328 call wrf_dm_bcast_real(xyl, nfuelcats)
329 call wrf_dm_bcast_real(bigalk, nfuelcats)
330 call wrf_dm_bcast_real(bigene, nfuelcats)
331 call wrf_dm_bcast_real(c10h16, nfuelcats)
332 call wrf_dm_bcast_real(c2h4, nfuelcats)
333 call wrf_dm_bcast_real(c2h5oh, nfuelcats)
334 call wrf_dm_bcast_real(c2h6, nfuelcats)
335 call wrf_dm_bcast_real(c3h6, nfuelcats)
336 call wrf_dm_bcast_real(c3h8, nfuelcats)
337 call wrf_dm_bcast_real(ch3cooh, nfuelcats)
338 call wrf_dm_bcast_real(ch3oh, nfuelcats)
339 call wrf_dm_bcast_real(cres, nfuelcats)
340 call wrf_dm_bcast_real(glyald, nfuelcats)
341 ! call wrf_dm_bcast_real(hyac, nfuelcats)
342 call wrf_dm_bcast_real(isopr, nfuelcats)
343 call wrf_dm_bcast_real(macr, nfuelcats)
344 call wrf_dm_bcast_real(mek, nfuelcats)
345 call wrf_dm_bcast_real(mvk, nfuelcats)
346 call wrf_dm_bcast_real(smoke, nfuelcats)
347 call wrf_dm_bcast_real(sulf, nfuelcats)
348 call wrf_dm_bcast_real(dms, nfuelcats)
349 call wrf_dm_bcast_real(msa, nfuelcats)
350 call wrf_dm_bcast_real(dust_1, nfuelcats)
351 call wrf_dm_bcast_real(dust_2, nfuelcats)
352 call wrf_dm_bcast_real(dust_3, nfuelcats)
353 call wrf_dm_bcast_real(dust_4, nfuelcats)
354 call wrf_dm_bcast_real(dust_5, nfuelcats)
355 call wrf_dm_bcast_real(seas_1, nfuelcats)
356 call wrf_dm_bcast_real(seas_2, nfuelcats)
357 call wrf_dm_bcast_real(seas_3, nfuelcats)
358 call wrf_dm_bcast_real(seas_4, nfuelcats)
359 call wrf_dm_bcast_real(p10, nfuelcats)
360 call wrf_dm_bcast_real(tr17_1, nfuelcats)
361 call wrf_dm_bcast_real(tr17_2, nfuelcats)
362 call wrf_dm_bcast_real(tr17_3, nfuelcats)
363 call wrf_dm_bcast_real(tr17_4, nfuelcats)
364 call wrf_dm_bcast_real(tr17_5, nfuelcats)
365 call wrf_dm_bcast_real(tr17_6, nfuelcats)
366 call wrf_dm_bcast_real(tr17_7, nfuelcats)
367 call wrf_dm_bcast_real(tr17_8, nfuelcats)
369 if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
370 ! should be stored in the registry future because of restarts
371 write(msg,'(3(a,i3,1x))')'allocating c_chem size',num_chem,'c_tracer size',num_tracer,'c_fuel size',nfuelcats
372 call message(msg,level=2)
374 allocate(c_chem(num_chem))
375 c_chem=0. ! cumulative burnt
378 allocate(c_tracer(num_tracer))
379 c_tracer=0. ! cumulative burnt
381 allocate(c_fuel(nfuelcats))
382 c_fuel=0. ! total per timestep, rate burnt, cumulative burnt
383 write(msg,'(a,i3,a,i3)')'allocated c_chem size',size(c_chem),' c_fuel size',size(c_fuel)
384 call message(msg,level=2)
389 end subroutine read_emissions_table
391 subroutine add_fire_emissions(chem_opt,tracer_opt,dt,dx,dy, &
392 ifms,ifme,jfms,jfme, &
393 ifts,ifte,jtfs,jfte, &
394 ids,ide,kds,kde,jds,jde, &
395 ims,ime,kms,kme,jms,jme, &
396 its,ite,kts,kte,jts,jte, &
397 rho,dz8w, & ! input on atmosphere mesh
398 fgip, fuel_frac_burnt, nfuel_cat, & ! input on fire mesh
399 chem,tracer) ! output
405 ! average fire emissions from fire mesh to coarser atmosphereic mesh and add to chemistry arrays
408 ! the dimensions are in cells, not nodes!
411 integer, intent(in)::chem_opt,tracer_opt
412 real, intent(in):: dt,dx,dy ! time step & mesh spacing
413 integer, intent(in)::its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme &! atm grid dims
414 ,ids,ide,kds,kde,jds,jde
415 integer, intent(in)::ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme ! fire grid dims
416 real, intent(in)::rho(ims:ime,kms:kme,jms:jme), & ! air density kg/m^3
417 dz8w(ims:ime,kms:kme,jms:jme) ! layer height
418 real, intent(in), dimension(ifms:ifme,jfms:jfme):: fgip, & ! initial fuel load kg/m^2
419 fuel_frac_burnt, & ! fuel fraction burned this step kg/kg
420 nfuel_cat ! fuel category (Anderson= 1 to 13)
422 real, intent(inout)::chem(ims:ime,kms:kme,jms:jme,num_chem),tracer(ims:ime,kms:kme,jms:jme,num_tracer)
425 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
426 real::fuel_burnt,vol,air,conv, avgw,emis
427 character(len=128)msg
429 real, dimension(mfuelcats)::s_fuel,t_fuel,r_fuel ! total per timestep, rate burnt
431 real, dimension(num_chem) ::s_chem,t_chem,r_chem ! total per timestep, rate burnt
432 real, dimension(num_chem) ::a_chem,g_chem ! concentration in ground level 1
433 integer, parameter:: chem_np=59
434 integer:: chem_pointers(chem_np)
435 character(len=8)::chem_names(chem_np)
437 real, dimension(num_tracer) ::s_tracer,t_tracer,r_tracer ! total per timestep, rate burnt
439 integer, parameter:: tracer_np=8
440 integer:: tracer_pointers(tracer_np)
441 character(len=8)::tracer_names(tracer_np)
445 !check mesh dimensions and domain dimensions
446 call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
447 call check_mesh_2dim(ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme)
449 if(.not.emis_read)call crash('add_fire_emissions: read_emissions_table must be called first')
450 write(msg,'(a,i3,a,i3,a,i3)')'add_fire_emissions: chem_opt=',chem_opt,' species ',num_chem,' tracers',num_tracer
579 call check_pointers('chem',chem,chem_names,chem_pointers)
582 tracer_pointers= (/ &
602 call check_pointers('tracer',tracer,tracer_names,tracer_pointers)
612 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)then
613 call message('all mesh sizes must be positive',level=0)
617 ! compute mesh ratios
621 if(isz2.ne.isz1*ir .or. jsz2.ne.jsz1*jr)then
622 call message('input mesh size must be multiple of output mesh size',level=0)
626 avgw = 1.0/(ir*jr) ! averaging weight = 1/number of fire cells per atm cell
628 ! initialize emissions statistics per timestep
637 ! conversion fuel_burnt kg/m^2 -> chem_X 1e6*mol/mol
638 ! emis_X(g/kg)*fuel_burnt(kg/m^2)/mw_X(g/mol) = emissions (mol/m^2)
639 ! rho(kg/m^3)*dz8w(m))/mw_air(28.97e-3 kg/mol) = dry air in the 1st layer (mol/m^2)
642 !$OMP CRITICAL(SFIRE_ATM_CRIT)
643 write(msg,'(a,i3)')'Fire tracers into atmosphere level',k1
644 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
645 call message(msg,level=msglevel)
648 if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
649 ! sum ground concentrations and check for nans
657 if(chem(i,k1,j,k_p ).ne.chem(i,k1,j,k_p ))errors=errors+1
658 a_chem(k_p)=a_chem(k_p)+chem(i,k1,j,k_p )
662 if(errors>0)call crash('NaN before chem update')
663 call wrf_dm_sum_reals(a_chem,g_chem)
664 call message('Layer1 raw sums before adding fire emissions',level=msglevel)
666 m=min(i+line-1,chem_np)
667 write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
668 call message(msg,level=msglevel)
669 write(msg,81)'Layer1 beg',(g_chem(chem_pointers(j)),j=i,m)
670 call message(msg,level=msglevel)
671 call message(' ',level=msglevel)
676 call message("Inserting chemical species",level=msglevel)
677 do j=max(jds+1,jts),min(jte,jde-1) ! safe distance from domain boundary
678 jbase=jtfs+jr*(j-jts) ! indexing
679 do i=max(ids+1,its),min(ite,ide-1)
680 ibase=ifts+ir*(i-its) ! indexing
681 !air = 1e6*mw_air/rho(i,kds,j) ! 1e6*mw_air/air density
682 !vol = avgw/dz8w(i,kds,j) ! averaging volume factor / 1st layer depth
690 !*** fire cell (i_f,j_f) contributes to atmosphere cell (i,j) at ground level
692 fuel_burnt = fgip(i_f,j_f) * fuel_frac_burnt(i_f,j_f) ! kg/m^2
693 cat = nfuel_cat(i_f, j_f) ! usually 1 to 13
695 if(cat.lt.no_fuel_cat)t_fuel(cat)=t_fuel(cat) + fuel_burnt
698 !*** chem compounds emissions given in g/kg
700 ! fuel_burnt kg/m^2 * table g/kg -> ppmv = 1e6*mol/mol in 1st layer
701 !AK rho is in kg/m3 so the conversion factor must be scaled by a 1000 to match
703 ! conv = avgw*1e6*mw_air/(rho(i,k1,j)*dz8w(i,k1,j))
704 conv = avgw*1e3*mw_air/(rho(i,k1,j)*dz8w(i,k1,j))
707 emis=co (cat)*fuel_burnt ! emission from fire cell in g/m^2
708 t_chem(p_co) = t_chem(p_co) + emis ! add to total
709 ! if(isnan(chem(i,k1,j,p_co )))call crash('NaN before')
710 chem(i,k1,j,p_co )=chem(i,k1,j,p_co ) + emis*conv*imw_co ! add to chem
711 ! if(isnan(chem(i,k1,j,p_co )))call crash('NaN after')
713 emis=ch4 (cat)*fuel_burnt ! emission from fire cell in g/m^2
714 t_chem(p_ch4) = t_chem(p_ch4) + emis ! add to total
715 chem(i,k1,j,p_ch4 )=chem(i,k1,j,p_ch4 ) + emis*conv*imw_ch4 ! add to chem
717 emis=h2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
718 t_chem(p_h2) = t_chem(p_h2) + emis ! add to total
719 chem(i,k1,j,p_h2 )=chem(i,k1,j,p_h2 ) + emis*conv*imw_h2 ! add to chem
721 emis=no (cat)*fuel_burnt ! emission from fire cell in g/m^2
722 t_chem(p_no) = t_chem(p_no) + emis ! add to total
723 chem(i,k1,j,p_no )=chem(i,k1,j,p_no ) + emis*conv*imw_no ! add to chem
725 emis=no2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
726 t_chem(p_no2) = t_chem(p_no2) + emis ! add to total
727 chem(i,k1,j,p_no2 )=chem(i,k1,j,p_no2 ) + emis*conv*imw_no2 ! add to chem
729 emis=so2 (cat)*fuel_burnt ! emission from fire cell in g/m^2
730 t_chem(p_so2) = t_chem(p_so2) + emis ! ads to total
731 chem(i,k1,j,p_so2 )=chem(i,k1,j,p_so2 ) + emis*conv*imw_so2 ! add to chem
733 emis=nh3 (cat)*fuel_burnt ! emission from fire cell in g/m^2
734 t_chem(p_nh3) = t_chem(p_nh3) + emis ! add to total
735 chem(i,k1,j,p_nh3 )=chem(i,k1,j,p_nh3 ) + emis*conv*imw_nh3 ! add to chem
738 !*** other emissions already given in mol/kg
739 ! fuel_burnt kg/m^2 * table mol/kg -> ppmv = 1e6*mol/mol in 1st layer dry air in 1st layer
741 ! same conversion factor but we will not divide by the molecular weight of the compound
742 ! conv = avgw*1e6*mw_air/(rho(i,kds,j)*dz8w(i,kds,j))
744 emis=ald (cat)*fuel_burnt ! emission from fire cell
745 t_chem(p_ald) = t_chem(p_ald) + emis ! add to total
746 chem(i,k1,j,p_ald )=chem(i,k1,j,p_ald )+emis*conv
748 emis=csl (cat)*fuel_burnt ! emission from fire cell
749 t_chem(p_csl) = t_chem(p_csl) + emis ! add to total
750 chem(i,k1,j,p_csl )=chem(i,k1,j,p_csl )+emis*conv
752 emis=eth (cat)*fuel_burnt ! emission from fire cell
753 t_chem(p_eth) = t_chem(p_eth) + emis ! add to total
754 chem(i,k1,j,p_eth )=chem(i,k1,j,p_eth )+emis*conv
756 emis=hc3 (cat)*fuel_burnt ! emission from fire cell
757 t_chem(p_hc3) = t_chem(p_hc3) + emis ! add to total
758 chem(i,k1,j,p_hc3 )=chem(i,k1,j,p_hc3 )+emis*conv
760 emis=hc5 (cat)*fuel_burnt ! emission from fire cell
761 t_chem(p_hc5) = t_chem(p_hc5) + emis ! add to total
762 chem(i,k1,j,p_hc5 )=chem(i,k1,j,p_hc5 )+emis*conv
764 emis=hcho (cat)*fuel_burnt ! emission from fire cell
765 t_chem(p_hcho) = t_chem(p_hcho) + emis ! add to total
766 chem(i,k1,j,p_hcho)=chem(i,k1,j,p_hcho)+emis*conv
768 emis=iso (cat)*fuel_burnt ! emission from fire cell
769 t_chem(p_iso) = t_chem(p_iso) + emis ! add to total
770 chem(i,k1,j,p_iso )=chem(i,k1,j,p_iso )+emis*conv
772 emis=ket (cat)*fuel_burnt ! emission from fire cell
773 t_chem(p_ket) = t_chem(p_ket) + emis ! add to total
774 chem(i,k1,j,p_ket )=chem(i,k1,j,p_ket )+emis*conv
776 emis=mgly (cat)*fuel_burnt ! emission from fire cell
777 t_chem(p_mgly) = t_chem(p_mgly) + emis ! add to total
778 chem(i,k1,j,p_mgly)=chem(i,k1,j,p_mgly)+emis*conv
780 emis=ol2 (cat)*fuel_burnt ! emission from fire cell
781 t_chem(p_ol2) = t_chem(p_ol2) + emis ! add to total
782 chem(i,k1,j,p_ol2 )=chem(i,k1,j,p_ol2 )+emis*conv
784 emis=olt (cat)*fuel_burnt ! emission from fire cell
785 t_chem(p_olt) = t_chem(p_olt) + emis ! add to total
786 chem(i,k1,j,p_olt )=chem(i,k1,j,p_olt )+emis*conv
788 emis=oli (cat)*fuel_burnt ! emission from fire cell
789 t_chem(p_oli) = t_chem(p_oli) + emis ! add to total
790 chem(i,k1,j,p_oli )=chem(i,k1,j,p_oli )+emis*conv
792 emis=ora2 (cat)*fuel_burnt ! emission from fire cell
793 t_chem(p_ora2) = t_chem(p_ora2) + emis ! add to total
794 chem(i,k1,j,p_ora2)=chem(i,k1,j,p_ora2)+emis*conv
796 emis=tol (cat)*fuel_burnt ! emission from fire cell
797 t_chem(p_tol) = t_chem(p_tol) + emis ! add to total
798 chem(i,k1,j,p_tol )=chem(i,k1,j,p_tol )+emis*conv
800 emis=xyl (cat)*fuel_burnt ! emission from fire cell
801 t_chem(p_xyl) = t_chem(p_xyl) + emis ! add to total
802 chem(i,k1,j,p_xyl )=chem(i,k1,j,p_xyl )+emis*conv
804 emis=bigalk (cat)*fuel_burnt ! emission from fire cell
805 t_chem(p_bigalk) = t_chem(p_bigalk) + emis ! add to total
806 chem(i,k1,j,p_bigalk )=chem(i,k1,j,p_bigalk )+emis*conv
808 emis=bigene (cat)*fuel_burnt ! emission from fire cell
809 t_chem(p_bigene) = t_chem(p_bigene) + emis ! add to total
810 chem(i,k1,j,p_bigene )=chem(i,k1,j,p_bigene )+emis*conv
812 emis=c10h16 (cat)*fuel_burnt ! emission from fire cell
813 t_chem(p_c10h16) = t_chem(p_c10h16) + emis ! add to total
814 chem(i,k1,j,p_c10h16 )=chem(i,k1,j,p_c10h16 )+emis*conv
816 emis=c2h4 (cat)*fuel_burnt ! emission from fire cell
817 t_chem(p_c2h4) = t_chem(p_c2h4) + emis ! add to total
818 chem(i,k1,j,p_c2h4 )=chem(i,k1,j,p_c2h4 )+emis*conv
820 emis=c2h5oh (cat)*fuel_burnt ! emission from fire cell
821 t_chem(p_c2h5oh) = t_chem(p_c2h5oh) + emis ! add to total
822 chem(i,k1,j,p_c2h5oh )=chem(i,k1,j,p_c2h5oh )+emis*conv
824 emis=c2h6 (cat)*fuel_burnt ! emission from fire cell
825 t_chem(p_c2h6) = t_chem(p_c2h6) + emis ! add to total
826 chem(i,k1,j,p_c2h6 )=chem(i,k1,j,p_c2h6 )+emis*conv
828 emis=c3h6 (cat)*fuel_burnt ! emission from fire cell
829 t_chem(p_c3h6) = t_chem(p_c3h6) + emis ! add to total
830 chem(i,k1,j,p_c3h6 )=chem(i,k1,j,p_c3h6 )+emis*conv
832 emis=c3h8 (cat)*fuel_burnt ! emission from fire cell
833 t_chem(p_c3h8) = t_chem(p_c3h8) + emis ! add to total
834 chem(i,k1,j,p_c3h8 )=chem(i,k1,j,p_c3h8 )+emis*conv
836 emis=ch3cooh (cat)*fuel_burnt ! emission from fire cell
837 t_chem(p_ch3cooh) = t_chem(p_ch3cooh) + emis ! add to total
838 chem(i,k1,j,p_ch3cooh )=chem(i,k1,j,p_ch3cooh )+emis*conv
840 emis=ch3oh (cat)*fuel_burnt ! emission from fire cell
841 t_chem(p_ch3oh) = t_chem(p_ch3oh) + emis ! add to total
842 chem(i,k1,j,p_ch3oh )=chem(i,k1,j,p_ch3oh )+emis*conv
844 emis=cres (cat)*fuel_burnt ! emission from fire cell
845 t_chem(p_cres) = t_chem(p_cres) + emis ! add to total
846 chem(i,k1,j,p_cres )=chem(i,k1,j,p_cres )+emis*conv
848 emis=glyald (cat)*fuel_burnt ! emission from fire cell
849 t_chem(p_glyald) = t_chem(p_glyald) + emis ! add to total
850 chem(i,k1,j,p_glyald )=chem(i,k1,j,p_glyald )+emis*conv
852 emis=isopr (cat)*fuel_burnt ! emission from fire cell
853 t_chem(p_isopr) = t_chem(p_isopr) + emis ! add to total
854 chem(i,k1,j,p_isopr )=chem(i,k1,j,p_isopr )+emis*conv
856 emis=macr (cat)*fuel_burnt ! emission from fire cell
857 t_chem(p_macr) = t_chem(p_macr) + emis ! add to total
858 chem(i,k1,j,p_macr )=chem(i,k1,j,p_macr )+emis*conv
860 emis=mek (cat)*fuel_burnt ! emission from fire cell
861 t_chem(p_mek) = t_chem(p_mek) + emis ! add to total
862 chem(i,k1,j,p_mek )=chem(i,k1,j,p_mek )+emis*conv
864 emis=mvk (cat)*fuel_burnt ! emission from fire cell
865 t_chem(p_mvk) = t_chem(p_mvk) + emis ! add to total
866 chem(i,k1,j,p_mvk )=chem(i,k1,j,p_mvk )+emis*conv
869 ! fuel_burnt kg/m^2 * table g/kg -> ug/kg dry air in 1st layer
871 ! see also chem/emissions_driver.F line 515
873 conv = avgw*1e6/(rho(i,k1,j)*dz8w(i,k1,j))
875 emis=p25 (cat)*fuel_burnt ! emission from fire cell
876 t_chem(p_p25) = t_chem(p_p25) + emis ! add to total
877 chem(i,k1,j,p_p25 )=chem(i,k1,j,p_p25 )+emis*conv
879 emis=p25i (cat)*fuel_burnt ! emission from fire cell
880 t_chem(p_p25i) = t_chem(p_p25i) + emis ! add to total
881 chem(i,k1,j,p_p25i )=chem(i,k1,j,p_p25i )+emis*conv
883 emis=p25j (cat)*fuel_burnt ! emission from fire cell
884 t_chem(p_p25j) = t_chem(p_p25j) + emis ! add to total
885 chem(i,k1,j,p_p25j )=chem(i,k1,j,p_p25j )+emis*conv
887 emis=oc1 (cat)*fuel_burnt ! emission from fire cell
888 t_chem(p_oc1 ) = t_chem(p_oc1 ) + emis ! add to total
889 chem(i,k1,j,p_oc1 )=chem(i,k1,j,p_oc1 )+emis*conv
891 emis=oc2 (cat)*fuel_burnt ! emission from fire cell
892 t_chem(p_oc2 ) = t_chem(p_oc2 ) + emis ! add to total
893 chem(i,k1,j,p_oc2 )=chem(i,k1,j,p_oc2 )+emis*conv
895 emis=bc1 (cat)*fuel_burnt ! emission from fire cell
896 t_chem(p_bc1 ) = t_chem(p_bc1 ) + emis ! add to total
897 chem(i,k1,j,p_bc1 )=chem(i,k1,j,p_bc1 )+emis*conv
899 emis=bc2 (cat)*fuel_burnt ! emission from fire cell
900 t_chem(p_bc2 ) = t_chem(p_bc2 ) + emis ! add to total
901 chem(i,k1,j,p_bc2 )=chem(i,k1,j,p_bc2 )+emis*conv
903 emis=sulf (cat)*fuel_burnt ! emission from fire cell
904 t_chem(p_sulf ) = t_chem(p_sulf ) + emis ! add to total
905 chem(i,k1,j,p_sulf )=chem(i,k1,j,p_sulf )+emis*conv
907 emis=dms (cat)*fuel_burnt ! emission from fire cell
908 t_chem(p_dms ) = t_chem(p_dms ) + emis ! add to total
909 chem(i,k1,j,p_dms )=chem(i,k1,j,p_dms )+emis*conv
911 emis=msa (cat)*fuel_burnt ! emission from fire cell
912 t_chem(p_msa ) = t_chem(p_msa ) + emis ! add to total
913 chem(i,k1,j,p_msa )=chem(i,k1,j,p_msa )+emis*conv
915 emis=dust_1 (cat)*fuel_burnt ! emission from fire cell
916 t_chem(p_dust_1 ) = t_chem(p_dust_1 ) + emis ! add to total
917 chem(i,k1,j,p_dust_1 )=chem(i,k1,j,p_dust_1 )+emis*conv
919 emis=dust_2 (cat)*fuel_burnt ! emission from fire cell
920 t_chem(p_dust_2 ) = t_chem(p_dust_2 ) + emis ! add to total
921 chem(i,k1,j,p_dust_2 )=chem(i,k1,j,p_dust_2 )+emis*conv
923 emis=dust_3 (cat)*fuel_burnt ! emission from fire cell
924 t_chem(p_dust_3 ) = t_chem(p_dust_3 ) + emis ! add to total
925 chem(i,k1,j,p_dust_3 )=chem(i,k1,j,p_dust_3 )+emis*conv
927 emis=dust_4 (cat)*fuel_burnt ! emission from fire cell
928 t_chem(p_dust_4 ) = t_chem(p_dust_4 ) + emis ! add to total
929 chem(i,k1,j,p_dust_4 )=chem(i,k1,j,p_dust_4 )+emis*conv
931 emis=dust_5 (cat)*fuel_burnt ! emission from fire cell
932 t_chem(p_dust_5 ) = t_chem(p_dust_5 ) + emis ! add to total
933 chem(i,k1,j,p_dust_5 )=chem(i,k1,j,p_dust_5 )+emis*conv
935 emis=seas_1 (cat)*fuel_burnt ! emission from fire cell
936 t_chem(p_seas_1 ) = t_chem(p_seas_1 ) + emis ! add to total
937 chem(i,k1,j,p_seas_1 )=chem(i,k1,j,p_seas_1 )+emis*conv
939 emis=seas_2 (cat)*fuel_burnt ! emission from fire cell
940 t_chem(p_seas_2 ) = t_chem(p_seas_2 ) + emis ! add to total
941 chem(i,k1,j,p_seas_2 )=chem(i,k1,j,p_seas_2 )+emis*conv
943 emis=seas_3 (cat)*fuel_burnt ! emission from fire cell
944 t_chem(p_seas_3 ) = t_chem(p_seas_3 ) + emis ! add to total
945 chem(i,k1,j,p_seas_3 )=chem(i,k1,j,p_seas_3 )+emis*conv
947 emis=seas_4 (cat)*fuel_burnt ! emission from fire cell
948 t_chem(p_seas_4 ) = t_chem(p_seas_4 ) + emis ! add to total
949 chem(i,k1,j,p_seas_4 )=chem(i,k1,j,p_seas_4 )+emis*conv
951 emis=p10 (cat)*fuel_burnt ! emission from fire cell
952 t_chem(p_p10 ) = t_chem(p_p10 ) + emis ! add to total
953 chem(i,k1,j,p_p10 )=chem(i,k1,j,p_p10 )+emis*conv
956 if (num_tracer >0)then
958 ! treat tracers exactly the same as aerosols, emissions g/kg fuel burned, tracer concentration ug/kg dry air
959 conv = avgw*1e6/(rho(i,k1,j)*dz8w(i,k1,j))
961 emis=tr17_1 (cat)*fuel_burnt ! emission from fire cell
962 t_tracer(p_tr17_1) = t_tracer(p_tr17_1) + emis ! add to total
963 tracer(i,k1,j,p_tr17_1 )=tracer(i,k1,j,p_tr17_1 )+emis*conv
965 emis=tr17_2 (cat)*fuel_burnt ! emission from fire cell
966 t_tracer(p_tr17_2) = t_tracer(p_tr17_2) + emis ! add to total
967 tracer(i,k1,j,p_tr17_2 )=tracer(i,k1,j,p_tr17_2 )+emis*conv
969 emis=tr17_3 (cat)*fuel_burnt ! emission from fire cell
970 t_tracer(p_tr17_3) = t_tracer(p_tr17_3) + emis ! add to total
971 tracer(i,k1,j,p_tr17_3 )=tracer(i,k1,j,p_tr17_3 )+emis*conv
973 emis=tr17_4 (cat)*fuel_burnt ! emission from fire cell
974 t_tracer(p_tr17_4) = t_tracer(p_tr17_4) + emis ! add to total
975 tracer(i,k1,j,p_tr17_4 )=tracer(i,k1,j,p_tr17_4 )+emis*conv
977 emis=tr17_5 (cat)*fuel_burnt ! emission from fire cell
978 t_tracer(p_tr17_5) = t_tracer(p_tr17_5) + emis ! add to total
979 tracer(i,k1,j,p_tr17_5 )=tracer(i,k1,j,p_tr17_5 )+emis*conv
981 emis=tr17_6 (cat)*fuel_burnt ! emission from fire cell
982 t_tracer(p_tr17_6) = t_tracer(p_tr17_6) + emis ! add to total
983 tracer(i,k1,j,p_tr17_6 )=tracer(i,k1,j,p_tr17_6 )+emis*conv
985 emis=tr17_7 (cat)*fuel_burnt ! emission from fire cell
986 t_tracer(p_tr17_7) = t_tracer(p_tr17_7) + emis ! add to total
987 tracer(i,k1,j,p_tr17_7 )=tracer(i,k1,j,p_tr17_7 )+emis*conv
989 emis=tr17_8 (cat)*fuel_burnt ! emission from fire cell
990 t_tracer(p_tr17_8) = t_tracer(p_tr17_8) + emis ! add to total
991 tracer(i,k1,j,p_tr17_8 )=tracer(i,k1,j,p_tr17_8 )+emis*conv
999 if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
1000 ! sum ground concentrations and check for nans
1006 k_p=chem_pointers(k)
1008 if(chem(i,k1,j,k_p ).ne.chem(i,k1,j,k_p ))errors=errors+1
1009 a_chem(k_p)=a_chem(k_p)+chem(i,k1,j,k_p )
1013 if(errors>0)call crash('NaN after chem update')
1014 call wrf_dm_sum_reals(a_chem,g_chem)
1015 call message('Layer1 raw sums after adding fire emissions',level=msglevel)
1017 m=min(i+line-1,chem_np)
1018 write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
1019 call message(msg,level=msglevel)
1020 write(msg,81)'Layer1 end',(g_chem(chem_pointers(j)),j=i,m)
1021 call message(msg,level=msglevel)
1022 call message(' ',level=msglevel)
1027 if(fire_print_msg .ge. msglevel .and.printsums .gt. 0)then
1028 call message("Computing totals over all processes",level=msglevel)
1029 ! sum over processes and add to cumulative sums
1032 call wrf_dm_sum_reals(t_fuel,s_fuel)
1034 s_fuel = s_fuel*dx*dy
1037 ! add to cumulative totals
1038 if(size(c_fuel).ne.nfuelcats)call crash('add_fire_emissions: bad size c_fuel')
1039 c_fuel = c_fuel + s_fuel
1042 call wrf_dm_sum_reals(a_chem,g_chem)
1044 call wrf_dm_sum_reals(t_chem,s_chem)
1045 s_chem = s_chem*dx*dy
1047 if(size(c_chem).ne.num_chem)call crash('add_fire_emissions: bad size c_chem')
1048 c_chem = c_chem + s_chem
1050 call message('Total emissions in g or mol per the table',level=msglevel)
1052 m=min(i+line-1,chem_np)
1053 write(msg,80)'Emissions ',(trim(chem_names(j)),j=i,m)
1054 call message(msg,level=msglevel)
1055 write(msg,81)'Cumulative',(c_chem(chem_pointers(j)),j=i,m)
1056 call message(msg,level=msglevel)
1057 write(msg,81)'Rate per s',(r_chem(chem_pointers(j)),j=i,m)
1058 call message(msg,level=msglevel)
1059 call message(' ',level=msglevel)
1063 if(num_tracer >0)then
1064 call message("Computing totals of tracers over all processes",level=msglevel)
1066 call wrf_dm_sum_reals(t_tracer,s_tracer)
1067 s_tracer = s_tracer*dx*dy
1068 r_tracer = s_tracer/dt
1069 if(size(c_tracer).ne.num_tracer)call crash('add_fire_emissions: bad size c_tracer')
1070 c_tracer = c_tracer + s_tracer
1072 call message('Total emissions in g',level=msglevel)
1073 do i=1,tracer_np,line
1074 m=min(i+line-1,tracer_np)
1075 write(msg,80)'Emissions ',(trim(tracer_names(j)),j=i,m)
1076 call message(msg,level=msglevel)
1077 write(msg,81)'Cumulative',(c_tracer(tracer_pointers(j)),j=i,m)
1078 call message(msg,level=msglevel)
1079 write(msg,81)'Rate per s',(r_tracer(tracer_pointers(j)),j=i,m)
1080 call message(msg,level=msglevel)
1081 call message(' ',level=msglevel)
1087 if(c_fuel(cat) > 0.)then
1088 write(msg,83)fuel_name(cat),' burned',c_fuel(cat),'kg, rate',r_fuel(cat),' kg/s'
1089 call message(msg,level=msglevel)
1092 write(msg,83)'Total fuel',' burned',sum(c_fuel),'kg, rate',sum(r_fuel),' kg/s'
1093 call message(msg,level=msglevel)
1098 83 format(a30,a,g14.4,a,g14.4,a,a)
1103 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1104 write(msg,91)ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme
1105 call message(msg,level=0)
1106 write(msg,91)its,ite,jts,jte,ims,ime,jms,jme
1107 call message(msg,level=0)
1108 write(msg,92)'input mesh size:',isz2,jsz2
1109 call message(msg,level=0)
1110 91 format('dimensions: ',8i8)
1111 write(msg,92)'output mesh size:',isz1,jsz1
1112 call message(msg,level=0)
1114 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1115 call crash('add_fire_emissions: bad mesh sizes')
1117 end subroutine add_fire_emissions
1123 subroutine check_pointers(array_name,array,pointer_names,pointers)
1127 character(len=*)::array_name
1128 real, dimension(:,:,:,:)::array
1129 character(len=*), dimension(:)::pointer_names
1130 integer, dimension(:)::pointers
1134 character(len=256)::msg
1137 np=ubound(pointers,1)
1140 993 format(3a,4(1x,i3,':',i3))
1141 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1142 write(msg,993)'array ',array_name,' has dimensions ',&
1143 lbound(array,1),ubound(array,1), &
1144 lbound(array,2),ubound(array,2), &
1145 lbound(array,3),ubound(array,3), &
1146 lbound(array,4),ubound(array,4)
1151 write(msg,'(a,8(1x,a8))')'Species',(trim(pointer_names(j)),j=i,m)
1152 call message(msg,level=msglevel)
1153 write(msg,'(a,8i9)') 'Pointer',(pointers(j),j=i,m)
1154 call message(msg,level=msglevel)
1158 if(maxval(pointers) > ubound(array,4) .or. minval(pointers) < lbound(array,4))then
1159 write(msg,'(3a)')'add_fire_emissions: a ',array_name,' pointer is out of bounds'
1162 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1163 end subroutine check_pointers
1171 SUBROUTINE fire_tendency( &
1172 ids,ide, kds,kde, jds,jde, & ! dimensions
1173 ims,ime, kms,kme, jms,jme, &
1174 its,ite, kts,kte, jts,jte, &
1175 grnhfx,grnqfx,canhfx,canqfx, & ! heat fluxes summed up to atm grid
1176 alfg,alfc,z1can, & ! coeffients, properties, geometry
1177 zs,z_at_w,dz8w,mu,rho, &
1178 rthfrten,rqvfrten) ! theta and Qv tendencies
1180 ! This routine is atmospheric physics
1181 ! it does NOT go into module_fr_sfire_phys because it is not fire physics
1183 ! taken from the code by Ned Patton, only order of arguments change to the convention here
1184 ! --- this routine takes fire generated heat and moisture fluxes and
1185 ! calculates their influence on the theta and water vapor
1186 ! --- note that these tendencies are valid at the Arakawa-A location
1190 ! --- incoming variables
1192 INTEGER , INTENT(in) :: ids,ide, kds,kde, jds,jde, &
1193 ims,ime, kms,kme, jms,jme, &
1194 its,ite, kts,kte, jts,jte
1196 REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: grnhfx,grnqfx ! W/m^2
1197 REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: canhfx,canqfx ! W/m^2
1198 REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: zs ! topography (m abv sealvl)
1199 REAL, INTENT(in), DIMENSION( ims:ime,jms:jme ) :: mu ! dry air mass (Pa)
1201 REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: z_at_w ! m abv sealvl
1202 REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: dz8w ! dz across w-lvl
1203 REAL, INTENT(in), DIMENSION( ims:ime,kms:kme,jms:jme ) :: rho ! density
1205 REAL, INTENT(in) :: alfg ! extinction depth ground fire heat (m)
1206 REAL, INTENT(in) :: alfc ! extinction depth crown fire heat (m)
1207 REAL, INTENT(in) :: z1can ! height of crown fire heat release (m)
1209 ! --- outgoing variables
1211 REAL, INTENT(out), DIMENSION( ims:ime,kms:kme,jms:jme ) :: &
1212 rthfrten, & ! theta tendency from fire (in mass units)
1213 rqvfrten ! Qv tendency from fire (in mass units)
1214 ! --- local variables
1217 INTEGER :: i_st,i_en, j_st,j_en, k_st,k_en
1223 REAL :: fact_g, fact_c
1224 REAL :: alfg_i, alfc_i
1226 REAL, DIMENSION( its:ite,kts:kte,jts:jte ) :: hfx,qfx
1228 !! character(len=128)::msg
1232 do k=kts,min(kte+1,kde)
1241 ! --- set some local constants
1244 cp_i = 1./cp ! inverse of specific heat
1245 xlv_i = 1./xlv ! inverse of latent heat
1249 !!write(msg,'(8e11.3)')cp,cp_i,xlv,xlv_i,alfg,alfc,z1can
1252 call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,grnhfx,'fire_tendency:grnhfx')
1253 call print_2d_stats(its,ite,jts,jte,ims,ime,jms,jme,grnqfx,'fire_tendency:grnqfx')
1255 ! --- set loop indicies : note that
1257 i_st = MAX(its,ids+1)
1258 i_en = MIN(ite,ide-1)
1260 k_en = MIN(kte,kde-1)
1261 j_st = MAX(jts,jds+1)
1262 j_en = MIN(jte,jde-1)
1264 ! --- distribute fluxes
1270 ! --- set z (in meters above ground)
1272 z_w = z_at_w(i,k,j) - zs(i,j) ! should be zero when k=k_st
1276 fact_g = cp_i * EXP( - alfg_i * z_w )
1277 IF ( z_w < z1can ) THEN
1280 fact_c = cp_i * EXP( - alfc_i * (z_w - z1can) )
1282 hfx(i,k,j) = fact_g * grnhfx(i,j) + fact_c * canhfx(i,j)
1284 !! write(msg,2)i,k,j,z_w,grnhfx(i,j),hfx(i,k,j)
1285 !!2 format('hfx:',3i4,6e11.3)
1286 !! call message(msg)
1290 fact_g = xlv_i * EXP( - alfg_i * z_w )
1291 IF (z_w < z1can) THEN
1294 fact_c = xlv_i * EXP( - alfc_i * (z_w - z1can) )
1296 qfx(i,k,j) = fact_g * grnqfx(i,j) + fact_c * canqfx(i,j)
1298 !! if(hfx(i,k,j).ne.0. .or. qfx(i,k,j) .ne. 0.)then
1299 !! write(msg,1)i,k,j,hfx(i,k,j),qfx(i,k,j)
1300 !!1 format('tend:',3i6,2e11.3)
1301 !! call message(msg)
1308 ! --- add flux divergence to tendencies
1310 ! multiply by dry air mass (mu) to eliminate the need to
1311 ! call sr. calculate_phy_tend (in dyn_em/module_em.F)
1313 ! print *,'fire_tendency:',i_st,i_en,j_st,j_en
1318 rho_i = 1./rho(i,k,j)
1320 rthfrten(i,k,j) = - mu(i,j) * rho_i * (hfx(i,k+1,j)-hfx(i,k,j)) / dz8w(i,k,j)
1321 rqvfrten(i,k,j) = - mu(i,j) * rho_i * (qfx(i,k+1,j)-qfx(i,k,j)) / dz8w(i,k,j)
1323 ! print *,i,j,k,rthfrten(i,k,j)
1329 call print_3d_stats(its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme,rthfrten,'fire_tendency:rthfrten')
1330 call print_3d_stats(its,ite,kts,kte,jts,jte,ims,ime,kms,kme,jms,jme,rqvfrten,'fire_tendency:rqvfrten')
1334 END SUBROUTINE fire_tendency
1339 subroutine interpolate_atm2fire(id, & ! for debug output, <= 0 no output
1340 ids,ide, kds,kde, jds,jde, & ! atm grid dimensions
1341 ims,ime, kms,kme, jms,jme, &
1344 ifds, ifde, jfds, jfde, & ! fire grid dimensions
1345 ifms, ifme, jfms, jfme, &
1346 ifps, ifpe, jfps, jfpe, & ! fire patch bounds
1347 ifts,ifte,jfts,jfte, &
1348 ir,jr, & ! atm/fire grid ratio
1349 u_frame, v_frame, & ! velocity frame correction
1350 u,v, & ! atm grid arrays in
1354 uf,vf) ! fire grid arrays out
1357 ! Jan Mandel, October 2010
1358 !*** purpose: interpolate winds and height
1361 integer, intent(in)::id
1362 integer, intent(in):: &
1363 ids,ide, kds,kde, jds,jde, & ! atm domain bounds
1364 ims,ime, kms,kme, jms,jme, & ! atm memory bounds
1366 its,ite,jts,jte, & ! atm tile bounds
1367 ifds, ifde, jfds, jfde, & ! fire domain bounds
1368 ifms, ifme, jfms, jfme, & ! fire memory bounds
1369 ifps, ifpe, jfps, jfpe, & ! fire patch bounds
1370 ifts,ifte,jfts,jfte, & ! fire tile bounds
1371 ir,jr ! atm/fire grid refinement ratio
1372 real, intent(in):: u_frame, v_frame ! velocity frame correction
1373 real,intent(in),dimension(ims:ime,kms:kme,jms:jme)::&
1374 u,v, & ! atm wind velocity, staggered
1375 ph,phb ! geopotential
1376 real,intent(in),dimension(ims:ime,jms:jme)::&
1377 z0, & ! roughness height
1379 real,intent(out),dimension(ims:ime,jms:jme)::&
1380 uah, & ! atm wind at fire_wind_height, diagnostics
1382 real,intent(out), dimension(ifms:ifme,jfms:jfme)::&
1383 uf,vf ! wind velocity fire grid nodes
1387 character(len=256)::msg
1388 #define TDIMS its-2,ite+2,jts-2,jte+2
1389 real, dimension(its-2:ite+2,jts-2:jte+2):: ua,va ! atm winds, interpolated over height, still staggered grid
1390 real, dimension(its-2:ite+2,kds:kde,jts-2:jte+2):: altw,altub,altvb,hgtu,hgtv ! altitudes
1391 integer:: i,j,k,ifts1,ifte1,jfts1,jfte1,ite1,jte1
1392 integer::itst,itet,jtst,jtet,itsu,iteu,jtsu,jteu,itsv,itev,jtsv,jtev
1393 integer::kdmax,its1,jts1,ips1,jps1
1394 integer::itsou,iteou,jtsou,jteou,itsov,iteov,jtsov,jteov
1395 real:: ground,loght,loglast,logz0,logfwh,ht,zr
1398 equivalence (i_nan,r_nan)
1402 ! debug init local arrays
1413 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1414 write(msg,*)'WARNING: bottom index kds=',kds,' should be 1?'
1416 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1423 ! | | nodes in cell (i,j)
1424 ! ------v----- view from top
1430 ! u(ide,jde) x x x u(ide+1,jde)
1432 ! | | p=ph,phb,z0,...
1436 ! staggered values set u(ids:ide+1,jds:jde) v(ids:ide,jds:jde+1)
1437 ! p=ph+phb set at (ids:ide,jds:jde)
1438 ! location of u(i,j) needs p(i-1,j) and p(i,j)
1439 ! location of v(i,j) needs p(i,j-1) and p(i,j)
1440 ! *** NOTE need HALO in ph, phb
1441 ! so we can compute only u(ids+1:ide,jds:jde) v(ids:ide,jds+1,jde)
1442 ! unless we extend p at the boundary
1443 ! but because we care about the fire way in the inside it does not matter
1444 ! if the fire gets close to domain boundary the simulation is over anyway
1446 ite1=snode(ite,ide,1)
1447 jte1=snode(jte,jde,1)
1448 ! do this in any case to check for nans
1449 call print_3d_stats(its,ite1,kds,kde,jts,jte,ims,ime,kms,kme,jms,jme,u,'wind U in')
1450 call print_3d_stats(its,ite,kds,kde,jts,jte1,ims,ime,kms,kme,jms,jme,v,'wind V in')
1452 if(fire_print_msg.gt.0)then
1453 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1454 write(msg,'(a,f7.2,a)')'interpolate_atm2fire: log-interpolation of wind to',fire_wind_height,' m'
1456 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1462 itst=ifval(ids.eq.its,its,its-1)
1463 itet=ifval(ide.eq.ite,ite,ite+1)
1464 jtst=ifval(jds.ge.jts,jts,jts-1)
1465 jtet=ifval(jde.eq.jte,jte,jte+1)
1468 itsu=ifval(ids.eq.its,its+1,its) ! staggered direction
1469 iteu=ifval(ide.eq.ite,ite,ite+1) ! staggered direction
1470 jtsu=ifval(jds.ge.jts,jts,jts-1)
1471 jteu=ifval(jde.eq.jte,jte,jte+1)
1474 jtsv=ifval(jds.eq.jts,jts+1,jts) ! staggered direction
1475 jtev=ifval(jde.eq.jte,jte,jte+1) ! staggered direction
1476 itsv=ifval(ids.ge.its,its,its-1)
1477 itev=ifval(ide.eq.ite,ite,ite+1)
1480 if(fire_print_msg.ge.1)then
1481 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1482 write(msg,7001)'atm input ','tile',its,ite,jts,jte
1484 write(msg,7001)'altw ','tile',itst,itet,jtst,jtet
1486 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1488 7001 format(a,' dimensions ',a4,':',i6,' to ',i6,' by ',i6,' to ',i6)
1490 !**********************************************************
1492 !* find the altitude of the w points *
1494 !**********************************************************
1495 !! in future, replace by z8w & test if the same
1497 kdmax=kde-1 ! max layer to interpolate from, can be less
1502 altw(i,k,j) = (ph(i,k,j)+phb(i,k,j))/g ! altitude of the bottom w-point
1507 ! values at u points
1508 if(fire_print_msg.ge.1)then
1509 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1510 write(msg,7001)'u interp at','tile',itsu,iteu,jtsu,jteu
1512 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1515 !**********************************************************
1517 !* interpolate the altitude from w points to u points *
1519 !**********************************************************
1524 altub(i,k,j)= 0.5*(altw(i-1,k,j)+altw(i,k,j)) ! altitude of the bottom point under u-point
1529 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
1534 ! values at v points
1535 if(fire_print_msg.ge.1)then
1536 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1537 write(msg,7001)'v interp at','tile',itsv,itev,jtsv,jtev
1539 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1542 !**********************************************************
1544 !* interpolate the altitude from w points to v points *
1546 !**********************************************************
1551 altvb(i,k,j)= 0.5*(altw(i,k,j-1)+altw(i,k,j)) ! altitude of the bottom point under v-point
1556 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
1562 call write_array_m3(itsu,iteu,kds,kdmax,jtsu,jteu,its-2,ite+2,kds,kde,jts-2,jte+2,altub,'altub',id)
1563 call write_array_m3(itsv,itev,kds,kdmax,jtsv,jtev,its-2,ite+2,kds,kde,jts-2,jte+2,altvb,'altvb',id)
1564 call write_array_m3(itsu,iteu,kds,kdmax,jtsu,jteu,its-2,ite+2,kds,kde,jts-2,jte+2,hgtu,'hgtu',id)
1565 call write_array_m3(itsv,itev,kds,kdmax,jtsv,jtev,its-2,ite+2,kds,kde,jts-2,jte+2,hgtv,'hgtv',id)
1568 logfwh = log(fire_wind_height)
1570 !**********************************************************
1572 !* interpolate u vertically to fire_wind_height *
1574 !**********************************************************
1576 ! interpolate u, staggered in X
1578 do j = jtsu,jteu ! compute on domain by 1 smaller, otherwise z0 and ph not available
1579 do i = itsu,iteu ! compute with halo 2
1580 zr = 0.5*(z0(i,j)+z0(i-1,j)) ! interpolated roughness length under this u point
1581 if(fire_wind_height > zr)then !
1583 ht = hgtu(i,k,j) ! height of this u point above the ground
1584 if( .not. ht < fire_wind_height) then ! found layer k this point is in
1586 if(k.eq.kds)then ! first layer, log linear interpolation from 0 at zr
1588 ua(i,j)= u(i,k,j)*(logfwh-logz0)/(loght-logz0)
1589 else ! log linear interpolation
1590 loglast=log(hgtu(i,k-1,j))
1591 ua(i,j)= u(i,k-1,j) + (u(i,k,j) - u(i,k-1,j)) * ( logfwh - loglast) / (loght - loglast)
1595 if(k.eq.kdmax)then ! last layer, still not high enough
1600 else ! roughness higher than the fire wind height
1607 !**********************************************************
1609 !* interpolate v vertically to fire_wind_height *
1611 !**********************************************************
1613 ! interpolate v, staggered in Y
1617 zr = 0.5*(z0(i,j-1)+z0(i,j)) ! roughness length under this v point
1618 if(fire_wind_height > zr)then !
1620 ht = hgtv(i,k,j) ! height of this u point above the ground
1621 if( .not. ht < fire_wind_height) then ! found layer k this point is in
1623 if(k.eq.kds)then ! first layer, log linear interpolation from 0 at zr
1625 va(i,j)= v(i,k,j)*(logfwh-logz0)/(loght-logz0)
1626 else ! log linear interpolation
1627 loglast=log(hgtv(i,k-1,j))
1628 va(i,j)= v(i,k-1,j) + (v(i,k,j) - v(i,k-1,j)) * ( logfwh - loglast) / (loght - loglast)
1632 if(k.eq.kdmax)then ! last layer, still not high enough
1637 else ! roughness higher than the fire wind height
1644 ! store the output for diagnostics
1652 call write_array_m(its,ite1,jts,jte,ims,ime,jms,jme,uah,'uah_n',id) ! no reflection
1653 call write_array_m(its,ite,jts,jte1,ims,ime,jms,jme,vah,'vah_n',id)
1656 !**********************************************************
1658 !* interpolate ua,va vertically to the fire mesh *
1660 !**********************************************************
1663 ips1 = ifval(ips.eq.ids,ips+1,ips)
1664 call continue_at_boundary(1,1,0., & ! x direction
1665 TDIMS, &! memory dims atm grid tile
1666 ids+1,ide,jds,jde, & ! domain dims - where u defined
1667 ips1,ipe,jps,jpe, & ! patch dims
1668 itsu,iteu,jtsu,jteu, & ! tile dims - in nonextended direction one beyond if at patch boundary but not domain
1669 itsou,iteou,jtsou,jteou, & ! out, where set
1672 jps1 = ifval(jps.eq.jds,jps+1,jps)
1673 call continue_at_boundary(1,1,0., & ! y direction
1674 TDIMS, & ! memory dims atm grid tile
1675 ids,ide,jds+1,jde, & ! domain dims - where v wind defined
1676 ips,ipe,jps1,jpe, & ! patch dims
1677 itsv,itev,jtsv,jtev, & ! tile dims
1678 itsov,iteov,jtsov,jteov, & ! where set
1681 ! store the output for diagnostics
1690 call write_array_m(itsou,iteou,jtsou,jteou,TDIMS,ua,'ua',id)
1691 call write_array_m(itsov,iteov,jtsov,jteov,TDIMS,va,'va',id)
1694 !$OMP CRITICAL(SFIRE_DRIVER_CRIT)
1695 ! don't have all values valid, don't check
1696 write(msg,12)'atm mesh wind U at',fire_wind_height,' m'
1697 call print_2d_stats(itsou,iteou,jtsou,jteou,TDIMS,ua,msg)
1698 write(msg,12)'atm mesh wind V at',fire_wind_height,' m'
1699 call print_2d_stats(itsov,iteov,jtsov,jteov,TDIMS,va,msg)
1701 call print_2d_stats(its,ite1,jts,jte,ims,ime,jms,jme,uah,'UAH')
1702 call print_2d_stats(its,ite,jts,jte1,ims,ime,jms,jme,vah,'VAH')
1703 !call write_array_m(its,ite1,jts,jte,ims,ime,jms,jme,uah,'uah',id)
1704 !call write_array_m(its,ite,jts,jte1,ims,ime,jms,jme,vah,'vah',id)
1705 !$OMP END CRITICAL(SFIRE_DRIVER_CRIT)
1708 ! | F | F | F | F | Example of atmospheric and fire grid with
1709 ! |-------|-------| ir=jr=4.
1710 ! | F | F | F | F | Winds are given at the midpoints of the sides of the atmosphere grid,
1711 ! ua------z-------| interpolated to midpoints of the cells of the fine fire grid F.
1712 ! | F | F | F | F | This is (1,1) cell of atmosphere grid, and [*] is the (1,1) cell of the fire grid.
1713 ! |---------------| ua(1,1) <--> uf(0.5,2.5)
1714 ! | * | F | F | F | va(1,1) <--> vf(2.5,0.5)
1715 ! -------va------ za(1,1) <--> zf(2.5,2.5)
1718 ! | --------va(1,2)---------
1719 ! | | | | Example of atmospheric and fire grid with
1721 ! | | za,zf | Winds are given at the midpoints of the sides of the atmosphere grid,
1722 ! | ua(1,1)----uf,vf-----ua(2,1) interpolated to midpoints of the cells of the (the same) fire grid
1723 ! | | (1,1) | ua(1,1) <--> uf(0.5,1)
1724 ! | | | | va(1,1) <--> vf(1,0.5)
1725 ! | | | | za(1,1) <--> zf(1,1)
1726 ! | --------va(1,1)---------
1727 ! |--------------------> x1
1729 ! Meshes are aligned by the lower left cell of the domain. Then in the above figure
1730 ! u = node with the ua component of the wind at (ids,jds), midpoint of side
1731 ! v = node with the va component of the wind at (ids,jds), midpoint of side
1732 ! * = fire grid node at (ifds,jfds)
1733 ! z = node with height, midpoint of cell
1735 ! ua(ids,jds)=uf(ifds-0.5,jfds+jr*0.5-0.5) = uf(ifds-0.5,jfds+(jr-1)*0.5)
1736 ! va(ids,jds)=vf(ifds+ir*0.5-0.5,jfds-0.5) = vf(ifds+(ir-1)*0.5,jfds-0.5)
1737 ! 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)
1739 ! ifts1=max(snode(ifts,ifps,-1),ifds) ! go 1 beyond patch boundary but not at domain boundary
1740 ! ifte1=min(snode(ifte,ifpe,+1),ifde)
1741 ! jfts1=max(snode(jfts,jfps,-1),jfds)
1742 ! jfte1=min(snode(jfte,jfpe,+1),jfde)
1744 call interpolate_2d( &
1745 TDIMS, & ! memory dims atm grid tile
1746 itsou,iteou,jtsou,jteou,& ! where set
1747 ifms,ifme,jfms,jfme, & ! array dims fire grid
1748 ifts,ifte,jfts,jfte,& ! dimensions on the fire grid to interpolate to
1749 ir,jr, & ! refinement ratio
1750 real(ids),real(jds),ifds-0.5,jfds+(jr-1)*0.5, & ! line up by lower left corner of domain
1754 call interpolate_2d( &
1755 TDIMS, & ! memory dims atm grid tile
1756 itsov,iteov,jtsov,jteov,& ! where set
1757 ifms,ifme,jfms,jfme, & ! array dims fire grid
1758 ifts,ifte,jfts,jfte,& ! dimensions on the fire grid to interpolate to
1759 ir,jr, & ! refinement ratio
1760 real(ids),real(jds),ifds+(ir-1)*0.5,jfds-0.5, & ! line up by lower left corner of domain
1764 call print_2d_stats_vec(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,uf,vf,'fire wind (m/s)')
1765 ! call print_2d_stats_vec(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,uf,vf,'fire wind extended')
1767 call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,uf,'uf1',id)
1768 call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,vf,'vf1',id)
1769 ! call write_array_m(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,uf,'uf1',id)
1770 ! call write_array_m(ifts1,ifte1,jfts1,jfte1,ifms,ifme,jfms,jfme,vf,'vf1',id)
1775 end subroutine interpolate_atm2fire
1777 subroutine apply_windrf( &
1778 ifms,ifme,jfms,jfme, &
1779 ifts,ifte,jfts,jfte, &
1782 ifms, ifme, jfms, jfme, & ! fire memory bounds
1783 ifts, ifte, jfts, jfte ! fire tile bounds
1784 real,intent(in),dimension(ifms:ifme,jfms:jfme)::nfuel_cat
1785 real,intent(inout),dimension(ifms:ifme,jfms:jfme)::uf,vf
1792 k=int( nfuel_cat(i,j) )
1793 if(k.lt.no_fuel_cat)then
1794 uf(i,j)=uf(i,j)*windrf(k)
1795 vf(i,j)=vf(i,j)*windrf(k)
1803 end subroutine apply_windrf
1809 subroutine setup_wind_log_interpolation( &
1810 ids,ide, jds,jde, & ! atm grid dimensions
1814 ifds, ifde, jfds, jfde, & ! fire grid dimensions
1815 ifms, ifme, jfms, jfme, &
1816 ifts, ifte, jfts, jfte, &
1817 ir,jr, & ! atm/fire grid ratio
1818 z0, & ! atm grid arrays in
1819 nfuel_cat, & ! fire array in
1820 fz0,fwh) ! fire arrays out
1822 integer, intent(in):: &
1823 ids,ide, jds,jde, & ! atm domain bounds
1824 ims,ime, jms,jme, & ! atm memory bounds
1826 its,ite,jts,jte, & ! atm tile bounds
1827 ifds, ifde, jfds, jfde, & ! fire domain bounds
1828 ifms, ifme, jfms, jfme, & ! fire memory bounds
1829 ifts, ifte, jfts, jfte, & ! fire tile bounds
1830 ir,jr ! atm/fire grid refinement ratio
1831 real,intent(in),dimension(ims:ime,jms:jme)::z0 ! landuse roughness length
1832 real,intent(in),dimension(ifms:ifme,jfms:jfme)::nfuel_cat ! fuel category
1833 real,intent(out),dimension(ifms:ifme,jfms:jfme)::&
1834 fz0, & ! roughness height
1835 fwh ! height to read the wind from
1837 integer::i,j,ii,jj,k,id=0
1838 character(len=128)::msg
1842 if(.not.have_fuel_cats)call crash('setup_wind_log_interpolation: fuel categories not yet set')
1844 select case(fire_wind_log_interp)
1847 call message('fire_wind_log_interp=1: log interpolation on fire mesh, roughness and wind height from fuel categories')
1850 k = int(nfuel_cat(i,j))
1851 if(k.ge.no_fuel_cat.and.k.le.no_fuel_cat2)then ! no fuel
1854 elseif(k < 1 .or. k > nfuelcats) then
1855 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1856 write(msg,*)'i,j,nfuel_cat,nfuelcats=',i,j,k,nfuelcats
1857 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1859 call crash('setup_wind_log_interpolation: fuel category out of bounds')
1868 call message('fire_wind_log_interp=2: log interpolation on fire mesh' // &
1869 'piecewise constant roughness from landuse, constant fire_wind_height')
1872 do jj=(j-1)*jr+1,(j-1)*jr+jr
1873 do ii=(i-1)*ir+1,(i-1)*ir+ir
1881 k = int(nfuel_cat(i,j))
1882 if(k.lt.no_fuel_cat)then ! no fuel, interpolation does not matter
1892 call message('fire_wind_log_interp=3: log interpolation on fire mesh,' // &
1893 ' interpolated roughness from landuse, constant fire_wind_height')
1894 call interpolate_z2fire(id,1, & ! for debug output, <= 0 no output
1895 ids,ide, jds,jde, & ! atm grid dimensions
1899 ifds, ifde, jfds, jfde, & ! fire grid dimensions
1900 ifms, ifme, jfms, jfme, &
1901 ifts,ifte,jfts,jfte, &
1902 ir,jr, & ! atm/fire grid ratio
1903 z0, & ! atm grid arrays in
1904 fz0) ! fire grid arrays out
1907 k = int(nfuel_cat(i,j))
1908 if(k.ne.no_fuel_cat)then ! no fuel, interpolation does not matter
1918 call message('fire_wind_log_interp=4: log interpolation on atmospheric' // &
1919 ' mesh, roughness from landuse, constant fire_wind_height')
1923 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1924 write(msg,*)'setup_wind_log_interpolation: invalid fire_wind_log_interp=',fire_wind_log_interp
1925 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1930 select case(fire_use_windrf)
1933 call message('setup_wind_log_interpolation: not using wind reduction factors')
1936 call message('setup_wind_log_interpolation: multiplying wind by reduction factors')
1939 call message('setup_wind_log_interpolation: resetting wind interpolation height from wind reduction factors')
1942 k = int(nfuel_cat(i,j))
1943 if(k.ne.no_fuel_cat)then
1944 fwh(i,j) = fz0(i,j) ** (1.-windrf(k)) * fire_wind_height ** windrf(k) ! GMD paper eq. (26)
1946 if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
1947 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1948 write(msg,*)'category ',k,'windrf=',windrf(k),' fire_wind_height=',fire_wind_height
1949 call message(msg,level=-1)
1950 write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
1951 call message(msg,level=-1)
1952 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1953 call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
1961 if(fire_wind_log_interp.eq.2.or.fire_wind_log_interp.eq.3)then
1962 call message('setup_wind_log_interpolation: adjusting wind interpolation height for LANDUSE roughness height')
1965 k = int(nfuel_cat(i,j))
1966 if(k.lt.no_fuel_cat)then
1967 r = log(fcwh(k)/fcz0(k))/log(fire_wind_height/fcz0(k))! GMD paper eq. (25)
1968 fwh(i,j) = fz0(i,j) ** (1.-r) * fire_wind_height ** r ! GMD paper eq. (26)
1970 if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
1971 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1972 write(msg,*)'category ',k, 'roughness ',fcz0(k),' midflame height ',fcwh(k),' fire_wind_height=',fire_wind_height
1973 call message(msg,level=-1)
1974 write(msg,*)'computed wind reduction factor ',r
1975 call message(msg,level=-1)
1976 write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
1977 call message(msg,level=-1)
1978 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
1979 call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
1986 call message('setup_wind_log_interpolation: not using wind reduction factors')
1990 !$OMP CRITICAL(SFIRE_ATM_CRIT)
1991 write(msg,*)'setup_wind_log_interpolation: invalid fire_use_windrf=',fire_use_windrf
1992 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
2000 k = int(nfuel_cat(i,j))
2001 if(k.lt.no_fuel_cat)then
2002 if (.not. fz0(i,j) > 0. .or. .not. fwh(i,j) > fz0(i,j))then
2003 !$OMP CRITICAL(SFIRE_ATM_CRIT)
2004 write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
2005 call message(msg,level=-1)
2006 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
2007 call crash('setup_wind_log_interpolation: must have fwh > fz0 > 0')
2010 if(.not.fwh(i,j)<0.)then
2011 !$OMP CRITICAL(SFIRE_ATM_CRIT)
2012 write(msg,*)'i=',i,' j=',j,' fz0(i,j)=',fz0(i,j),' fwh(i,j)=',fwh(i,j)
2013 call message(msg,level=-1)
2014 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
2015 call crash('setup_wind_log_interpolation: no fuel must be signalled by fwh<0')
2021 have_wind_log_interpolation = .true.
2023 call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fz0,'setup_wind_log:fz0')
2024 call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,fz0,'setup_wind_log:fwh')
2026 end subroutine setup_wind_log_interpolation
2032 subroutine interpolate_wind2fire_height(id, & ! to identify debugging prints and files if needed
2033 ids,ide, kds,kde, jds,jde, & ! atm grid dimensions
2034 ims,ime, kms,kme, jms,jme, &
2037 ifds, ifde, jfds, jfde, & ! fire grid dimensions
2038 ifms, ifme, jfms, jfme, &
2039 ifps, ifpe, jfps, jfpe, & ! fire patch bounds
2040 ifts,ifte,jfts,jfte, &
2041 ir,jr, & ! atm/fire grid ratio
2042 u_frame, v_frame, & ! velocity frame correction
2043 u,v,ph,phb, & ! input atmospheric arrays
2044 fz0,fwh, & ! input fire arrays
2045 uf,vf) ! output fire arrays
2049 integer, intent(in):: id, & ! debug identification
2050 ids,ide, kds,kde, jds,jde, & ! atm domain bounds
2051 ims,ime, kms,kme, jms,jme, & ! atm memory bounds
2053 its,ite,jts,jte, & ! atm tile bounds
2054 ifds, ifde, jfds, jfde, & ! fire domain bounds
2055 ifms, ifme, jfms, jfme, & ! fire memory bounds
2056 ifps, ifpe, jfps, jfpe, & ! fire patch bounds
2057 ifts,ifte,jfts,jfte, & ! fire tile bounds
2058 ir,jr ! atm/fire grid refinement ratio
2059 real, intent(in):: u_frame, v_frame ! velocity frame correction
2060 real,intent(in),dimension(ims:ime,kms:kme,jms:jme)::&
2061 u,v, & ! atm wind velocity, staggered
2062 ph,phb ! geopotential
2063 real,intent(in),dimension(ifms:ifme,jfms:jfme)::&
2064 fz0, & ! roughness height
2065 fwh ! height to read the wind from
2066 real,intent(out),dimension(ifms:ifme,jfms:jfme)::&
2067 uf, & ! atm wind at fire_wind_height, diagnostics
2071 integer:: i,j,k,jcb,jcm,icb,icm,kdmax,kmin,kmax
2072 integer::itst,itet,jtst,jtet
2073 integer::iftst,iftet,jftst,jftet
2074 real:: wjcb,wjcm,wicb,wicm,ht,i_g,loght,zr,ht_last,logwh,wh,loght_last,uk,vk,uk1,vk1,z0,logz0
2075 real, dimension (its-1:ite+1,kds:kde,jts-1:jte+1):: z
2076 character(len=128)::msg
2080 if(.not. have_wind_log_interpolation) call crash('interpolate_wind2fire_height: wind_log_interpolation must be set up first')
2082 ! print *,'interpolate_wind2fire_height start, id=',id
2084 kdmax=kde-1 ! max layer to use
2086 ! find the altitude of atm cell centers
2088 ! index bounds for cell centers - need to go one beyond if at end of tile but not domain
2089 itst=ifval(ids.eq.its,its,its-1)
2090 itet=ifval(ide.eq.ite,ite,ite+1)
2091 jtst=ifval(jds.ge.jts,jts,jts-1)
2092 jtet=ifval(jde.eq.jte,jte,jte+1)
2094 ! print *,'its, ite, jts, jte =',its, ite, jts, jte
2095 ! print *,'itst, itet, jtst, jtet=',itst, itet, jtst, jtet
2102 z(i,k,j) = (ph(i,k,j)+phb(i,k,j))*i_g ! altitude of the bottom w-point
2104 ! print *,'i,k,j=',i,k,j,'ph, phb, z=',ph(i,k,j),phb(i,k,j),z(i,k,j)
2110 z(i,k,j) = (z(i,k,j)+z(i,k+1,j))*0.5 - z(i,kds,j) ! height of the cell center
2115 ! index bounds for fire mesh cell centers
2116 ! to prevent setting values from uninitialized memory
2117 iftst=ifval(ifds.eq.ifts,ifts+ir/2,ifts)
2118 iftet=ifval(ifde.eq.ifte,ifte-ir/2,ifte)
2119 jftst=ifval(jfds.ge.jfts,jfts+jr/2,jfts)
2120 jftet=ifval(jfde.eq.jfte,jfte-jr/2,jfte)
2122 ! print *,'iftst, iftet, jftst, jftet=',iftst, iftet, jftst, jftet
2124 ! zero out first, to prevent unitialized values on strips along domain boundaries
2125 ! it would be faster but longer code to do just cleanup loop on the strips
2133 ! vertical and horizontal interpolation
2135 kmin=kde ! init stats
2138 loop_j: do j = jftst,jftet
2139 call coarse(j,jr,-2,jcb,wjcb) ! get interpolation coefficients from the boundary
2140 call coarse(j,jr,ir,jcm,wjcm) ! get interpolation coefficients from the midpoint
2141 loop_i: do i = iftst,iftet
2142 call coarse(i,ir,-2,icb,wicb) ! get interpolation coefficients from the boundary
2143 call coarse(i,ir,ir,icm,wicm) ! get interpolation coefficients from the midpoint
2144 z0 = fz0(i,j) ! roughness length
2145 wh = fwh(i,j) ! wind height
2147 ! print *,'i=',i,' j=',j,' icb=',icb,' jcb=',jcb,' z0=',z0,' wh=',wh
2150 if( wh > z0 .and. z0 > 0)then
2152 ht_last=z0 ! initialize starting height of this layer
2153 loop_k: do k=kds,kdmax ! search for layer k such that ht(k-1)<=wh<ht(k), ht(0)=z0
2154 ! interpolate height from atmospheric cell midpoints
2155 ht=interpolate_h(its-1,ite+1,kds,kde,jts-1,jts+1,icm,k,jcm,wicm,wjcm,z)
2157 ! print *,'i=',i,' j=',j,'k=',k,' ht=',ht
2159 if(.not. ht < wh) exit loop_k ! found layer k this point is in
2162 if(k .gt. kdmax) then
2163 goto 91 ! run out of vertical levels, this must be wrong
2167 ! found layer k, ht_last < wh <= ht
2170 loght_last = log(ht_last)
2173 ! interpolate u at level k from staggered coarse grid: boundary in i, midpoints in j
2174 uk=interpolate_h(ims,ime,kms,kme,jms,jme,icb,k,jcm,wicb,wjcm,u) - u_frame
2176 ! print *,'i=',i,' j=',j,' uk=',uk
2178 ! interpolate v at level k from staggered coarse grid: midpoints in i, boundary in j
2179 vk=interpolate_h(ims,ime,kms,kme,jms,jme,icm,k,jcb,wicm,wjcb,v) - v_frame
2181 ! print *,'i=',i,' j=',j,' vk=',vk
2183 if(k.gt.kds)then ! interpolate u,v horizontaly at the previous layer, k-1
2184 ! interpolate u at level k-1 from staggered coarse grid: boundary in i, midpoints in j
2185 uk1=interpolate_h(ims,ime,kms,kme,jms,jme,icb,k-1,jcm,wicb,wjcm,u)
2187 ! print *,'i=',i,' j=',j,' uk1=',uk1
2189 ! interpolate v at level k-1 from staggered coarse grid: midpoints in i, boundary in j
2190 vk1=interpolate_h(ims,ime,kms,kme,jms,jme,icm,k-1,jcb,wicm,wjcb,v)
2192 ! print *,'i=',i,' j=',j,' uk1=',uk1
2194 else ! there is no previous layer, wind at roughness is assumed 0
2199 ! log interpolate the wind to wh
2200 uf(i,j)= uk1 + (uk - uk1) * ( logwh - loght_last) / (loght - loght_last)
2201 vf(i,j)= vk1 + (vk - vk1) * ( logwh - loght_last) / (loght - loght_last)
2203 ! print *,'i=',i,' j=',j,' uk=',uk,' vk=',vk,' uk1=',uk1,' vk1=',vk1,' uf=',uf(i,j),' vf=',vf(i,j)
2215 ! print *,'interpolate_wind2fire_height complete, id=',id
2217 !$OMP CRITICAL(SFIRE_ATM_CRIT)
2218 write(msg,*)'wind interpolated from layers',kmin,' to ',kmax
2220 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
2224 91 call crash('interpolate_wind2fire_height: fire wind height too large, increase kdmax or atm height')
2226 !$OMP CRITICAL(SFIRE_ATM_CRIT)
2227 write(msg,*)'fz0(',i,j,')=',fz0(i,j),'fwh(',i,j,')=',fwh(i,j)
2229 !$OMP END CRITICAL(SFIRE_ATM_CRIT)
2230 call crash('interpolate_wind2fire_height: must have fire wind height > roughness height > 0')
2234 real function interpolate_h(ims,ime,kms,kme,jms,jme,ic,kc,jc,wic,wjc,a)
2235 !*** purpose: bilinear interpolation from a(ic:ic+1,k,jc:jc+1) with weights wicm wjcm
2238 integer, intent(in)::ims,ime,jms,kms,kme,jme,ic,kc,jc
2239 real, intent(in)::wic,wjc,a(ims:ime,kms:kme,jms:jme)
2242 a(ic,kc,jc) *wic *wjc + &
2243 a(ic,kc,jc+1) *wic *(1.-wjc) + &
2244 a(ic+1,kc,jc) *(1.-wic)*wjc + &
2245 a(ic+1,kc,jc+1)*(1.-wic)*(1.-wjc)
2246 end function interpolate_h
2249 subroutine coarse(ix,nr,ia,ic,w)
2250 !*** find coarse mesh index and interpolation weight
2253 integer, intent(in)::ix,nr,ia
2254 integer, intent(out)::ic
2255 real, intent(out)::w
2257 ! given fine mesh with nr cells for each coarse mesh cell and such that
2258 ! coarse mesh node 1 is aligned with the fine mesh at (na+1)/2
2259 ! for fine mesh node ix find its coarse mesh coordinate c and return
2260 ! ic=floor(c), the index of the nearest coarse mesh node below
2261 ! w =1-(c-ic), the interpolation weight from coarse mesh node ic to fine mesh node ix
2264 ! fine mesh nodes are always at the middle of their cells
2266 ! the alignment when the coarse nodes are on the boundary of coarse cells:
2267 ! |---1---|---2---|.......|--nr---| fine mesh
2268 ! 1-------------------------------2 coarse mesh
2269 ! ia = -2 because coarse node 1 is aligned with the fine mesh at -1/2 = (-2 + 1)/2
2271 ! the alignment when the coarse node is at the midpoint of coarse cell:
2272 ! |---1---|---2---|---3---|---4---| fine mesh, here nr=4
2273 ! |---------------1---------------| coarse mesh
2274 ! ia = nr because coarse node 1 is aligned with the fine mesh at (nr + 1)/2
2275 ! here, (4 + 1)/2 = 2.5
2283 a = (ia + 1)*0.5 ! the location on the fine grid where coarse node 1 is aligned
2284 c = 1 + (ix - a)/nr ! coarse mesh coordinate of ix
2285 ic= floor(c) ! nearest coarse node to the left
2286 w = (1 + ic) - c ! interpolation weight, 1-(c-ic)
2288 end subroutine coarse
2290 end subroutine interpolate_wind2fire_height
2292 end module module_fr_sfire_atm