2 !*** Jan Mandel October 2007 email: jmandel@ucar.edu or Jan.Mandel@gmail.com
7 module module_fr_sfire_model
9 use module_fr_sfire_core
10 use module_fr_sfire_util
11 use module_fr_sfire_phys
15 subroutine sfire_model ( &
16 id, & ! unique number for prints and debug
17 ifun, & ! what to do see below
18 need_lfn_update, & ! if lfn needs to be synced between tiles
19 num_ignitions, & ! number of ignitions before advancing
20 ifuelread,nfuel_cat0, & ! initialize fuel categories
21 ifds,ifde,jfds,jfde, & ! fire domain dims - the whole domain
22 ifms,ifme,jfms,jfme, & ! fire memory dims - how declared
23 ifps,ifpe,jfps,jfpe, & ! patch - nodes owned by this process
24 ifts,ifte,jfts,jfte, & ! fire tile dims - this thread
25 time_start,dt, & ! time and increment
26 fdx,fdy, & ! fire mesh spacing,
27 ignition_start_x,ignition_start_y, & ! ignition - small arrays
28 ignition_end_x,ignition_end_y, &
31 coord_xf,coord_yf,unit_xf,unit_yf, & ! fire mesh coordinates
32 zsf, & ! terrain height (for gradient)
33 vx,vy, & ! input: wind
34 lfn,lfn_out,tign,fuel_frac,fire_area, & ! state: level function, ign time, fuel left, area burning
35 grnhfx,grnqfx, & ! output: heat fluxes
36 nfuel_cat, & ! fuel data per point
37 fuel_time, & ! save derived internal data
38 bbb,betafl,phiwc,r_0,fgip,ischap &
41 ! This subroutine implements the fire spread model.
42 ! All quantities are on the fire grid. It inputs
43 ! winds given on the nodes of the fire grid
44 ! and outputs the heat fluxes on the cells of the fire grid.
45 ! This subroutine has no knowledge of any atmospheric model.
46 ! This code was written to conform with the WRF parallelism model, however it
47 ! does not depend on it. It can be called with domain equal to tile.
48 ! Wind and height must be given on 1 more node beyond the domain bounds.
49 ! The subroutine changes only array entries of the arguments in the tile.
50 ! Upon exit with ifun=2 (time step), lfn_out is to be copied into lfn by the caller.
51 ! When this subroutine is used on separate tiles that make a domain the value, the
52 ! it uses lfn on a strip of width 2 from neighboring tiles.
54 ! All computation is done on one tile.
56 ! This subroutine is intended to be called in a loop like
59 ! do ifun=1,6 (if initizalize run, otherwise 3,6)
60 ! start parallel loop over tiles
61 ! if ifun=1, set z and fuel data
62 ! if ifun=3, set the wind arrays
63 ! call sfire_model(....)
64 ! end parallel loop over tiles
66 ! if need_lfn_update, halo exchange on lfn width 2
69 ! halo exchange on z width 2
70 ! halo exchange on fuel data width 1
73 ! if ifun=3, halo exchange on winds width 2
82 integer, intent(in) :: id
83 integer, intent(in) :: ifun ! 1 = initialize run pass 1
84 ! 2 = initialize run pass 2
85 ! 3 = initialize timestep
87 ! 5 = copy timestep output to input
88 ! 6 = compute output fluxes
89 logical, intent(out)::need_lfn_update ! if true, halo update on lfn afterwards
91 integer, intent(in) :: num_ignitions ! number of ignition locations/times
92 integer, intent(in) :: ifuelread,nfuel_cat0 ! for set_fire_params
93 integer, intent(in) :: ifds,ifde,jfds,jfde,& ! fire domain bounds
94 ifps,ifpe,jfps,jfpe ! patch - nodes owned by this process
95 integer, intent(in) :: ifts,ifte,jfts,jfte ! fire tile bounds
96 integer, intent(in) :: ifms,ifme,jfms,jfme ! fire memory array bounds
97 REAL,INTENT(in) :: time_start,dt ! starting time, time step
98 REAL,INTENT(in) :: fdx,fdy ! spacing of the fire mesh
100 real, dimension(num_ignitions), intent(in):: &
101 ignition_start_x,ignition_start_y, &
102 ignition_end_x,ignition_end_y,ignition_radius, & ! start, end, radius, time
103 ignition_time ! of ignition lines
104 real, dimension(ifms:ifme, jfms:jfme), intent(in):: &
105 coord_xf,coord_yf ! node coordinates
106 real, intent(in):: unit_xf,unit_yf ! coordinate units in m
107 REAL, INTENT(in), dimension(ifms:ifme,jfms:jfme):: &
108 vx,vy ! wind m/s (node based), data, variable
111 REAL, INTENT(inout), dimension(ifms:ifme,jfms:jfme):: &
112 zsf, & ! terrain height, node based, data, constant after extr
113 lfn , & ! level function: fire is where lfn<0 (node)
114 tign , & ! absolute time of ignition (node)
115 fuel_frac ! fuel fraction (node), currently redundant
117 REAL, INTENT(out), dimension(ifms:ifme,jfms:jfme):: &
118 fire_area ! fraction of each cell burning
121 REAL, INTENT(out), dimension(ifms:ifme,jfms:jfme):: &
123 grnhfx,grnqfx ! heat fluxes J/m^2/s (cell)
125 ! constant arrays - set at initialization
126 integer, intent(inout), dimension(ifms:ifme, jfms:jfme)::nfuel_cat ! cell based, data, constant
127 real,intent(inout),dimension(ifms:ifme,jfms:jfme):: fuel_time
128 real,intent(inout),dimension(ifms:ifme,jfms:jfme):: bbb,betafl,phiwc,r_0 ! (node) spread formula coefficients
129 real,intent(inout),dimension(ifms:ifme,jfms:jfme):: fgip ! (cell) init mass of surface fuel (kg/m^2)
130 integer,intent(inout),dimension(ifms:ifme,jfms:jfme):: ischap ! (node) .ne.0 if chapparal
134 integer :: xifms,xifme,xjfms,xjfme ! memory bounds for pass-through arguments to normal spread
135 real, dimension(ifts:ifte,jfts:jfte)::fuel_frac_burnt,fuel_frac_end
136 integer::ignited,ig,i,j
138 character(len=128)::msg
142 call check_mesh_2dim(ifts-1,ifte+1,jfts-1,jfte+1,ifms,ifme,jfms,jfme)
145 xifms=ifms ! dimensions for the include file
151 need_lfn_update=.false.
153 if(ifun.eq.1)then ! do nothing, init pass 1 is outside only
154 elseif(ifun.eq.2)then
155 ! initialize all arrays that the model will not change later
157 ! assuming halo on zsf done
158 ! extrapolate on 1 row of cells beyond the domain boundary
159 ! including on the halo regions
161 call continue_at_boundary(1,1,0., & ! do x direction or y direction
162 ifms,ifme,jfms,jfme, & ! memory dims
163 ifds,ifde,jfds,jfde, & ! domain dims
164 ifps,ifpe,jfps,jfpe, & ! patch dims - winds defined up to +1
165 ifts,ifte,jfts,jfte, & ! tile dims
168 call set_nfuel_cat( &
169 ifms,ifme,jfms,jfme, &
170 ifts,ifte,jfts,jfte, &
171 ifuelread,nfuel_cat0,&
172 zsf,nfuel_cat) ! better not use the extrapolated zsf!!
174 ! uses nfuel_cat to set the other fuel data arrays
175 ! needs zsf on halo width 1 to compute the terrain gradient
176 call set_fire_params( &
177 ifds,ifde,jfds,jfde, &
178 ifms,ifme,jfms,jfme, &
179 ifts,ifte,jfts,jfte, &
181 nfuel_cat,fuel_time &
182 # include "fr_sfire_params_args.h"
185 call print_2d_stats(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,zsf,'model: terrain height')
187 ! initialize model state to no fire
188 call init_no_fire ( &
189 ifds,ifde,jfds,jfde, &
190 ifms,ifme,jfms,jfme, &
191 ifts,ifte,jfts,jfte, &
192 fdx,fdy,time_start, &
193 fuel_frac,fire_area,lfn,tign)
195 need_lfn_update=.true. ! because we have set lfn
197 elseif(ifun.eq.3)then ! ignition if so specified
199 ! check for ignitions
200 do ig = 1,num_ignitions
202 if(ignition_time(ig)>=time_start.and.ignition_time(ig)<time_start+dt)then
204 ifds,ifde,jfds,jfde, & ! fire domain dims - the whole domain
205 ifms,ifme,jfms,jfme, &
206 ifts,ifte,jfts,jfte, &
207 ignition_start_x(ig),ignition_start_y(ig),&
208 ignition_end_x(ig),ignition_end_y(ig), &
209 ignition_radius(ig), &
211 coord_xf,coord_yf,unit_xf,unit_yf, &
214 need_lfn_update=.true. ! if ignition, lfn changed
216 call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,lfn,'lfn_ig',id)
217 call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,coord_xf,'coord_xf_ig',id)
218 call write_array_m(ifts,ifte,jfts,jfte,ifms,ifme,jfms,jfme,coord_yf,'coord_yf_ig',id)
224 elseif (ifun.eq.4) then ! do the timestep
226 ! compute fuel fraction at start
228 ! ifms,ifme,jfms,jfme, &
229 ! ifts,ifte,jfts,jfte, &
230 ! ifms,ifme,jfms,jfme, &
231 ! lfn,tign,fuel_time,time_start,fuel_frac,fire_area) ! fuel frac is shared
233 call print_2d_stats(ifts,ifte,jfts,jfte, &
234 ifms,ifme,jfms,jfme, &
235 fuel_frac,'model: fuel_frac start')
237 ! advance the model from time_start to time_start+dt
238 ! return the fuel fraction burnt this call in each fire cell
239 ! will call module_fr_sfire_speed::normal_spread for propagation speed
240 ! We cannot simply compute the spread rate here because that will change with the
241 ! angle of the wind and the direction of propagation, thus it is done in subroutine
242 ! normal_spread at each fire time step. Instead, we pass arguments that
243 ! the speed function may use. The include is to guarantee this is done consistently
244 ! over the call chain.
246 ! propagate level set function in time
248 ! lfn does not change, tign has no halos
251 ifds,ifde,jfds,jfde, & ! fire domain dims - the whole domain
252 ifms,ifme,jfms,jfme, &
253 ifps,ifpe,jfps,jfpe, & ! patch - nodes owned by this process
254 ifts,ifte,jfts,jfte, &
255 time_start,dt,fdx,fdy,tbound, &
257 # include "fr_sfire_params_args.h"
260 elseif (ifun.eq.5) then ! copy the result of timestep back to input
261 ! this cannot be done in the time step itself because of race condition
262 ! some thread may still be using lfn as input in their tile halo
266 lfn(i,j)=lfn_out(i,j)
267 ! if want to try timestep again treat tign the same way here
268 ! even if tign does not need a halo
272 need_lfn_update=.true. ! duh
274 elseif (ifun.eq.6) then ! timestep postprocessing
276 ! compute the heat fluxes from the fuel burned
277 ! needs lfn and tign from neighbors so halo must be updated before
279 ifms,ifme,jfms,jfme, &
280 ifts,ifte,jfts,jfte, &
281 ifts,ifte,jfts,jfte, &
282 lfn,tign,fuel_time,time_start+dt,fuel_frac_end,fire_area) !fuel_frac_end is private and tile based
284 call print_2d_stats(ifts,ifte,jfts,jfte, &
285 ifts,ifte,jfts,jfte, &
286 fuel_frac_end,'model: fuel_frac end')
290 fuel_frac_burnt(i,j)=fuel_frac(i,j)-fuel_frac_end(i,j) ! fuel lost this timestep
291 fuel_frac(i,j)=fuel_frac_end(i,j) ! copy new value to state array
295 call print_2d_stats(ifts,ifte,jfts,jfte, &
296 ifts,ifte,jfts,jfte, &
297 fuel_frac_burnt,'model: fuel_frac burned')
299 call heat_fluxes(dt, &
300 ifms,ifme,jfms,jfme, &
301 ifts,ifte,jfts,jfte, &
302 ifts,ifte,jfts,jfte, & ! fuel_frac_burned is tile dimensioned
308 call print_2d_stats(ifts,ifte,jfts,jfte, &
309 ifms,ifme,jfms,jfme, &
310 grnhfx,'model: heat flux(J/m^2/s)')
313 write(msg,*)'sfire_model: bad ifun=',ifun
317 end subroutine sfire_model
323 end module module_fr_sfire_model