!
module module_fr_fire_phys 3
use module_model_constants
, only: cp,xlv
use module_fr_fire_util
PRIVATE
! subroutines and functions
PUBLIC:: init_fuel_cats,fire_ros,heat_fluxes,set_nfuel_cat,set_fire_params,write_fuels_m
PUBLIC::fire_params
! arrays passed to fire_ros
type fire_params
real,pointer,dimension(:,:):: vx,vy ! wind velocity (m/s)
real,pointer,dimension(:,:):: zsf ! terrain height (m)
real,pointer,dimension(:,:):: dzdxf,dzdyf ! terrain grad (1)
real,pointer,dimension(:,:):: bbb,betafl,phiwc,r_0 ! spread formula coefficients
real,pointer,dimension(:,:):: fgip ! init mass of surface fuel (kg/m^2)
real,pointer,dimension(:,:):: ischap ! if fuel is chaparral and want rate of spread treated differently
end type fire_params
! use as
! type(fire_params)::fp
!D in col 2 means quantity derived from the others
!
! Scalar constants (data same for all fuel categories):
! HFGL SURFACE FIRE HEAT FLUX THRESHOLD TO IGNITE CANOPY (W/m^2)
! CMBCNST JOULES PER KG OF DRY FUEL
! FUELHEAT FUEL PARTICLE LOW HEAT CONTENT, BTU/LB
! FUELMC_G FUEL PARTICLE (SURFACE) MOISTURE CONTENT
!D BMST RATIO OF LATENT TO SENSIBLE HEAT FROM SFC BURN:
! % of total fuel mass that is water (not quite
! = % fuel moisture). BMST= (H20)/(H20+DRY)
! so BMST = FUELMC_G / (1 + FUELMC_G) where
! FUELMC_G = moisture content of surface fuel
!
! Data arrays indexed by fuel category:
! FGI INITIAL TOTAL MASS OF SURFACE FUEL (KG/M**2)
! FUELDEPTHM FUEL DEPTH, IN M (CONVERTED TO FT)
! SAVR FUEL PARTICLE SURFACE-AREA-TO-VOLUME RATIO, 1/FT
! GRASS: 3500., 10 hr fuel: 109., 100 hr fuel: 30.
! FUELMCE MOISTURE CONTENT OF EXTINCTION; 0.30 FOR MANY DEAD FUELS; 0.15 FOR GRASS
! FUELDENS OVENDRY PARTICLE DENSITY, LB/FT^3
! ST FUEL PARTICLE TOTAL MINERAL CONTENT
! SE FUEL PARTICLE EFFECTIVE MINERAL CONTENT
! WEIGHT WEIGHTING PARAMETER THAT DETERMINES THE SLOPE OF THE MASS LOSS CURVE
! RANGES FROM ~5 (FAST BURNUP) TO 1000 ( ~40% DECR OVER 10 MIN).
! FCI_D INITIAL DRY MASS OF CANOPY FUEL
! FCT BURN OUT TIME FOR CANOPY FUEL, AFTER DRY (S)
! ichap Set=1 if fuel is chaparral and want the rate of spread treated differently, 0 if not
!D FCI INITIAL TOTAL MASS OF CANOPY FUEL
!D FCBR FUEL CANOPY BURN RATE (KG/M**2/S)
! =============================================================================
! Anderson 13 surface fire fuel models, along with some
! estimated canopy properties (for crown fire).
! =============================================================================
! --- Grass-dominated fuel models
! FUEL MODEL 1: Short grass (1 ft)
! FUEL MODEL 2: Timber (grass and understory)
! FUEL MODEL 3: Tall grass (2.5 ft)
! --- Shrub-dominated fuel models
! FUEL MODEL 4: Chaparral (6 ft)
! FUEL MODEL 5: Brush (2 ft)
! FUEL MODEL 6: Dormant brush, hardwood slash
! FUEL MODEL 7: Southern rough
! --- Forest litter-dominated fuel models
! FUEL MODEL 8: Closed timber litter
! FUEL MODEL 9: Hardwood litter
! FUEL MODEL 10: Timber (litter + understory)
! --- Logging debris-dominated fuel models
! FUEL MODEL 11: Light logging slash
! FUEL MODEL 12: Medium logging slash
! FUEL MODEL 13: Heavy logging slash
! --- Fuel-free
! FUEL MODEL 14: no fuel
! scalar fuel coefficients
REAL, SAVE:: cmbcnst,hfgl,fuelmc_g,fuelmc_c
! computed values
REAL, SAVE:: bmst,fuelheat
! defaults, may be changed in init_fuel_cats
DATA cmbcnst / 17.433e+06/ ! J/kg dry fuel
DATA hfgl / 17.e4 / ! W/m^2
DATA fuelmc_g / 0.08 / ! set = 0 for dry surface fuel
DATA fuelmc_c / 1.00 / ! set = 0 for dry canopy
! REAL, PARAMETER :: bmst = fuelmc_g/(1+fuelmc_g)
! REAL, PARAMETER :: fuelheat = cmbcnst * 4.30e-04 ! convert J/kg to BTU/lb
! real, parameter :: xlv = 2.5e6 ! to make it selfcontained
! real, parameter :: cp = 7.*287./2 ! to make it selfcontained
! fuel categorytables
INTEGER, PARAMETER :: nf=14 ! number of fuel categories in data stmts
INTEGER, SAVE :: nfuelcats = 13 ! number of fuel categories that are specified
INTEGER, PARAMETER :: mfuelcats = 30 ! allowable number of fuel categories
INTEGER, PARAMETER :: zf = mfuelcats-nf ! number of zero fillers in data stmt
INTEGER, SAVE :: no_fuel_cat = 14 ! special category outside of 1:nfuelcats
CHARACTER (len=80), DIMENSION(mfuelcats ), save :: fuel_name
INTEGER, DIMENSION( mfuelcats ), save :: ichap
REAL , DIMENSION( mfuelcats ), save :: windrf,weight,fgi,fci,fci_d,fct,fcbr, &
fueldepthm,fueldens,fuelmce, &
savr,st,se
DATA windrf /0.36, 0.36, 0.44, 0.55, 0.42, 0.44, 0.44, &
0.36, 0.36, 0.36, 0.36, 0.43, 0.46, 1e-7, zf*0 /
DATA fgi / 0.166, 0.896, 0.674, 3.591, 0.784, 1.344, 1.091, &
1.120, 0.780, 2.692, 2.582, 7.749, 13.024, 1.e-7, zf*0. /
DATA fueldepthm /0.305, 0.305, 0.762, 1.829, 0.61, 0.762,0.762, &
0.0610, 0.0610, 0.305, 0.305, 0.701, 0.914, 0.305,zf*0. /
DATA savr / 3500., 2784., 1500., 1739., 1683., 1564., 1562., &
1889., 2484., 1764., 1182., 1145., 1159., 3500., zf*0. /
DATA fuelmce / 0.12, 0.15, 0.25, 0.20, 0.20, 0.25, 0.40, &
0.30, 0.25, 0.25, 0.15, 0.20, 0.25, 0.12 , zf*0. /
DATA fueldens / nf * 32., zf*0. / ! 32 if solid, 19 if rotten.
DATA st / nf* 0.0555 , zf*0./
DATA se / nf* 0.010 , zf*0./
! ----- Notes on weight: (4) - best fit of data from D. Latham (pers. comm.);
! (5)-(7) could be 60-120; (8)-(10) could be 300-1600;
! (11)-(13) could be 300-1600
DATA weight / 7., 7., 7., 180., 100., 100., 100., &
900., 900., 900., 900., 900., 900., 7. , zf*0./
! ----- 1.12083 is 5 tons/acre. 5-50 tons/acre orig., 100-300 after blowdown
DATA fci_d / 0., 0., 0., 1.123, 0., 0., 0., &
1.121, 1.121, 1.121, 1.121, 1.121, 1.121, 0., zf*0./
DATA fct / 60., 60., 60., 60., 60., 60., 60., &
60., 120., 180., 180., 180., 180. , 60. , zf*0. /
DATA ichap / 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , zf*0/
! =========================================================================
contains
subroutine init_fuel_cats 1,49
implicit none
!*** purpose: initialize fuel tables and variables by constants
!*** arguments: none
logical, external:: wrf_dm_on_monitor
!$ integer, external:: OMP_GET_THREAD_NUM
!*** local
integer:: i,j,k,ii,iounit
character(len=128):: msg
!*** executable
! read
namelist /fuel_scalars/ cmbcnst,hfgl,fuelmc_g,fuelmc_c,nfuelcats,no_fuel_cat
namelist /fuel_categories/ fuel_name,windrf,fgi,fueldepthm,savr, &
fuelmce,fueldens,st,se,weight,fci_d,fct,ichap
!$ if (OMP_GET_THREAD_NUM() .ne. 0)then
!$ call crash('init_fuel_cats: must be called from master thread')
!$ endif
IF ( wrf_dm_on_monitor() ) THEN
! if we are the master task, read the file
iounit=open_text_file
('namelist.fire','read')
read(iounit,fuel_scalars)
read(iounit,fuel_categories)
CLOSE(iounit)
if (nfuelcats>mfuelcats) then
write(msg,*)'nfuelcats=',nfuelcats,' is too large, increase mfuelcats'
call crash
(msg)
endif
if (no_fuel_cat >= 1 .and. no_fuel_cat <= nfuelcats)then
write(msg,*)'no_fuel_cat=',no_fuel_cat,' may not be between 1 and nfuelcats=',nfuelcats
call crash
(msg)
endif
ENDIF
! broadcast the contents of the file
call wrf_dm_bcast_real
(cmbcnst,1)
call wrf_dm_bcast_real
(hfgl,1)
call wrf_dm_bcast_real
(fuelmc_g,1)
call wrf_dm_bcast_real
(fuelmc_c,1)
call wrf_dm_bcast_integer
(nfuelcats,1)
call wrf_dm_bcast_integer
(no_fuel_cat,1)
call wrf_dm_bcast_real
(windrf, nfuelcats)
call wrf_dm_bcast_real
(fgi, nfuelcats)
call wrf_dm_bcast_real
(fueldepthm,nfuelcats)
call wrf_dm_bcast_real
(savr, nfuelcats)
call wrf_dm_bcast_real
(fuelmce, nfuelcats)
call wrf_dm_bcast_real
(fueldens, nfuelcats)
call wrf_dm_bcast_real
(st, nfuelcats)
call wrf_dm_bcast_real
(se, nfuelcats)
call wrf_dm_bcast_real
(weight, nfuelcats)
call wrf_dm_bcast_real
(fci_d, nfuelcats)
call wrf_dm_bcast_real
(fct, nfuelcats)
call wrf_dm_bcast_integer
(ichap, nfuelcats)
! compute derived scalars
bmst = fuelmc_g/(1+fuelmc_g)
fuelheat = cmbcnst * 4.30e-04 ! convert J/kg to BTU/lb
! compute derived fuel category coefficients
DO i = 1,nfuelcats
fci(i) = (1.+fuelmc_c)*fci_d(i)
if(fct(i) .ne. 0.)then
fcbr(i) = fci_d(i)/fct(i) ! avoid division by zero
else
fcbr(i) = 0
endif
END DO
! prints
call message
('**********************************************************')
call message
('FUEL COEFFICIENTS')
write(msg,8)'cmbcnst ',cmbcnst
call message
(msg)
write(msg,8)'hfgl ',hfgl
call message
(msg)
write(msg,8)'fuelmc_g ',fuelmc_g
call message
(msg)
write(msg,8)'fuelmc_c ',fuelmc_c
call message
(msg)
write(msg,8)'bmst ',bmst
call message
(msg)
write(msg,8)'fuelheat ',fuelheat
call message
(msg)
write(msg,7)'nfuelcats ',nfuelcats
call message
(msg)
write(msg,7)'no_fuel_cat',no_fuel_cat
call message
(msg)
j=1
7 format(a,5(1x,i8,4x))
8 format(a,5(1x,g12.5e2))
9 format(a,5(1x,a))
do i=1,nfuelcats,j
k=min(i+j-1,nfuelcats)
call message
(' ')
write(msg,7)'CATEGORY ',(ii,ii=i,k)
call message
(msg)
write(msg,9)'fuel name ',(fuel_name(ii),ii=i,k)
call message
(msg)
! write(msg,8)'windrf ',(windrf(ii),ii=i,k)
! call message(msg)
write(msg,8)'fgi ',(fgi(ii),ii=i,k)
call message
(msg)
write(msg,8)'fueldepthm',(fueldepthm(ii),ii=i,k)
call message
(msg)
write(msg,8)'savr ',(savr(ii),ii=i,k)
call message
(msg)
write(msg,8)'fuelmce ',(fuelmce(ii),ii=i,k)
call message
(msg)
write(msg,8)'fueldens ',(fueldens(ii),ii=i,k)
call message
(msg)
write(msg,8)'st ',(st(ii),ii=i,k)
call message
(msg)
write(msg,8)'se ',(se(ii),ii=i,k)
call message
(msg)
write(msg,8)'weight ',(weight(ii),ii=i,k)
call message
(msg)
write(msg,8)'fci_d ',(fci_d(ii),ii=i,k)
call message
(msg)
write(msg,8)'fct ',(fct(ii),ii=i,k)
call message
(msg)
write(msg,7)'ichap ',(ichap(ii),ii=i,k)
call message
(msg)
write(msg,8)'fci ',(fci(ii),ii=i,k)
call message
(msg)
write(msg,8)'fcbr ',(fcbr(ii),ii=i,k)
call message
(msg)
enddo
call message
('**********************************************************')
! and print to file
IF ( wrf_dm_on_monitor() ) THEN
call write_fuels_m
(61,30.,1.)
ENDIF
end subroutine init_fuel_cats
subroutine write_fuels_m(nsteps,maxwind,maxslope) 1,22
implicit none
integer, intent(in):: nsteps ! number of steps for speed computation
real, intent(in):: maxwind,maxslope ! computer from zero to these
integer:: iounit,k,j,i
type(fire_params)::fp
!type fire_params
!real,pointer,dimension(:,:):: vx,vy ! wind velocity (m/s)
!real,pointer,dimension(:,:):: zsf ! terrain height (m)
!real,pointer,dimension(:,:):: dzdxf,dzdyf ! terrain grad (1)
!real,pointer,dimension(:,:):: bbb,betafl,phiwc,r_0 ! spread formula coefficients
!real,pointer,dimension(:,:):: fgip ! init mass of surface fuel (kg/m^2)
!real,pointer,dimension(:,:):: ischap ! 1 if chapparal
!end type fire_params
real, dimension(1:2,1:nsteps), target::vx,vy,zsf,dzdxf,dzdyf,bbb,betafl,phiwc,r_0,fgip,ischap
real, dimension(1:2,1:nsteps)::nfuel_cat,fuel_time,ros
real::ros_base,ros_wind,ros_slope,propx,propy,r
fp%vx=>vx
fp%vy=>vy
fp%dzdxf=>dzdxf
fp%dzdyf=>dzdyf
fp%bbb=>bbb
fp%betafl=>betafl
fp%phiwc=>phiwc
fp%r_0=>r_0
fp%fgip=>fgip
fp%ischap=>ischap
iounit = open_text_file
('fuels.m','write')
10 format('fuel(',i3,').',a,'=',"'",a,"'",';% ',a)
do k=1,nfuelcats
write(iounit,10)k,'fuel_name',trim(fuel_name(k)),'FUEL MODEL NAME'
call write_var
(k,'windrf',windrf(k),'WIND REDUCTION FACTOR FROM 20ft TO MIDFLAME HEIGHT' )
call write_var
(k,'fgi',fgi(k),'INITIAL TOTAL MASS OF SURFACE FUEL (KG/M**2)' )
call write_var
(k,'fueldepthm',fueldepthm(k),'FUEL DEPTH (M)')
call write_var
(k,'savr',savr(k),'FUEL PARTICLE SURFACE-AREA-TO-VOLUME RATIO, 1/FT')
call write_var
(k,'fuelmce',fuelmce(k),'MOISTURE CONTENT OF EXTINCTION')
call write_var
(k,'fueldens',fueldens(k),'OVENDRY PARTICLE DENSITY, LB/FT^3')
call write_var
(k,'st',st(k),'FUEL PARTICLE TOTAL MINERAL CONTENT')
call write_var
(k,'se',se(k),'FUEL PARTICLE EFFECTIVE MINERAL CONTENT')
call write_var
(k,'weight',weight(k),'WEIGHTING PARAMETER THAT DETERMINES THE SLOPE OF THE MASS LOSS CURVE')
call write_var
(k,'fci_d',fci_d(k),'INITIAL DRY MASS OF CANOPY FUEL')
call write_var
(k,'fct',fct(k),'BURN OUT TIME FOR CANOPY FUEL, AFTER DRY (S)')
call write_var
(k,'ichap',float(ichap(k)),'1 if chaparral, 0 if not')
call write_var
(k,'fci',fci(k),'INITIAL TOTAL MASS OF CANOPY FUEL')
call write_var
(k,'fcbr',fcbr(k),'FUEL CANOPY BURN RATE (KG/M**2/S)')
call write_var
(k,'hfgl',hfgl,'SURFACE FIRE HEAT FLUX THRESHOLD TO IGNITE CANOPY (W/m^2)')
call write_var
(k,'cmbcnst',cmbcnst,'JOULES PER KG OF DRY FUEL')
call write_var
(k,'fuelheat',fuelheat,'FUEL PARTICLE LOW HEAT CONTENT, BTU/LB')
call write_var
(k,'fuelmc_g',fuelmc_g,'FUEL PARTICLE (SURFACE) MOISTURE CONTENT')
call write_var
(k,'fuelmc_c',fuelmc_c,'FUEL PARTICLE (CANOPY) MOISTURE CONTENT')
! set up fuel arrays
!subroutine set_fire_params( &
! ifds,ifde,jfds,jfde, &
! ifms,ifme,jfms,jfme, &
! ifts,ifte,jfts,jfte, &
! fdx,fdy,nfuel_cat0, &
! nfuel_cat,fuel_time, &
! fp )
nfuel_cat = k
call set_fire_params
( &
1,2,1,nsteps, &
1,2,1,nsteps, &
1,2,1,nsteps, &
0.,0.,k, &
nfuel_cat,fuel_time, &
fp )
! set up windspeed and slope table
propx=1.
propy=0.
do j=1,nsteps
r=float(j-1)/float(nsteps-1)
! line 1 varies windspeed (in x direction), zero slope
vx(1,j)=maxwind*r
vy(1,j)=0.
dzdxf(1,j)=0.
dzdyf(1,j)=0.
! line 2 varies slope (in x direction), zero slope
vx(2,j)=0.
vy(2,j)=0.
dzdxf(2,j)=maxslope*r
dzdyf(2,j)=0.
enddo
do j=1,nsteps
do i=1,2
call fire_ros
(ros_base,ros_wind,ros_slope, &
propx,propy,i,j,fp)
ros(i,j)=ros_base+ros_wind+ros_slope
enddo
write(iounit,13)k,'wind',j,vx(1,j),'wind speed'
write(iounit,13)k,'ros_wind',j,ros(1,j),'rate of spread for the wind speed'
write(iounit,13)k,'slope',j,dzdxf(2,j),'slope'
write(iounit,13)k,'ros_slope',j,ros(2,j),'rate of spread for the slope'
enddo
enddo
13 format('fuel(',i3,').',a,'(',i3,')=',g12.5e2,';% ',a)
close(iounit)
! stop
contains
subroutine write_var(k,name,value,descr) 19
! write entry for one variable
integer, intent(in)::k
character(len=*), intent(in)::name,descr
real, intent(in)::value
write(iounit,11)k,name,value
write(iounit,12)k,name,descr
11 format('fuel(',i3,').',a,'=',g12.5e2, ';')
12 format('fuel(',i3,').',a,"_descr='",a,"';")
end subroutine write_var
end subroutine write_fuels_m
!
!*******************
!
subroutine set_fire_params( & 2,3
ifds,ifde,jfds,jfde, &
ifms,ifme,jfms,jfme, &
ifts,ifte,jfts,jfte, &
fdx,fdy,nfuel_cat0, &
nfuel_cat,fuel_time, &
fp )
implicit none
!*** purpose: Set all fire model params arrays, constant values.
!*** arguments
integer, intent(in)::ifds,ifde,jfds,jfde ! fire domain bounds
integer, intent(in)::ifts,ifte,jfts,jfte ! fire tile bounds
integer, intent(in)::ifms,ifme,jfms,jfme ! memory array bounds
real, intent(in):: fdx,fdy ! fire mesh spacing
integer,intent(in)::nfuel_cat0 ! default fuel category, if nfuel_cat=0
real, intent(in),dimension(ifms:ifme, jfms:jfme)::nfuel_cat ! fuel data
real, intent(out), dimension(ifms:ifme, jfms:jfme)::fuel_time ! fire params arrays
type(fire_params),intent(inout)::fp
!*** local
real:: fuelload, fueldepth, rtemp1, rtemp2, &
qig, epsilon, rhob, wn, betaop, e, c, &
xifr, etas, etam, a, gammax, gamma, ratio, ir, &
fuelloadm,fdxinv,fdyinv
integer:: i,j,k
integer::nerr
character(len=128)::msg
!*** executable
nerr=0
do j=jfts,jfte
do i=ifts,ifte
! fuel category
k=int( nfuel_cat(i,j) )
if(k.eq.no_fuel_cat)then ! no fuel
fp%fgip(i,j)=0. ! no mass
fp%ischap(i,j)=0.
fp%betafl(i,j)=0. ! to prevent division by zero
fp%bbb(i,j)=1. !
fuel_time(i,j)=7./0.85 ! does not matter, just what was there before
fp%phiwc(i,j)=0.
fp%r_0(i,j)=0. ! no fuel, no spread.
else
if(k.eq.0.and.nfuel_cat0.ge.1.and.nfuel_cat0.le.nfuelcats)then
! replace k=0 by default
k=nfuel_cat0
nerr=nerr+1
endif
if(k.lt.1.or.k.gt.nfuelcats)then
!$OMP CRITICAL(FIRE_PHYS_CRIT)
write(msg,'(3(a,i5))')'nfuel_cat(', i ,',',j,')=',k
!$OMP END CRITICAL(FIRE_PHYS_CRIT)
call message
(msg)
call crash
('set_fire_params: fuel category out of bounds')
endif
fuel_time(i,j)=weight(k)/0.85 ! cell based
! set fuel time constant: weight=1000 => 40% decrease over 10 min
! fuel decreases as exp(-t/fuel_time)
! exp(-600*0.85/1000) = approx 0.6
fp%ischap(i,j)=ichap(k)
fp%fgip(i,j)=fgi(k)
! ...Settings of fire spread parameters from Rothermel follows. These
! don't need to be recalculated later.
fuelloadm= (1.-bmst) * fgi(k) ! fuelload without moisture
fuelload = fuelloadm * (.3048)**2 * 2.205 ! to lb/ft^2
fueldepth = fueldepthm(k)/0.3048 ! to ft
fp%betafl(i,j) = fuelload/(fueldepth * fueldens(k))! packing ratio
betaop = 3.348 * savr(k)**(-0.8189) ! optimum packing ratio
qig = 250. + 1116.*fuelmc_g ! heat of preignition, btu/lb
epsilon = exp(-138./savr(k) ) ! effective heating number
rhob = fuelload/fueldepth ! ovendry bulk density, lb/ft^3
c = 7.47 * exp( -0.133 * savr(k)**0.55) ! const in wind coef
fp%bbb(i,j) = 0.02526 * savr(k)**0.54 ! const in wind coef
e = 0.715 * exp( -3.59e-4 * savr(k)) ! const in wind coef
fp%phiwc(i,j) = c * (fp%betafl(i,j)/betaop)**(-e)
rtemp2 = savr(k)**1.5
gammax = rtemp2/(495. + 0.0594*rtemp2) ! maximum rxn vel, 1/min
a = 1./(4.774 * savr(k)**0.1 - 7.27) ! coef for optimum rxn vel
ratio = fp%betafl(i,j)/betaop
gamma = gammax *(ratio**a) *exp(a*(1.-ratio)) !optimum rxn vel, 1/min
wn = fuelload/(1 + st(k)) ! net fuel loading, lb/ft^2
rtemp1 = fuelmc_g/fuelmce(k)
etam = 1.-2.59*rtemp1 +5.11*rtemp1**2 -3.52*rtemp1**3 !moist damp coef
etas = 0.174* se(k)**(-0.19) ! mineral damping coef
ir = gamma * wn * fuelheat * etam * etas !rxn intensity,btu/ft^2 min
! irm = ir * 1055./( 0.3048**2 * 60.) * 1.e-6 !for mw/m^2
xifr = exp( (0.792 + 0.681*savr(k)**0.5) &
* (fp%betafl(i,j)+0.1)) /(192. + 0.2595*savr(k)) ! propagating flux ratio
! ... r_0 is the spread rate for a fire on flat ground with no wind.
fp%r_0(i,j) = ir*xifr/(rhob * epsilon *qig) ! default spread rate in ft/min
endif
enddo
enddo
if(nerr.gt.1)then
!$OMP CRITICAL(FIRE_PHYS_CRIT)
write(msg,'(a,i6,a)')'set_fire_params: WARNING: fuel category 0 replaced in',nerr,' cells'
!$OMP END CRITICAL(FIRE_PHYS_CRIT)
call message
(msg)
endif
end subroutine set_fire_params
!
!*******************
!
subroutine heat_fluxes(dt, & 1
ifms,ifme,jfms,jfme, & ! memory dims
ifts,ifte,jfts,jfte, & ! tile dims
iffs,iffe,jffs,jffe, & ! fuel_frac_burnt dims
fgip,fuel_frac_burnt, & !in
grnhft,grnqft) !out
implicit none
!*** purpose
! compute the heat fluxes on the fire grid cells
!*** arguments
real, intent(in)::dt ! dt the fire time step (the fire model advances time by this)
integer, intent(in)::ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,iffs,iffe,jffs,jffe ! dimensions
real, intent(in),dimension(ifms:ifme,jfms:jfme):: fgip
real, intent(in),dimension(iffs:iffe,jffs:jffe):: fuel_frac_burnt
real, intent(out),dimension(ifms:ifme,jfms:jfme):: grnhft,grnqft
!*** local
integer::i,j
real:: dmass
!*** executable
do j=jfts,jfte
do i=ifts,ifte
dmass = & ! surface fuel dry mass burnt this call (kg/m^2)
fgip(i,j) & ! init mass from fuel model no (kg/m^2) = fgi(nfuel_cat(i,j)
* fuel_frac_burnt(i,j) ! fraction burned this call (1)
grnhft(i,j) = (dmass/dt)*(1.-bmst)*cmbcnst ! surface fire sensible heat flux W/m^2
grnqft(i,j) = (bmst+(1.-bmst)*.56)*(dmass/dt)*xlv ! surface fire latent heat flux W/m
! xlv is defined in module_model_constants.. Assume 56% of cellulose molecule mass is water.
enddo
enddo
end subroutine heat_fluxes
!
!**********************
!
subroutine set_nfuel_cat( & 1,6
ifms,ifme,jfms,jfme, &
ifts,ifte,jfts,jfte, &
ifuelread,nfuel_cat0,zsf,nfuel_cat)
implicit none
! set fuel distributions for testing
integer, intent(in):: ifts,ifte,jfts,jfte, &
ifms,ifme,jfms,jfme
integer, intent(in)::ifuelread,nfuel_cat0
real, intent(in), dimension(ifms:ifme, jfms:jfme)::zsf
real, intent(out), dimension(ifms:ifme, jfms:jfme)::nfuel_cat
!*** local
! parameters to control execution
integer:: i,j,iu1
real:: t1
character(len=128)msg
!$OMP CRITICAL(FIRE_PHYS_CRIT)
write(msg,'(a,i3)')'set_nfuel_cat: ifuelread=',ifuelread
!$OMP END CRITICAL(FIRE_PHYS_CRIT)
call message
(msg)
if (ifuelread .eq. -1 .or. ifuelread .eq. 2) then
!$OMP CRITICAL(FIRE_PHYS_CRIT)
call message
('set_nfuel_cat: assuming nfuel_cat initialized already')
call message
(msg)
!$OMP END CRITICAL(FIRE_PHYS_CRIT)
else if (ifuelread .eq. 0) then
!
do j=jfts,jfte
do i=ifts,ifte
nfuel_cat(i,j)=real(nfuel_cat0)
enddo
enddo
!$OMP CRITICAL(FIRE_PHYS_CRIT)
write(msg,'(a,i3)')'set_nfuel_cat: fuel initialized with category',nfuel_cat0
!$OMP END CRITICAL(FIRE_PHYS_CRIT)
call message
(msg)
else if (ifuelread .eq. 1) then
!
! make dependent on altitude (co mountains/forest vs. plains)
! 2000 m : 6562 ft ; 1600 m: 5249 ft
! ... user defines fuel category spatial variability ! param!
do j=jfts,jfte
do i=ifts,ifte
! nfuel_cat(i,j)= 2 ! grass with understory ! jm does nothing
!jm t1=zsf(i,j)*slngth/100.
t1 = zsf(i,j) ! this is in m
if(t1.le.1524.)then ! up to 5000 ft
nfuel_cat(i,j)= 3 ! tall grass
else if(t1.ge.1524. .and. t1.le.2073.)then ! 5.0-6.8 kft.
nfuel_cat(i,j)= 2 ! grass with understory
else if(t1.ge.2073..and.t1.le.2438.)then ! 6.8-8.0 kft.
nfuel_cat(i,j)= 8 ! timber litter - 10 (ponderosa)
else if(t1.gt.2438. .and. t1.le. 3354.) then ! 8.0-11.0 kft.
! ... could also be mixed conifer.
nfuel_cat(i,j)= 10 ! timber litter - 8 (lodgepole)
else if(t1.gt.3354. .and. t1.le. 3658.) then ! 11.0-12.0 kft
nfuel_cat(i,j)= 1 ! alpine meadow - 1
else if(t1.gt.3658. ) then ! > 12.0 kft
nfuel_cat(i,j)= 14 ! no fuel.
endif
enddo
enddo
call message
('set_nfuel_cat: fuel initialized by altitude')
else
call crash
('set_nfuel_cat: bad ifuelread')
endif
! .............end load fuel categories (or constant) here.
end subroutine set_nfuel_cat
!
!**********************
!
subroutine fire_ros(ros_base,ros_wind,ros_slope, & 3
propx,propy,i,j,fp)
implicit none
! copied with the following changes ONLY:
! 0.5*(speed + abs(speed)) -> max(speed,0.)
! index l -> j
! not using nfuel_cat here - cell info was put into arrays passed as arguments
! in include file to avoid transcription errors when used elsewhere
! betaop is absorbed in phiwc, see module_fr_fire_model/fire_startup
! return the base, wind, and slope contributions to the rate of spread separately
! because they may be needed to take advantage of known wind and slope vectors.
! They should add up to get the total rate of spread.
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
! ... calculates fire spread rate with McArthur formula or Rothermel
! using fuel type of fuel cell
!
! m/s =(ft/min) *.3048/60. =(ft/min) * .00508 ! conversion rate
! ft/min = m/s * 2.2369 * 88. = m/s * 196.850 ! conversion rate
!
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
!*** arguments
real, intent(out)::ros_base,ros_wind,ros_slope ! rate of spread contribution due to fuel, wind, and slope
real, intent(in)::propx,propy
integer, intent(in)::i,j ! node mesh coordinates
type(fire_params),intent(in)::fp
!*** local
real:: speed, tanphi ! windspeed and slope in the direction normal to the fireline
real:: umid, phis, phiw, spdms, umidm, excess
real:: ros_back
integer, parameter::ibeh=1
real, parameter::ros_max=6.
character(len=128)msg
real::cor_wind,cor_slope,nvx,nvy,scale
!*** executable
! make sure normal direction is size 1
!scale=sqrt(propx*propx+propy*propy)+tiny(scale)
scale=1.
nvx=propx/scale
nvy=propy/scale
if (fire_advection.ne.0) then ! from flags in module_fr_fire_util
! wind speed is total speed
speed = sqrt(fp%vx(i,j)*fp%vx(i,j)+ fp%vy(i,j)*fp%vy(i,j))+tiny(speed)
! slope is total slope
tanphi = sqrt(fp%dzdxf(i,j)*fp%dzdxf(i,j) + fp%dzdyf(i,j)*fp%dzdyf(i,j))+tiny(tanphi)
! cos of wind and spread, if >0
cor_wind = max(0.,(fp%vx(i,j)*nvx + fp%vy(i,j)*nvy)/speed)
! cos of slope and spread, if >0
cor_slope = max(0., (fp%dzdxf(i,j)*nvx + fp%dzdyf(i,j)*nvy)/tanphi)
else
! wind speed in spread direction
speed = fp%vx(i,j)*nvx + fp%vy(i,j)*nvy
! slope in spread direction
tanphi = fp%dzdxf(i,j)*nvx + fp%dzdyf(i,j)*nvy
cor_wind=1.
cor_slope=1.
endif
if (.not. fp%ischap(i,j) > 0.) then ! if fuel is not chaparral, calculate rate of spread one of these ways
if (ibeh .eq. 1) then ! use Rothermel formula
! ... if wind is 0 or into fireline, phiw = 0, &this reduces to backing ros.
spdms = max(speed,0.) !
umidm = min(spdms,30.) ! max input wind spd is 30 m/s !param!
umid = umidm * 196.850 ! m/s to ft/min
! eqn.: phiw = c * umid**bbb(i,j) * (fp%betafl(i,j)/betaop)**(-e) ! wind coef
phiw = umid**fp%bbb(i,j) * fp%phiwc(i,j) ! wind coef
phis=0.
if (tanphi .gt. 0.) then
phis = 5.275 *(fp%betafl(i,j))**(-0.3) *tanphi**2 ! slope factor
endif
! rosm = fp%r_0(i,j)*(1. + phiw + phis) * .00508 ! spread rate, m/s
ros_base = fp%r_0(i,j) * .00508
ros_wind = ros_base*phiw
ros_slope= ros_base*phis
else ! McArthur formula (Australian)
! rosm = 0.18*exp(0.8424*max(speed,0.))
ros_base = 0.18*exp(0.8424)
ros_wind = 0.18*exp(0.8424*max(speed,0.))
ros_slope =0.
endif
!
else ! chaparral
! .... spread rate has no dependency on fuel character, only windspeed.
spdms = max(speed,0.)
! rosm = 1.2974 * spdms**1.41 ! spread rate, m/s
! note: backing ros is 0 for chaparral without setting nozero value below
!sp_n=.03333
! chaparral backing fire spread rate 0.033 m/s ! param!
!rosm= max(rosm, sp_n) ! no less than backing r.o.s.
ros_back=.03333 ! chaparral backing fire spread rate 0.033 m/s ! param!
ros_wind = 1.2974 * spdms**1.41 ! spread rate, m/s
ros_wind = max(ros_wind, ros_back)
ros_slope =0.
endif
! if advection, multiply by the cosines
ros_wind=ros_wind*cor_wind
ros_slope=ros_slope*cor_slope
!
! ----------note! put an 6 m/s cap on max spread rate -----------
! rosm= min(rosm, 6.) ! no faster than this cap ! param !
excess = ros_base + ros_wind + ros_slope - ros_max
if (excess > 0.)then
! take it out of wind and slope in proportion
ros_wind = ros_wind - excess*ros_wind/(ros_wind+ros_slope)
ros_slope = ros_slope - excess*ros_slope/(ros_wind+ros_slope)
endif
!write(msg,*)i,j,' speed=',speed,' tanphi',tanphi,' ros=',ros_base,ros_wind,ros_slope
!call message(msg)
return
contains
real function nrm2(u,v)
real, intent(in)::u,v
nrm2=sqrt(u*u+v*v)
end function nrm2
end subroutine fire_ros
end module module_fr_fire_phys