Skip to content

Commit 20e249e

Browse files
authored
Merge pull request #25 from pedro-jm/devels_frediani
Devels Frediani
2 parents 6311b01 + f45710a commit 20e249e

File tree

3 files changed

+147
-30
lines changed

3 files changed

+147
-30
lines changed

physics/fire_model_mod.F90

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module fire_model_mod
22

33
use fire_physics_mod, only: Calc_flame_length, Calc_fire_fluxes, Calc_smoke_emissions
44
use level_set_mod, only: Calc_fuel_left, Update_ignition_times, Reinit_level_set, Prop_level_set, Extrapol_var_at_bdys, &
5-
Stop_if_close_to_bdy, Copy_lfnout_to_lfn, Reinit_level_set_fast_dist
5+
Stop_if_close_to_bdy, Copy_lfnout_to_lfn, Reinit_level_set_fast_dist, Check_isolated_negative_lfn
66
use namelist_mod, only : namelist_t
77
use ros_mod, only : ros_t
88
use state_mod, only: state_fire_t, N_POINTS_IN_HALO
@@ -29,6 +29,7 @@ subroutine Advance_fire_model (config_flags, grid)
2929

3030
integer :: ij, ifds, ifde, jfds, jfde, ifts, ifte, jfts, jfte, ifms, ifme, jfms, jfme
3131
real :: tbound, time_start
32+
integer, parameter :: CHECK_ISOLATED_NEG_LFN = 0
3233
logical, parameter :: DEBUG_LOCAL = .false.
3334

3435

@@ -130,6 +131,8 @@ subroutine Advance_fire_model (config_flags, grid)
130131
#ifdef DM_PARALLEL
131132
call Do_halo_exchange_with_corners (grid%lfn, ifms, ifme, jfms, jfme, grid%ifps, grid%ifpe, grid%jfps, grid%jfpe, N_POINTS_IN_HALO, grid%cart_comm)
132133
#endif
134+
135+
if (CHECK_ISOLATED_NEG_LFN == 1) call Check_isolated_negative_lfn (grid)
133136

134137
if (DEBUG_LOCAL) call Print_message ('calling Ignite_prescribed_fires...')
135138
!$OMP PARALLEL DO &

physics/level_set_mod.F90

Lines changed: 142 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ module level_set_mod
2020
use ros_mod, only : ros_t
2121

2222
#ifdef DM_PARALLEL
23-
use mpi_mod, only : Do_halo_exchange
23+
use mpi_mod, only : Do_halo_exchange, Sum_across_mpi_tasks, Max_across_mpi_tasks
2424
#endif
2525

2626
implicit none
2727

2828
private
2929

3030
public :: Calc_fuel_left, Update_ignition_times, Reinit_level_set, Prop_level_set, Extrapol_var_at_bdys, Stop_if_close_to_bdy, &
31-
Copy_lfnout_to_lfn, Reinit_level_set_fast_dist
31+
Copy_lfnout_to_lfn, Reinit_level_set_fast_dist, Check_isolated_negative_lfn
3232

