@@ -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)
0 commit comments