PLUME-MoM-TSM  1.0
VolcanicPlumeModel
SW_UMBRELLA.f90
Go to the documentation of this file.
1 !********************************************************************************
3 !********************************************************************************
4 module sw_umbrella
5 
6 CONTAINS
7 
8  SUBROUTINE solve_umbrella
9 
12 
15  USE geometry_2d, ONLY : j_source , k_source
16 
20 
21  USE inpout_2d, ONLY : init_param
22  USE inpout_2d, ONLY : output_solution
23  USE inpout_2d, ONLY : close_units
24 
27  USE solver_2d, ONLY : allocate_multigrid
28  USE solver_2d, ONLY : remap_solution
29  USE solver_2d, ONLY : deallocate_multigrid
30  USE solver_2d, ONLY : imex_rk_solver
31  USE solver_2d, ONLY : timestep
32  USE solver_2d, ONLY : check_solve
33 
34  USE variables, ONLY : wp
36 
37  USE parameters_2d, ONLY : x_source , y_source , r_source
38 
39  USE parameters_2d, ONLY : t_start
40  USE parameters_2d, ONLY : t_end
41  USE parameters_2d, ONLY : t_output
42  USE parameters_2d, ONLY : t_steady
43  USE parameters_2d, ONLY : dt0
44  USE parameters_2d, ONLY : verbose_level
45  USE parameters_2d, ONLY : n_vars
46 
47  USE solver_2d, ONLY : q , qp , t, dt
48  USe solver_2d, ONLY : q_mg_new
49 
50  USE constitutive_2d, ONLY : qc_to_qp
51 
52  USE solver_2d, ONLY : solve_mask , solve_cells
53  USE solver_2d, ONLY : j_cent , k_cent
54 
55  USE inpout, ONLY : run_name , dak_unit
56 
57  USE inpout, ONLY : write_dakota
58 
59  USE omp_lib
60 
61  IMPLICIT NONE
62 
63  REAL(wp) :: t1 , t2 , t3
64 
65  REAL(wp) :: rate
66  INTEGER :: st1 , st2 , st3 , cr , cm
67 
68  REAL(wp) :: dt_old , dt_old_old
69  LOGICAL :: stop_flag
70  LOGICAL :: steady_state
71 
72  INTEGER :: j,k,l
73  INTEGER :: n_threads
74 
75  INTEGER :: ix
76  INTEGER :: iy
77 
78  REAL(wp) :: x1 , x2 , x3 , xt
79  REAL(wp) :: y1 , y2 , y3 , yt
80  REAL(wp) :: x_new_source
81  REAL(wp) :: y_new_source
82  REAL(wp) :: r_new_source
83  REAL(wp) :: r_old_source
84  INTEGER :: j1 , j2 , j3
85  INTEGER :: k1 , k2 , k3
86 
87  REAL(wp) :: max_up_dist
88  REAL(wp) :: max_cw_distL
89  REAL(wp) :: max_cw_distR
90 
91  REAL(wp) :: csq1 , csq2 , csq3
92  REAL(wp) :: top , bot
93 
94  REAL(wp) :: h_tot , h_avg
95  INTEGER :: n_tot
96 
97  REAL(wp) :: x_upw , y_upw
98  REAL(wp) :: d_upw_nbl , d_upw_umb
99 
100  integer, allocatable :: positive_values(:)
101 
102  LOGICAL :: use_openmp = .false.
103 
104  INTEGER :: i_multigrid
105 
107  CHARACTER(LEN=30) :: swu_file
108  CHARACTER(LEN=30) :: umb_file
109 
110  INTEGER, PARAMETER :: swu_unit = 19
111  INTEGER, PARAMETER :: umb_unit = 20
112 
113  CHARACTER(LEN=20) :: description
114 
115  ! ALLOCATE( j_min(comp_cells_x) )
116 
117 
118  WRITE(*,*) '---------------------'
119  WRITE(*,*) 'SW_UMBRELLA 1.0'
120  WRITE(*,*) '---------------------'
121 
122  !$ use_openmp = .true.
123  !$ print *, "OpenMP program"
124 
125  IF ( .NOT. use_openmp) THEN
126 
127  print *, "Non-OpenMP simulation"
128 
129  ELSE
130 
131  !$ n_threads = omp_get_max_threads()
132  !$ CALL OMP_SET_NUM_THREADS(n_threads)
133  IF ( verbose_level .GE. 0 ) WRITE(*,*) 'Number of threads used', n_threads
134 
135  END IF
136 
137 
138  WRITE(*,*) 'u_atm',u_atm_umbl
139  WRITE(*,*) 'v_atm',v_atm_umbl
140 
141 
142 
143  ! First initialize the system_clock
144  CALL system_clock(count_rate=cr)
145  CALL system_clock(count_max=cm)
146  rate = dble(cr)
147 
148  CALL cpu_time(t1)
149  CALL system_clock (st1)
150 
151  CALL init_param
152 
153  CALL init_problem_param
154 
155  CALL init_grid
156 
157  CALL allocate_solver_variables
158 
159  CALL compute_cell_fract
160 
161  IF ( i_multigrid .GT. 1 ) THEN
162 
163  q = q_mg_new
164 
165  END IF
166 
167  t = t_start
168 
169  umb_file = trim(run_name)//'.umb'
170 
171  OPEN(umb_unit,file=umb_file,status='unknown',form='formatted')
172 
173  x_upw = x_source - r_source * u_atm_umbl / sqrt( u_atm_umbl**2 + &
174  v_atm_umbl**2 )
175  y_upw = y_source - r_source * v_atm_umbl / sqrt( u_atm_umbl**2 + &
176  v_atm_umbl**2 )
177 
178  d_upw_nbl = sqrt(x_upw**2 + y_upw**2)
179 
180  WRITE(umb_unit,305)
181  WRITE(umb_unit,306) t, 3.1415_wp * r_source**2 , d_upw_nbl
182 
183 305 FORMAT( 5x,' time (s)', 11x,' area (m2)',11x, 'upw distance (m)')
184 
185 306 FORMAT((7x,f14.4,16x,es11.3e3,16x,es11.3e3))
186 
187  steady_state = .false.
188 
189  solve_mask(2:comp_cells_x-1,2:comp_cells_y-1) = .true.
190 
191  CALL check_solve
192 
193  IF ( verbose_level .GE. 0 ) THEN
194 
195  WRITE(*,*)
196  WRITE(*,*) '******** START COMPUTATION *********'
197  WRITE(*,*)
198 
199  END IF
200 
201  IF ( verbose_level .GE. 1 ) THEN
202 
203  WRITE(*,*) 'Min q(1,:,:)=',minval(q(1,:,:))
204  WRITE(*,*) 'Max q(1,:,:)=',maxval(q(1,:,:))
205 
206  WRITE(*,*) 'SUM(q(1,:,:)=',sum(q(1,:,:))
207 
208  END IF
209 
210  dt_old = dt0
211  dt_old_old = dt_old
212  t_steady = t_end
213  stop_flag = .false.
214 
215  DO k = 1,comp_cells_y
216 
217  DO j = 1,comp_cells_x
218 
219  IF ( q(1,j,k) .GT. 0.0_wp ) THEN
220 
221  CALL qc_to_qp(q(1:n_vars,j,k) , qp(1:n_vars,j,k) )
222 
223  ELSE
224 
225  qp(1:n_vars,j,k) = 0.0_wp
226 
227  END IF
228 
229  END DO
230 
231  END DO
232 
233  CALL output_solution(t,steady_state)
234 
235  IF ( sum(q(1,:,:)) .EQ. 0.0_wp ) t_steady = t_output
236 
237  x_new_source = x_source
238  y_new_source = y_source
239  r_new_source = r_source
240  r_old_source = r_source
241 
242  WRITE(*,*) dx*dy*count(q(1,:,:).GT.1.e-5_wp)
243  IF ( verbose_level .GE. 0.0_wp ) THEN
244 
245  WRITE(*,fmt="(A3,F10.4,A5,F9.5,A9,ES11.3E3,A11,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3)") &
246  't =',t,'dt =',dt0, &
247  ' volume = ',dx*dy*sum(qp(1,:,:)) , &
248  ' area = ',dx*dy*count(q(1,:,:).GT.1.e-5_wp),' xnew =',x_new_source, &
249  ' rnew =',r_new_source
250  END IF
251 
252  CALL cpu_time(t2)
253  CALL system_clock (st2)
254 
255  time_loop:DO WHILE ( ( t .LT. t_end ) .AND. ( t .LT. t_steady ) )
256 
257  CALL check_solve
258 
259  IF ( verbose_level .GE. 1 ) THEN
260 
261  WRITE(*,*) 'cells to solve and reconstruct:' , count(solve_mask)
262 
263  END IF
264 
265  CALL timestep
266 
267  IF ( t+dt .GT. t_end ) dt = t_end - t
268  IF ( t+dt .GT. t_output ) dt = t_output - t
269 
270  dt = min(dt,1.1_wp * 0.5_wp * ( dt_old + dt_old_old ) )
271 
272  dt_old_old = dt_old
273  dt_old = dt
274 
275  CALL imex_rk_solver
276 
277  t = t+dt
278 
279  !$OMP PARALLEL DO private(j,k)
280 
281  max_up_dist = r_source
282  x1 = x_source - r_source*u_atm_umbl / ( sqrt( u_atm_umbl**2+v_atm_umbl**2 ) )
283  y1 = y_source - r_source*v_atm_umbl / ( sqrt( u_atm_umbl**2+v_atm_umbl**2 ) )
284  max_cw_distl = 0.0_wp
285  max_cw_distr = 0.0_wp
286 
287  DO l = 1,solve_cells
288 
289  j = j_cent(l)
290  k = k_cent(l)
291 
292  IF ( q(1,j,k) .GT. 0.0_wp ) THEN
293 
294  CALL qc_to_qp(q(1:n_vars,j,k) , qp(1:n_vars+2,j,k) )
295 
296  IF ( qp(1,j,k) .GE. 10.0_wp ) THEN
297 
298  upwind_dist(j,k) = - ( u_atm_umbl * ( x_comp(j) - x_source ) + &
299  v_atm_umbl * ( y_comp(k) - y_source ) ) &
300  / ( sqrt( u_atm_umbl**2 + v_atm_umbl**2 ) )
301 
302  crosswind_dist(j,k) = ( v_atm_umbl * ( x_comp(j) - x_source ) - &
303  u_atm_umbl * ( y_comp(k) - y_source ) ) &
304  / ( sqrt( u_atm_umbl**2 + v_atm_umbl**2 ) )
305 
306 
307  IF ( upwind_dist(j,k) .GE. max_up_dist ) THEN
308 
309  max_up_dist = upwind_dist(j,k)
310  x1 = x_comp(j)
311  y1 = y_comp(k)
312 
313  END IF
314 
315  IF ( abs(upwind_dist(j,k)) .LE. cell_size ) THEN
316 
317  IF ( crosswind_dist(j,k) .GT. max_cw_distl ) THEN
318 
319  max_cw_distl = crosswind_dist(j,k)
320  x2 = x_comp(j)
321  y2 = y_comp(k)
322 
323  END IF
324 
325  IF ( crosswind_dist(j,k) .LT. max_cw_distr ) THEN
326 
327  max_cw_distr = crosswind_dist(j,k)
328  x3 = x_comp(j)
329  y3 = y_comp(k)
330 
331  END IF
332 
333  END IF
334 
335  END IF
336 
337  ELSE
338 
339  qp(1:n_vars+2,j,k) = 0.0_wp
340 
341  END IF
342 
343  END DO
344 
345  !$OMP END PARALLEL DO
346 
347  !WRITE(*,*) max_up_dist
348  !WRITE(*,*) x1,y1,x2,y2,x3,y3
349 
350  IF ( abs( y1 - y2 ) .LT. abs( y1 - y3 ) ) THEN
351 
352  xt = x2
353  yt = y2
354 
355  x2 = x3
356  y2 = y3
357 
358  x3 = xt
359  y3 = yt
360 
361  END IF
362 
363  csq1 = x1**2 + y1**2
364  csq2 = x2**2 + y2**2
365  csq3 = x3**2 + y3**2
366 
367  top = ( y2 - y3 ) * ( csq1 - csq2 ) - ( y1 - y2 ) * ( csq2 - csq3 )
368  bot = ( x1 - x2 ) * ( y2 - y3 ) - ( x2 - x3 ) * ( y1 - y2 )
369 
370  x_new_source = 0.5_wp * top / bot
371  y_new_source = 0.5_wp * ( csq1 - csq2 - 2.0_wp * x_new_source * &
372  ( x1 - x2 ) ) / ( y1 - y2 )
373  r_new_source = sqrt( ( x1 - x_new_source )**2 + ( y1 - y_new_source )**2 )
374 
375  IF ( verbose_level .GE. 0 ) THEN
376 
377  WRITE(*,fmt="(A3,F10.4,A5,F9.5,A9,ES11.3E3,A11,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3)")&
378  't =' , t , 'dt =' , dt , ' volume = ' , dx*dy*sum(qp(1,:,:)) , &
379  ' area = ' , dx*dy*count(q(1,:,:).GT.1.e-2_wp) , ' xnew =' , &
380  x_new_source , ' ynew =' , y_new_source , ' rnew =' , r_new_source
381 
382  END IF
383 
384  t_steady = t_end
385 
386  IF ( ( t .GE. t_output ) .OR. ( t .GE. t_end ) ) THEN
387 
388  CALL cpu_time(t3)
389  CALL system_clock(st3)
390 
391  IF ( verbose_level .GE. 0.0_wp ) THEN
392 
393  WRITE(*,*) 'Time taken by iterations is',t3-t2,'seconds'
394  WRITE(*,*) 'Elapsed real time = ', dble( st3-st2 ) / rate,'seconds'
395 
396  END IF
397 
398  CALL output_solution(t,steady_state)
399 
400  x_upw = x_new_source - r_new_source * u_atm_umbl / sqrt( u_atm_umbl**2 + &
401  v_atm_umbl**2 )
402  y_upw = y_new_source - r_new_source * v_atm_umbl / sqrt( u_atm_umbl**2 + &
403  v_atm_umbl**2 )
404 
405  d_upw_umb = sqrt(x_upw**2 + y_upw**2)
406 
407  WRITE(umb_unit,306) t, dx*dy*count(q(1,:,:).GT.1.e-2_wp) , d_upw_umb
408 
409 
410  IF ( steady_flag .AND. ( r_new_source .EQ. r_old_source ) ) THEN
411 
412  WRITE(*,*) 'STEADY UMBRELLA REACHED'
413  EXIT time_loop
414 
415  END IF
416  r_old_source = r_new_source
417 
418  END IF
419 
420  solve_mask(2:comp_cells_x-1,2:comp_cells_y-1) = .false.
421 
422  END DO time_loop
423 
424  steady_state = .true.
425  CALL output_solution(t,steady_state)
426 
427 
428  CALL check_solve
429 
430  h_tot = 0.0_wp
431  n_tot = 0
432 
433  DO l = 1,solve_cells
434 
435  j = j_cent(l)
436  k = k_cent(l)
437 
438  IF ( q(1,j,k) .GT. 0.0_wp ) THEN
439 
440  CALL qc_to_qp(q(1:n_vars,j,k) , qp(1:n_vars+2,j,k) )
441 
442  IF ( ( x_comp(j)-x_new_source )**2 + ( y_comp(k)-y_new_source )**2 &
443  .LE. r_new_source**2 ) THEN
444 
445  h_tot = h_tot + qp(1,j,k)
446  n_tot = n_tot + 1
447 
448  END IF
449 
450  END IF
451 
452  END DO
453 
454  h_avg = h_tot / n_tot
455 
456  CALL deallocate_solver_variables
457  CALL deallocate_grid
458 
459  CALL close_units
460 
461  CALL cpu_time(t3)
462  CALL system_clock(st3)
463 
464  WRITE(*,fmt="(A9,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3)") ' xold =', x_source, &
465  ' yold =',y_source, ' rold =',r_source
466 
467  x_upw = x_source - r_source * u_atm_umbl / sqrt( u_atm_umbl**2 + &
468  v_atm_umbl**2 )
469  y_upw = y_source - r_source * v_atm_umbl / sqrt( u_atm_umbl**2 + &
470  v_atm_umbl**2 )
471 
472  d_upw_nbl = sqrt(x_upw**2 + y_upw**2)
473 
474  WRITE(*,*) 'Upwind plume point',x_upw,y_upw
475  WRITE(*,*) 'Upwind plume distance',d_upw_nbl
476 
477 
478  WRITE(*,fmt="(A9,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3,A9,ES11.3E3)") ' xnew =', &
479  x_new_source, ' ynew =',y_new_source, ' rnew =',r_new_source,' havg =',&
480  h_avg
481 
482  x_upw = x_new_source - r_new_source * u_atm_umbl / sqrt( u_atm_umbl**2 + &
483  v_atm_umbl**2 )
484  y_upw = y_new_source - r_new_source * v_atm_umbl / sqrt( u_atm_umbl**2 + &
485  v_atm_umbl**2 )
486 
487  d_upw_umb = sqrt(x_upw**2 + y_upw**2)
488 
489  WRITE(*,*) 'Upwind umbrella point',x_upw,y_upw
490  WRITE(*,*) 'Upwind umbrella distance',d_upw_umb
491  WRITE(*,*)
492  WRITE(*,*) 'Radius increase', r_new_source/r_source
493  WRITE(*,*) 'Upwind spreading increase', d_upw_umb/d_upw_nbl
494 
495  IF ( dakota_flag ) THEN
496 
497  description = 'Radius old'
498  CALL write_dakota(description,r_source)
499  description = 'Radius new'
500  CALL write_dakota(description,r_new_source)
501  description = 'Radius increase'
502  CALL write_dakota(description,r_new_source/r_source)
503  description = 'Upwind distance old'
504  CALL write_dakota(description,d_upw_nbl)
505  description = 'Upwind distance'
506  CALL write_dakota(description,d_upw_umb)
507  description = 'Upwind increase'
508  CALL write_dakota(description,d_upw_umb/d_upw_nbl)
509 
510  CLOSE(dak_unit)
511 
512  END IF
513 
514 
515  WRITE(*,*)
516  WRITE(*,*) 'Total time taken by the code is',t3-t1,'seconds'
517  WRITE(*,*) 'Total elapsed real time is', dble( st3 - st1 ) / rate,'seconds'
518 
519  ! Write x_new_soure, y_new_source , r_new_source on a file
520 
521  swu_file = trim(run_name)//'.swu'
522 
523  OPEN(swu_unit,file=swu_file,status='unknown',form='formatted')
524 
525  WRITE(swu_unit,307)
526 
527  WRITE(swu_unit,308) x_new_source , y_new_source , r_new_source , h_avg
528 
529 307 FORMAT( 5x,'x_new_source (m)', 14x,'y_new_source (m)',14x, 'r_new_source (m)',14x, 'h_avg (m)')
530 
531 308 FORMAT((7x,f14.4,16x,f14.4,16x,f14.4,9x,f14.4))
532 
533  CLOSE(swu_unit)
534  CLOSE(umb_unit)
535 
536  END SUBROUTINE solve_umbrella
537 
538 END module sw_umbrella
logical dakota_flag
Flag for dakota run (less files on output)
Definition: variables.f90:36
subroutine write_dakota(description, value)
Dakota outputs.
Definition: inpout.f90:2779
integer comp_cells_x
Number of control volumes x in the comp. domain.
Definition: geometry_2d.f90:64
real(wp) cell_size
Definition: geometry_2d.f90:68
real(wp) r_source
real(wp) dt0
Initial time step.
integer, dimension(:), allocatable k_cent
Definition: solver_2d.f90:172
Parameters.
Umbrella module.
Definition: SW_UMBRELLA.f90:4
integer comp_cells_y
Number of control volumes y in the comp. domain.
Definition: geometry_2d.f90:66
Numerical solver.
Definition: solver_2d.f90:12
subroutine deallocate_solver_variables
Memory deallocation.
Definition: solver_2d.f90:438
subroutine solve_umbrella
Definition: SW_UMBRELLA.f90:9
Input/Output module.
Definition: inpout_2d.f90:13
real(wp), dimension(:,:,:), allocatable q_mg_new
Definition: solver_2d.f90:181
real(wp) t_output
time of the next output
Input/Output module.
Definition: inpout.f90:11
integer n_vars
Number of conservative variables.
integer dak_unit
Dakota variables data unit.
Definition: inpout.f90:129
integer j_source
Definition: geometry_2d.f90:71
real(wp), dimension(:), allocatable x_comp
Location of the centers (x) of the control volume of the domain.
Definition: geometry_2d.f90:15
logical hysplit_flag
Flag for hysplit run.
Definition: variables.f90:39
real(wp), dimension(:,:,:), allocatable qp
Physical variables ( )
Definition: solver_2d.f90:107
Constitutive equations.
real(wp) dt
Time step.
Definition: solver_2d.f90:121
subroutine init_grid
Finite volume grid initialization.
Definition: geometry_2d.f90:91
logical steady_flag
Flag to stop the umbrella solver when a steady upwind spreading is reached.
Definition: variables.f90:56
subroutine init_problem_param
Initialization of relaxation flags.
subroutine deallocate_grid
subroutine init_source
Grid module.
Definition: geometry_2d.f90:7
subroutine deallocate_multigrid
Definition: solver_2d.f90:534
subroutine check_solve
Masking of cells to solve.
Definition: solver_2d.f90:598
integer verbose_level
subroutine compute_cell_fract
subroutine timestep
Time-step computation.
Definition: solver_2d.f90:727
subroutine qc_to_qp(qc, qp)
Conservative to physical variables.
integer, dimension(:), allocatable j_cent
Definition: solver_2d.f90:171
real(wp) t_end
end time for the run
real(wp) dx
Control volumes size.
Definition: geometry_2d.f90:56
real(wp) y_source
real(wp), dimension(:,:), allocatable upwind_dist
Definition: geometry_2d.f90:78
integer, parameter wp
working precision
Definition: variables.f90:21
subroutine close_units
Definition: inpout_2d.f90:298
real(wp), dimension(:,:), allocatable crosswind_dist
Definition: geometry_2d.f90:79
real(wp) t
time
Definition: solver_2d.f90:39
character(len=30) run_name
Name of the run (used for the output and backup files)
Definition: inpout.f90:69
subroutine init_param
Initialization of the variables read from the input file.
Definition: inpout_2d.f90:106
real(wp) t_start
initial time for the run
real(wp), dimension(:,:,:), allocatable q
Conservative variables.
Definition: solver_2d.f90:42
subroutine imex_rk_solver
Runge-Kutta integration.
Definition: solver_2d.f90:868
logical, dimension(:,:), allocatable solve_mask
Definition: solver_2d.f90:112
subroutine remap_solution
Definition: solver_2d.f90:541
real(wp) x_source
integer solve_cells
Definition: solver_2d.f90:116
subroutine allocate_solver_variables
Memory allocation.
Definition: solver_2d.f90:199
Global variables.
Definition: variables.f90:10
subroutine output_solution(time, steady_state)
Write the solution on the output unit.
Definition: inpout_2d.f90:215
real(wp), dimension(:), allocatable y_comp
Location of the centers (y) of the control volume of the domain.
Definition: geometry_2d.f90:21
integer k_source
Definition: geometry_2d.f90:71
real(wp) t_steady
end time when reached steady solution
real(wp) dy
Control volumes size.
Definition: geometry_2d.f90:59
subroutine allocate_multigrid
Definition: solver_2d.f90:527