3333
integer, parameter :: BDY_ENO1 = 10, FAST_DIST_REINIT_FSM = 1
3434
integer, parameter :: FAR = 0, TRIAL = 1, KNOWN = 2
@@ -291,6 +291,137 @@ pure subroutine Copy_lfnout_to_lfn (ifts, ifte, jfts, jfte, ifms, ifme, jfms, jf
291291

292292
end subroutine Copy_lfnout_to_lfn
293293

294+
subroutine Check_isolated_negative_lfn (grid, threshold, min_size, max_size)
295+
296+
implicit none
297+
298+
type (state_fire_t), intent (in out) :: grid
299+
real, intent (in), optional :: threshold
300+
integer, intent (in), optional :: min_size, max_size
301+
302+
character (len = 256) :: msg
303+
integer :: cluster_i, cluster_j, cluster_size, flagged_size
304+
integer :: head, tail, i, ic, inb, j, jc, jnb, max_queue, min_size_value, max_size_value
305+
integer :: nx_loc, ny_loc
306+
logical :: found_cluster, touches_boundary
307+
logical, dimension(:, :), allocatable :: visited
308+
integer, dimension(:), allocatable :: queue_i, queue_j
309+
real :: detection_flag, detection_sum, global_location_i, global_location_j, global_size_value
310+
real :: location_i, location_j, size_value, threshold_value
311+
312+
313+
threshold_value = 0.0
314+
if (present (threshold)) threshold_value = threshold
315+
316+
min_size_value = 1
317+
if (present (min_size)) min_size_value = min_size
318+
319+
max_size_value = 6
320+
if (present (max_size)) max_size_value = max_size
321+
322+
if (max_size_value < min_size_value) return
323+
324+
nx_loc = grid%ifpe - grid%ifps + 1
325+
ny_loc = grid%jfpe - grid%jfps + 1
326+
if (nx_loc <= 0 .or. ny_loc <= 0) return
327+
max_queue = nx_loc * ny_loc
328+
329+
allocate (visited(grid%ifps:grid%ifpe, grid%jfps:grid%jfpe))
330+
allocate (queue_i(max_queue))
331+
allocate (queue_j(max_queue))
332+
333+
visited = .false.
334+
found_cluster = .false.
335+
flagged_size = 0
336+
cluster_i = grid%ifps
337+
cluster_j = grid%jfps
338+
339+
Cluster_search: do j = grid%jfps, grid%jfpe
340+
do i = grid%ifps, grid%ifpe
341+
if (visited(i, j)) cycle
342+
visited(i, j) = .true.
343+
if (grid%lfn(i, j) >= threshold_value) cycle
344+
345+
head = 1
346+
tail = 1
347+
queue_i(1) = i
348+
queue_j(1) = j
349+
cluster_size = 0
350+
touches_boundary = .false.
351+
352+
do while (head <= tail)
353+
ic = queue_i(head)
354+
jc = queue_j(head)
355+
head = head + 1
356+
357+
cluster_size = cluster_size + 1
358+
if (ic == grid%ifps .or. ic == grid%ifpe .or. jc == grid%jfps .or. jc == grid%jfpe) touches_boundary = .true.
359+
360+
do jnb = jc - 1, jc + 1
361+
do inb = ic - 1, ic + 1
362+
if (inb == ic .and. jnb == jc) cycle
363+
if (inb < grid%ifps .or. inb > grid%ifpe) cycle
364+
if (jnb < grid%jfps .or. jnb > grid%jfpe) cycle
365+
if (visited(inb, jnb)) cycle
366+
visited(inb, jnb) = .true.
367+
if (grid%lfn(inb, jnb) >= threshold_value) cycle
368+
369+
tail = tail + 1
370+
queue_i(tail) = inb
371+
queue_j(tail) = jnb
372+
end do
373+
end do
374+
end do
375+
376+
if (cluster_size >= min_size_value .and. cluster_size <= max_size_value .and. .not. touches_boundary) then
377+
found_cluster = .true.
378+
flagged_size = cluster_size
379+
cluster_i = i
380+
cluster_j = j
381+
exit Cluster_search
382+
end if
383+
end do
384+
end do Cluster_search
385+
386+
deallocate (visited)
387+
deallocate (queue_i)
388+
deallocate (queue_j)
389+
390+
detection_flag = 0.0
391+
location_i = -1.0
392+
location_j = -1.0
393+
size_value = -1.0
394+
if (found_cluster) then
395+
detection_flag = 1.0
396+
location_i = real (cluster_i)
397+
location_j = real (cluster_j)
398+
size_value = real (flagged_size)
399+
end if
400+
401+
#ifdef DM_PARALLEL
402+
call Sum_across_mpi_tasks (detection_flag, grid%cart_comm, detection_sum)
403+
call Max_across_mpi_tasks (location_i, grid%cart_comm, global_location_i)
404+
call Max_across_mpi_tasks (location_j, grid%cart_comm, global_location_j)
405+
call Max_across_mpi_tasks (size_value, grid%cart_comm, global_size_value)
406+
#else
407+
detection_sum = detection_flag
408+
global_location_i = location_i
409+
global_location_j = location_j
410+
global_size_value = size_value
411+
#endif
412+
413+
if (detection_sum > 0.0) then
414+
grid%datetime_now = grid%datetime_start
415+
call grid%datetime_now%Add_seconds (grid%itimestep * grid%dt)
416+
call grid%Save_state ()
417+
418+
write (msg, '(a, i6, a, i6, a, i6, a)') 'Isolated negative LFN cluster (size', int (global_size_value), ') near (i=', &
419+
int (global_location_i), ', j=', int (global_location_j), '). Simulation stopped after saving state.'
420+
call Stop_simulation (trim (msg))
421+
end if
422+
423+
end subroutine Check_isolated_negative_lfn
424+
294425
subroutine Prop_level_set (ifds, ifde, jfds, jfde, ifms, ifme, jfms, jfme, &
295426
num_tiles, i_start, i_end, j_start, j_end, ts, dt, dx, dy, fire_upwinding, fire_viscosity, &
296427
fire_viscosity_bg, fire_viscosity_band, fire_viscosity_ngp, fire_lsm_band_ngp, &
@@ -1667,34 +1798,25 @@ end function Select_godunov
16671798

16681799
pure function Select_eno (diff_lx, diff_rx) result (return_value)
16691800

1670-
! 1st order ENO scheme
1801+
! 1st order ENO scheme: choose the smaller magnitude derivative
1802+
! Both positive: pick smaller
1803+
! Both negative: pick larger (less negative)
1804+
! Mixed signs: zero (derivative crosses zero)
16711805

16721806
implicit none
16731807

1674-
real, intent (in):: diff_lx, diff_rx
1808+
real, intent(in) :: diff_lx, diff_rx
16751809
real :: return_value
16761810

1677-
real :: diff2x
16781811

1679-
1680-
if (.not. diff_lx > 0.0 .and. .not. diff_rx > 0.0) then
1681-
diff2x = diff_rx
1682-
else if (.not. diff_lx < 0.0 .and. .not. diff_rx < 0.0) then
1683-
diff2x = diff_lx
1684-
else if (.not. diff_lx < 0.0 .and. .not. diff_rx > 0.0) then
1685-
if (.not. abs (diff_rx) < abs(diff_lx)) then
1686-
diff2x = diff_rx
1687-
else
1688-
diff2x = diff_lx
1689-
end if
1812+
if (diff_lx * diff_rx > 0.0) then
1813+
return_value = sign(1.0, diff_lx) * min(abs(diff_lx), abs(diff_rx))
16901814
else
1691-
diff2x = 0.0
1815+
return_value = 0.0
16921816
end if
16931817

1694-
return_value = diff2x
1695-
16961818
end function Select_eno
1697-
1819+
16981820
pure function Select_2nd (dx, lfn_i, lfn_im1, lfn_ip1) result (return_value)
16991821

17001822
! 2nd-order advection scheme in the x,y-direction (DME)

physics/ros_wrffire_mod.F90

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,7 @@ pure function Calc_ros_wrffire (this, ifms, ifme, jfms, jfme, i, j, nvx, nvy, uf
8888
ros_wind = ros_wind * cor_wind
8989
ros_slope = ros_slope * cor_slope
9090

91-
! Limit the ros
92-
excess = ros_base + ros_wind + ros_slope - ROS_MAX
93-
if (excess > 0.0) then
94-
! take excess out of wind and slope in proportion
95-
ros_wind = ros_wind - excess * ros_wind / (ros_wind + ros_slope)
96-
ros_slope = ros_slope - excess * ros_slope/ (ros_wind + ros_slope)
97-
end if
98-
99-
return_value = ros_base + ros_wind + SLOPE_FACTOR * ros_slope
91+
return_value = min (ros_base + ros_wind + SLOPE_FACTOR * ros_slope, ROS_MAX)
10092
if (FIRE_GROWS_ONLY) return_value = max (return_value, 0.0)
10193

10294
end function Calc_ros_wrffire

0 commit comments

Comments
 (0)