PLUME-MoM-TSM  1.0
VolcanicPlumeModel
inversion.f90
Go to the documentation of this file.
1 !********************************************************************
3 !
9 !********************************************************************
10 
11 MODULE inversion
12 
13  USE plume_module, ONLY: w0 , r0
14  USE variables, ONLY: write_flag
15 
16  USE mixture_module, ONLY : mass_flow_rate
17  USE rise, ONLY: plume_height, column_regime
18 
19  USE inpout, ONLY: write_inversion
20  USE rise, ONLY: plumerise
21 
22  USE variables, ONLY : wp
23 
24 
25  IMPLICIT NONE
26 
28  REAL(wp) :: opt_value
29 
31  REAL(wp) :: opt_height
32 
34  REAL(wp) :: opt_mfr
35 
37  INTEGER :: opt_regime
38 
39 
40  REAL(wp) :: check_height
41 
42  SAVE
43 
44 CONTAINS
45 
46  !******************************************************************************
48  !
54  !******************************************************************************
55 
56  SUBROUTINE invert_height
57 
58  USE variables, ONLY: isset
59 
60  IMPLICIT NONE
61 
62  REAL(wp) :: r_opt , w_opt
63  LOGICAL :: search_flag
64 
65  IF ( .NOT.isset(w0) ) THEN
66 
67  IF ( .NOT.isset(r0) ) THEN
68 
69  WRITE(*,*) 'Inversion: Searching for velocity/radius'
70  w0 = 100.0_wp
72 
73  ELSE
74 
75  WRITE(*,*) 'Inversion: Searching for velocity'
76  w0 = 100.0_wp
77 
78  CALL velocity_search(w_opt,search_flag)
79  WRITE(*,*) 'Plume_height [m] =',opt_height,search_flag
80  WRITE(*,*) 'Velocity [m/s] =',w_opt
81 
82  CALL write_inversion(r0,w_opt,opt_mfr,opt_height,search_flag, &
83  opt_regime)
84 
85 
86  write_flag = .true.
87  w0 = w_opt
88  CALL plumerise
89 
90  END IF
91 
92  ELSE
93 
94  IF ( .NOT.isset(r0) ) THEN
95 
96  WRITE(*,*) 'Inversion: Searching for radius'
97  r0 = 50.0_wp
98 
99  CALL radius_search(r_opt,search_flag)
100  WRITE(*,*) 'Best height [m] =',opt_height,search_flag
101  WRITE(*,*) 'Radius [m] =',r_opt
102 
103  CALL write_inversion(r0,w_opt,opt_mfr,opt_height,search_flag, &
104  opt_regime)
105 
106  write_flag = .true.
107  r0 = r_opt
108  CALL plumerise
109 
110  ELSE
111 
112  WRITE(*,*) 'No Inversion: radius and velocity fixed in input file'
113 
114  write_flag = .true.
115  CALL plumerise
116 
117  END IF
118 
119  END IF
120 
121  END SUBROUTINE invert_height
122 
123  !******************************************************************************
125  !
131  !******************************************************************************
132 
133  SUBROUTINE velocity_radius_search
135  USE variables, ONLY: r_min,r_max,n_values
136 
137  IMPLICIT NONE
138 
139  REAL(wp) :: w_opt
140  INTEGER :: i
141  LOGICAL :: search_flag
142 
143  WRITE(*,97)
144 97 FORMAT(1x,' radius (m) ',1x,' velocity (m/s) ',1x, &
145  'MER (kg/s) ', 1x,'plume height (m)',1x, &
146  ' inversion ',1x,'column regime')
147 
148 
149  DO i=0,n_values-1
150 
151  r0 = r_min * (r_max/r_min)**( i / (n_values-1.0_wp) )
152  ! WRITE(*,*) 'r0',r0
153  CALL velocity_search(w_opt,search_flag)
154  WRITE(*,101) r0,w_opt,opt_mfr,opt_height,search_flag, opt_regime
155 
156  CALL write_inversion(r0,w_opt,opt_mfr,opt_height,search_flag, &
157  opt_regime)
158 
159  END DO
160 
161 101 FORMAT(2(2x,f15.8),1(1x,es15.8),1(1x,f15.2)4x,l,7x,i4)
162 
163 
164  END SUBROUTINE velocity_radius_search
165 
166  !******************************************************************************
168  !
176  !******************************************************************************
177 
178  SUBROUTINE velocity_search(w_opt,search_flag)
179 
180  USE variables, ONLY: height_obj, w_min, w_max
181  USE variables, ONLY: height_nbl
182  USE variables, ONLY : nbl_stop , umbrella_flag
183 
184  IMPLICIT none
185 
186  REAL(wp),INTENT(OUT) :: w_opt
187  LOGICAL,INTENT(OUT) :: search_flag
188  REAL(wp) :: w0_init
189  REAL(wp) :: w0_0 ,w0_2
190  REAL(wp) :: plume_height_0 , plume_height_2
191  REAL(wp) :: sign_0 , sign_2
192  REAL(wp) :: init_sign , mult_fact
193 
194  INTEGER :: iter_interval
195 
196  write_flag = .false.
197  search_flag = .true.
198 
199  ! Initial velocity value for the search of the best value
200  w0_init = sqrt(w_max*w_min)
201  w0 = w0_init
202 
203  CALL plumerise
204 
205  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
206 
207  check_height = height_nbl
208 
209  ELSE
210 
211  check_height = plume_height
212 
213  END IF
214 
215  ! WRITE(*,*) 'first solve',w0,plume_height,INT(column_regime)
216 
217  w_opt = w0
218  opt_value = abs(check_height-height_obj)
221  opt_regime = column_regime
222 
223 
224  IF ( ( check_height .GT. height_obj ) ) THEN
225 
226  mult_fact = 1.0_wp/((w_max/w_min)**0.125_wp)
227  plume_height_2 = check_height
228 
229  ELSE
230 
231  mult_fact = ((w_max/w_min)**0.125_wp)
232  plume_height_0 = check_height
233 
234  END IF
235 
236  init_sign = check_height-height_obj
237 
238  ! loop to search for a velocity interval over which the residual change sign
239  search_interval:DO iter_interval=1,4
240 
241  w0 = (mult_fact**iter_interval)*w0_init
242 
243  CALL plumerise
244 
245  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
246 
247  check_height = height_nbl
248 
249  ELSE
250 
251  check_height = plume_height
252 
253  END IF
254 
255  IF ( abs(check_height-height_obj) .LT. opt_value ) THEN
256 
257  w_opt = w0
258  opt_value = abs(check_height-height_obj)
261  opt_regime = column_regime
262 
263  END IF
264 
265  ! WRITE(*,*) 'search_interval',w0,plume_height,INT(column_regime)
266 
267  IF ( (check_height-height_obj)*init_sign .LT. 0.0_wp ) EXIT search_interval
268 
269  END DO search_interval
270 
271  IF ( iter_interval .EQ. 5 ) THEN
272 
273  ! WRITE(*,*) 'optimal velocity not found in the interval',w0_init,w0
274  w0 = w0_init
275  search_flag = .false.
276  return
277 
278  END IF
279 
280  init_sign = check_height-height_obj
281 
282  IF ( mult_fact .GT. 1.0_wp ) THEN
283 
284  w0_2 = w0
285  plume_height_2 = check_height
286  w0_0 = w0 / mult_fact
287 
288  ELSE
289 
290  w0_0 = w0
291  plume_height_0 = check_height
292  w0_2 = w0 / mult_fact
293 
294  END IF
295 
296  sign_0 = plume_height_0-height_obj
297  sign_2 = plume_height_2-height_obj
298 
299  search_zero:DO
300 
301  w0 = 0.5_wp * ( w0_0 + w0_2 )
302 
303  ! WRITE(*,*) 'search_zero',r0,w0,w0_0,w0_2
304 
305  CALL plumerise
306 
307  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
308 
309  check_height = height_nbl
310 
311  ELSE
312 
313  check_height = plume_height
314 
315  END IF
316 
317  IF ( abs(check_height-height_obj) .LT. opt_value ) THEN
318 
319  w_opt = w0
320  opt_value = abs(check_height-height_obj)
323  opt_regime = column_regime
324 
325  END IF
326 
327  !WRITE(*,*) 'plume_height,regime',plume_height,INT(column_regime)
328  !WRITE(*,*) 'w0_0,w0_2',w0_0,w0_2
329  !WRITE(*,*) 'plume_0,plume_2',plume_height_0,plume_height_2
330  !READ(*,*)
331 
332  IF ( abs(plume_height_0-plume_height_2) .LT. 1.e-3_wp ) EXIT search_zero
333  IF ( abs(check_height-height_obj)/height_obj .LT. 1.e-5_wp ) EXIT search_zero
334  IF ( abs(w0_2-w0_0) .LT. 1.e-6_wp ) THEN
335 
336  search_flag = .false.
337  EXIT search_zero
338 
339  END IF
340 
341  IF ( (check_height-height_obj)*sign_2 .LT. 0.0_wp ) THEN
342 
343  w0_0 = w0
344  plume_height_0 = check_height
345  sign_0 = plume_height_0-height_obj
346 
347  ELSE
348 
349  w0_2 = w0
350  plume_height_2 = check_height
351  sign_2 = plume_height_2-height_obj
352 
353  END IF
354 
355  init_sign = check_height-height_obj
356 
357  END DO search_zero
358 
359  w0 = w0_init
360 
361  END SUBROUTINE velocity_search
362 
363  !******************************************************************************
365  !
373  !******************************************************************************
374 
375  SUBROUTINE radius_search(r_opt,search_flag)
376 
377  USE variables, ONLY: height_obj , height_nbl
378  USE variables, ONLY : nbl_stop , umbrella_flag
379 
380  IMPLICIT none
381 
382  REAL(wp),INTENT(OUT) :: r_opt
383  LOGICAL,INTENT(OUT) :: search_flag
384  REAL(wp) :: r0_init
385  REAL(wp) :: r0_0 ,r0_2
386  REAL(wp) :: plume_height_0 , plume_height_2
387  REAL(wp) :: sign_0 , sign_2
388  REAL(wp) :: init_sign , mult_fact
389 
390  INTEGER :: iter_interval
391 
392  write_flag = .false.
393  search_flag = .true.
394 
395  r0_init = r0
396 
397  CALL plumerise
398  !WRITE(*,*) 'first solve',r0,plume_height,INT(column_regime)
399 
400  r_opt = r0
401 
402  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
403 
404  check_height = height_nbl
405 
406  ELSE
407 
408  check_height = plume_height
409 
410  END IF
411 
412  opt_value = abs(check_height-height_obj)
414 
416  opt_regime = column_regime
417 
418 
419  IF ( ( check_height .GT. height_obj ) ) THEN
420 
421  mult_fact = 0.33_wp
422  plume_height_2 = check_height
423 
424  ELSE
425 
426  mult_fact = 3.33_wp
427  plume_height_0 = check_height
428 
429  END IF
430 
431  init_sign = check_height-height_obj
432 
433  search_interval:DO iter_interval=1,5
434 
435  r0 = mult_fact*r0
436 
437  CALL plumerise
438 
439  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
440 
441  check_height = height_nbl
442 
443  ELSE
444 
445  check_height = plume_height
446 
447  END IF
448 
449  !WRITE(*,*) 'search interval',r0,plume_height,INT(column_regime)
450 
451  IF ( abs(check_height-height_obj) .LT. opt_value ) THEN
452 
453  r_opt = r0
454  opt_value = abs(check_height-height_obj)
457  opt_regime = column_regime
458 
459  END IF
460 
461  IF ( (check_height-height_obj)*init_sign .LT. 0.0_wp ) EXIT search_interval
462 
463  END DO search_interval
464 
465  !WRITE(*,*) 'iter_interval',iter_interval
466 
467  IF ( iter_interval .EQ. 6 ) THEN
468 
469  !WRITE(*,*) 'optimal velocity not found in the interval',r0_init,r0
470  r0 = r0_init
471  search_flag = .false.
472  RETURN
473 
474  END IF
475 
476  init_sign = plume_height-height_obj
477 
478  IF ( mult_fact .GT. 1.0_wp ) THEN
479 
480  r0_2 = r0
481  plume_height_2 = plume_height
482  r0_0 = r0_init
483 
484  ELSE
485 
486  r0_0 = r0
487  plume_height_0 = plume_height
488  r0_2 = r0_init
489 
490 
491  END IF
492 
493  sign_0 = plume_height_0-height_obj
494  sign_2 = plume_height_2-height_obj
495 
496  search_zero:DO
497 
498  r0 = 0.5_wp * ( r0_0 + r0_2 )
499 
500  CALL plumerise
501 
502  IF ( ( umbrella_flag ) .OR. ( nbl_stop ) ) THEN
503 
504  check_height = height_nbl
505 
506  ELSE
507 
508  check_height = plume_height
509 
510  END IF
511 
512  IF ( abs(check_height-height_obj) .LT. opt_value ) THEN
513 
514  r_opt = r0
515  opt_value = abs(check_height-height_obj)
518  opt_regime = column_regime
519 
520  END IF
521 
522  !WRITE(*,*) 'search_zero',r0,check_height,INT(column_regime)
523  !WRITE(*,*) 'r0_0,r0_2',r0_0,r0_2
524  !WRITE(*,*) 'plume_0,height_obj,plume_2',plume_height_0,height_obj,plume_height_2
525  !READ(*,*)
526 
527  IF ( abs(plume_height_0-plume_height_2) .LT. 1.e-3_wp ) EXIT search_zero
528  IF ( abs(check_height-height_obj)/height_obj .LT. 1.e-5_wp ) EXIT search_zero
529  IF ( abs(r0_2-r0_0) .LT. 1.e-6_wp ) THEN
530 
531  search_flag = .false.
532  EXIT search_zero
533 
534  END IF
535 
536  IF ( (check_height-height_obj)*sign_2 .LT. 0.0_wp ) THEN
537 
538  r0_0 = r0
539  plume_height_0 = check_height
540  sign_0 = plume_height_0-height_obj
541 
542  ELSE
543 
544  r0_2 = r0
545  plume_height_2 = check_height
546  sign_2 = plume_height_2-height_obj
547 
548  END IF
549 
550  init_sign = check_height-height_obj
551 
552  END DO search_zero
553 
554  r0 = r0_init
555 
556  END SUBROUTINE radius_search
557 
558 
559 
560 END MODULE inversion
real(wp) opt_value
Optimal value of velocity.
Definition: inversion.f90:28
real(wp) w0
initial vertical velocity of the plume
Definition: plume.f90:36
integer opt_regime
Optimal solution regime.
Definition: inversion.f90:37
logical write_flag
Definition: variables.f90:74
Input/Output module.
Definition: inpout.f90:11
subroutine velocity_radius_search
Height-radius/velocity inversion.
Definition: inversion.f90:134
logical nbl_stop
Flag for hysplit output .
Definition: variables.f90:45
real(wp) r_min
Definition: variables.f90:77
subroutine write_inversion(r0, w_opt, opt_mfr, opt_height, search_flag, opt_regime)
Write inversion file.
Definition: inpout.f90:2819
real(wp) opt_mfr
Optimal solution mass flow rate.
Definition: inversion.f90:34
real(wp) r0
initial radius of the plume
Definition: plume.f90:37
real(wp) w_min
Definition: variables.f90:79
Inversion module.
Definition: inversion.f90:11
subroutine velocity_search(w_opt, search_flag)
Height-velocity inversion.
Definition: inversion.f90:179
Gas/particles mixture module.
Definition: mixture.f90:11
Plume module.
Definition: plume.f90:11
real(wp) r_max
Definition: variables.f90:78
real(wp) column_regime
Definition: rise.f90:17
logical function isset(var)
Input variable check.
Definition: variables.f90:104
real(wp) height_nbl
Definition: variables.f90:60
real(wp) mass_flow_rate
Definition: mixture.f90:61
logical umbrella_flag
Flag to solve the model for the umbrella spreading.
Definition: variables.f90:53
subroutine invert_height
Height inversion.
Definition: inversion.f90:57
integer, parameter wp
working precision
Definition: variables.f90:21
subroutine plumerise
Main subroutine for the integration.
Definition: rise.f90:37
integer n_values
Definition: variables.f90:81
real(wp) check_height
Definition: inversion.f90:40
real(wp) opt_height
Optimal height found (can be different from the input one)
Definition: inversion.f90:31
Predictor-corrector module.
Definition: rise.f90:10
real(wp) height_obj
Definition: variables.f90:76
subroutine radius_search(r_opt, search_flag)
Height-radius inversion.
Definition: inversion.f90:376
Global variables.
Definition: variables.f90:10
real(wp) plume_height
Definition: rise.f90:16
real(wp) w_max
Definition: variables.f90:80