1 | ! $Id: ropp_fm_bg2ro_1d.f90 4452 2015-01-29 14:42:02Z idculv $
|
---|
2 |
|
---|
3 | PROGRAM ropp_fm_bg2ro_1d
|
---|
4 |
|
---|
5 | !****p* Programs/ropp_fm_bg2ro_1d *
|
---|
6 | !
|
---|
7 | ! NAME
|
---|
8 | ! ropp_fm_bg2ro_1d
|
---|
9 | !
|
---|
10 | ! SYNOPSIS
|
---|
11 | ! Calculate radio occultation pseudo observation from background model
|
---|
12 | ! data using 1d forward models
|
---|
13 | !
|
---|
14 | ! > ropp_fm_bg2ro_1d <infile(s)> -o <outfile>
|
---|
15 | ! [-l] <levels_file> [-f] [-use_logp] [-use_logq]
|
---|
16 | ! [-comp] [-check_qsat] [-new_op] [-direct_ion] [-247L]
|
---|
17 | ! -zmin <geop_min> -zmax <geop_max> -nz <n_geop>
|
---|
18 | ! [-d] [-h] [-v]
|
---|
19 | !
|
---|
20 | ! ARGUMENTS
|
---|
21 | ! <infile(s)> One (or more) input file names.
|
---|
22 | !
|
---|
23 | ! OPTIONS
|
---|
24 | ! -o <outfile> name of output file (default: bg2ro.nc)
|
---|
25 | ! -l <levels_file> name of file containing a set of altitudes and
|
---|
26 | ! impact heights. This will typically be an
|
---|
27 | ! observation file. Only works for single file.
|
---|
28 | ! -f forward model only, no gradient calculation.
|
---|
29 | ! -use_logp use log(pressure) for forward model
|
---|
30 | ! -use_logq use log(spec humidity) for forward model
|
---|
31 | ! -comp include non ideal gas compressibility
|
---|
32 | ! -check_qsat check against saturation
|
---|
33 | ! -new_op use alternative refrac and bangle interpolation
|
---|
34 | ! -direct_ion forward model L1 and L2 directly, using model ionosphere
|
---|
35 | ! -247L output refrac and bangle on 'standard' 247L
|
---|
36 | ! -zmin <geop_min> minimum refractivity geopotential (gpm)'
|
---|
37 | ! -zmax <geop_max> maximum refractivity geopotential (gpm)'
|
---|
38 | ! -nz <n_geop> number of uniformly spaced refractivity geopotentials (gpm)'
|
---|
39 | ! -d output additional diagnostics
|
---|
40 | ! -h help
|
---|
41 | ! -v version information
|
---|
42 | !
|
---|
43 | ! DESCRIPTION
|
---|
44 | ! This program reads model data on model levels from the input data files
|
---|
45 | ! and calculates vertical profiles of bending angle and refractivity using
|
---|
46 | ! the 1d forward operators. The result is written to an ROPP formatted
|
---|
47 | ! output file.
|
---|
48 | !
|
---|
49 | ! NOTES
|
---|
50 | ! If the input file is a multifile, or more than one input files are
|
---|
51 | ! specified, the output file is a multifile.
|
---|
52 | !
|
---|
53 | ! Already existing output files will be overwritten.
|
---|
54 | !
|
---|
55 | ! EXAMPLES
|
---|
56 | ! 1) To calculate bending angle and refractivity from one of the example
|
---|
57 | ! (single-) files in the data directory:
|
---|
58 | !
|
---|
59 | ! > ropp_fm_bg2ro_1d ../data/bgr20090401_000329_M02_2030337800_N0007_XXXX.nc
|
---|
60 | !
|
---|
61 | ! 2) To calculate bending angle and refractivity profiles from all singlefiles
|
---|
62 | ! in the data directory:
|
---|
63 | !
|
---|
64 | ! > ropp_fm_bg2ro_1d ../data/bgr20090401*_N0007_XXXX.nc -o eg_02.nc
|
---|
65 | !
|
---|
66 | ! Note that the resulting eg_02.nc file contains forward modelled data from
|
---|
67 | ! all example profiles.
|
---|
68 | !
|
---|
69 | ! 3) To calculate forward modelled bending angle and refractivity profiles from
|
---|
70 | ! all profiles contained in the multifile bgr20090401_multi.nc:
|
---|
71 | !
|
---|
72 | ! > ropp_fm_bg2ro_1d ../data/bgr20090401_multi.nc -o eg_03.nc
|
---|
73 | !
|
---|
74 | ! Since the ecmwf_multi_* file was generated by concatenating the other
|
---|
75 | ! files in the data directory, eg_02.nc and eg_03.nc should be identical
|
---|
76 | ! apart from the file names.
|
---|
77 | !
|
---|
78 | ! 4) To calculate forward modelled L1 and L2 bending angles, assuming
|
---|
79 | ! a model ionosphere, from one of the example (single-) files
|
---|
80 | ! in the data directory:
|
---|
81 | !
|
---|
82 | ! > ropp_fm_bg2ro_1d --direct_ion ../data/bgr20090401_000329_M02_2030337800_N0007_YYYY.nc
|
---|
83 | !
|
---|
84 | ! The model ionosphere comprises a set of Chapman layers, each of
|
---|
85 | ! whose {Ne_max, H_peak, H_width} parameters are contained in the input file.
|
---|
86 | ! (The L2ctype and state1dFM structures have been suitably extended.)
|
---|
87 | !
|
---|
88 | ! SEE ALSO
|
---|
89 | ! ropp_fm_bangle_1d
|
---|
90 | ! ropp_fm_refrac_1d
|
---|
91 | ! ropp_fm_refrac_1d_new
|
---|
92 | !
|
---|
93 | ! AUTHOR
|
---|
94 | ! Met Office, Exeter, UK.
|
---|
95 | ! Any comments on this software should be given via the ROM SAF
|
---|
96 | ! Helpdesk at http://www.romsaf.org
|
---|
97 | !
|
---|
98 | ! COPYRIGHT
|
---|
99 | ! (c) EUMETSAT. All rights reserved.
|
---|
100 | ! For further details please refer to the file COPYRIGHT
|
---|
101 | ! which you should have received as part of this distribution.
|
---|
102 | !
|
---|
103 | !****
|
---|
104 |
|
---|
105 | !-------------------------------------------------------------------------------
|
---|
106 | ! 1. Declarations
|
---|
107 | !-------------------------------------------------------------------------------
|
---|
108 |
|
---|
109 | USE typesizes, ONLY: wp => EightByteReal
|
---|
110 | USE ropp_utils
|
---|
111 | USE ropp_io
|
---|
112 | USE ropp_io_types, ONLY: ROprof
|
---|
113 | USE ropp_fm
|
---|
114 | USE ropp_fm_types
|
---|
115 | USE ropp_fm_copy
|
---|
116 | USE ropp_fm_iono
|
---|
117 | USE ropp_fm_levels
|
---|
118 |
|
---|
119 | IMPLICIT NONE
|
---|
120 |
|
---|
121 | TYPE(ROprof) :: ro_data, l_data
|
---|
122 | TYPE(State1dFM) :: state
|
---|
123 | TYPE(Obs1dRefrac) :: obs_refrac
|
---|
124 | TYPE(Obs1dBangle) :: obs_bangle
|
---|
125 |
|
---|
126 | REAL(wp), DIMENSION(:,:), ALLOCATABLE :: gradient_bangle
|
---|
127 | REAL(wp), DIMENSION(:,:), ALLOCATABLE :: gradient_refrac
|
---|
128 | REAL(wp) :: geop_min
|
---|
129 | REAL(wp) :: geop_max
|
---|
130 | INTEGER :: n_geop
|
---|
131 |
|
---|
132 | INTEGER :: idummy
|
---|
133 | INTEGER :: i, iargc, argc, k
|
---|
134 | INTEGER :: n_files, n_profiles
|
---|
135 |
|
---|
136 | LOGICAL :: give_help = .FALSE.
|
---|
137 | LOGICAL :: do_adj = .TRUE.
|
---|
138 | LOGICAL :: lfile_exist = .FALSE.
|
---|
139 | LOGICAL :: ranchk = .TRUE.
|
---|
140 | LOGICAL :: compress = .FALSE.
|
---|
141 | LOGICAL :: checksat = .FALSE.
|
---|
142 | LOGICAL :: new_op = .FALSE.
|
---|
143 | LOGICAL :: direct_ion = .FALSE.
|
---|
144 | LOGICAL :: use_247L = .FALSE.
|
---|
145 |
|
---|
146 | CHARACTER(len = 4096), DIMENSION(:), ALLOCATABLE :: ifiles
|
---|
147 | CHARACTER(len = 4096) :: ofile = 'bg2ro.nc'
|
---|
148 | CHARACTER(len = 4096) :: lfile
|
---|
149 | CHARACTER(len = 256) :: buffer
|
---|
150 | CHARACTER(len = 4) :: istr
|
---|
151 | CHARACTER(len = 6) :: nstr
|
---|
152 |
|
---|
153 | !-------------------------------------------------------------------------------
|
---|
154 | ! 2. Default settings
|
---|
155 | !-------------------------------------------------------------------------------
|
---|
156 |
|
---|
157 | CALL message_set_routine ( 'ropp_fm_bg2ro_1d' )
|
---|
158 |
|
---|
159 | CALL message(msg_noin, '')
|
---|
160 | CALL message(msg_noin, &
|
---|
161 | '-----------------------------------------------------------------------')
|
---|
162 | CALL message(msg_noin, &
|
---|
163 | ' ROPP Forward Model' )
|
---|
164 | CALL message(msg_noin, &
|
---|
165 | '-----------------------------------------------------------------------')
|
---|
166 | CALL message(msg_noin, '')
|
---|
167 |
|
---|
168 | !-------------------------------------------------------------------------------
|
---|
169 | ! 3. Command line arguments
|
---|
170 | !-------------------------------------------------------------------------------
|
---|
171 |
|
---|
172 | argc = iargc()
|
---|
173 | i = 1
|
---|
174 | n_files = 0
|
---|
175 | ALLOCATE(ifiles(argc))
|
---|
176 |
|
---|
177 | geop_min = 200.0_wp
|
---|
178 | geop_max = 60000.0_wp
|
---|
179 | n_geop = 300
|
---|
180 |
|
---|
181 | DO WHILE(i <= argc)
|
---|
182 | CALL getarg(i, buffer)
|
---|
183 | SELECT CASE (buffer)
|
---|
184 | CASE('-o') ! Output file name (netCDF output)
|
---|
185 | CALL getarg(i+1, buffer)
|
---|
186 | ofile = buffer
|
---|
187 | i = i + 1
|
---|
188 | CASE ('-l') ! Use level structure defined here
|
---|
189 | CALL getarg(i+1, buffer)
|
---|
190 | lfile = buffer
|
---|
191 | i = i + 1
|
---|
192 | lfile_exist = .TRUE.
|
---|
193 | CASE ('-f') ! Perform forward model only
|
---|
194 | do_adj = .FALSE.
|
---|
195 | CASE ('-use_logp') ! Use log(pressure) for FM
|
---|
196 | state%use_logp = .TRUE.
|
---|
197 | CASE ('-use_logq') ! Use log(shum) for FM
|
---|
198 | state%use_logq = .TRUE.
|
---|
199 | CASE ('-comp') ! Non ideal gas switch
|
---|
200 | compress = .TRUE.
|
---|
201 | CASE ('-check_qsat') ! Check against saturation
|
---|
202 | checksat = .TRUE.
|
---|
203 | CASE ('-new_op') ! New interpolation
|
---|
204 | new_op = .TRUE.
|
---|
205 | CASE ('-direct_ion') ! Model L1 and L2 bangles directly
|
---|
206 | direct_ion = .TRUE.
|
---|
207 | CASE ('--no-ranchk') ! Disable rangecheck; for experts only
|
---|
208 | CALL message ( msg_warn, "Range checking is disabled" )
|
---|
209 | ranchk = .FALSE. ! Do not document as a user option.
|
---|
210 | CASE ('-247L', '-247l', '-247') ! Output refrac and bangle on standard 247L
|
---|
211 | use_247L = .TRUE.
|
---|
212 | CASE ('-zmin', '-Zmin', '-ZMIN') ! Min refrac geopotential
|
---|
213 | CALL getarg(i+1, buffer)
|
---|
214 | READ(buffer, *) geop_min
|
---|
215 | i = i + 1
|
---|
216 | CASE ('-zmax', '-Zmax', '-ZMAX') ! Max refrac geopotential
|
---|
217 | CALL getarg(i+1, buffer)
|
---|
218 | READ(buffer, *) geop_max
|
---|
219 | i = i + 1
|
---|
220 | CASE ('-nz', '-Nz', '-NZ') ! Number of refractivity levels
|
---|
221 | CALL getarg(i+1, buffer)
|
---|
222 | READ(buffer, *) n_geop
|
---|
223 | i = i + 1
|
---|
224 | CASE('-d') ! Additional diagnostic mode
|
---|
225 | msg_MODE = VerboseMode
|
---|
226 | CASE('-h', '--help', '?') ! Help
|
---|
227 | give_help = .TRUE.
|
---|
228 | CASE('-v', '-V', '--version') ! Version information
|
---|
229 | CALL version_info()
|
---|
230 | CALL EXIT(msg_exit_ok)
|
---|
231 | CASE default ! Input file name
|
---|
232 | IF ( buffer(1:1) /= '-' ) THEN
|
---|
233 | n_files = n_files + 1
|
---|
234 | ifiles(n_files) = buffer
|
---|
235 | END IF
|
---|
236 | END SELECT
|
---|
237 | i = i + 1
|
---|
238 | END DO
|
---|
239 |
|
---|
240 | IF ( n_files == 0 .AND. .NOT. give_help ) &
|
---|
241 | CALL message ( msg_error, "No input file(s) specified" )
|
---|
242 |
|
---|
243 | IF (argc == 0 .OR. n_files == 0 .OR. give_help) THEN
|
---|
244 | CALL usage()
|
---|
245 | CALL EXIT(msg_exit_status)
|
---|
246 | ENDIF
|
---|
247 |
|
---|
248 | !-------------------------------------------------------------------------------
|
---|
249 | ! 4. Remove pre-existing output file
|
---|
250 | !-------------------------------------------------------------------------------
|
---|
251 |
|
---|
252 | CALL file_delete(ofile, idummy)
|
---|
253 |
|
---|
254 | !-------------------------------------------------------------------------------
|
---|
255 | ! 4. Set default units
|
---|
256 | !-------------------------------------------------------------------------------
|
---|
257 |
|
---|
258 | CALL ropp_fm_set_units(ro_data)
|
---|
259 |
|
---|
260 | !-------------------------------------------------------------------------------
|
---|
261 | ! 5. Loop over all input files
|
---|
262 | !-------------------------------------------------------------------------------
|
---|
263 |
|
---|
264 | DO k = 1, n_files
|
---|
265 |
|
---|
266 | !-------------------------------------------------------------------------------
|
---|
267 | ! 6. Loop over all profiles
|
---|
268 | !-------------------------------------------------------------------------------
|
---|
269 |
|
---|
270 | n_profiles = ropp_io_nrec(ifiles(k))
|
---|
271 |
|
---|
272 | DO i = 1, n_profiles
|
---|
273 |
|
---|
274 | WRITE(istr, '(i4)') i
|
---|
275 | WRITE(nstr, '(i6)') n_profiles
|
---|
276 | CALL message(msg_noin, '')
|
---|
277 | CALL message(msg_info, "Processing profile " // istr // " of " // nstr )
|
---|
278 |
|
---|
279 | !-------------------------------------------------------------------------------
|
---|
280 | ! 7. Read data
|
---|
281 | !-------------------------------------------------------------------------------
|
---|
282 |
|
---|
283 | CALL ropp_io_read(ro_data, ifiles(k), rec = i, ranchk = ranchk)
|
---|
284 |
|
---|
285 | CALL message(msg_info, "(" // TRIM(ro_data%occ_id) // ") \n")
|
---|
286 |
|
---|
287 | IF (lfile_exist) THEN
|
---|
288 |
|
---|
289 | CALL ropp_io_read(l_data, lfile, ranchk=ranchk)
|
---|
290 |
|
---|
291 | ro_data%dtocc = l_data%dtocc
|
---|
292 | ro_data%georef = l_data%georef
|
---|
293 | ro_data%lev1b = l_data%lev1b
|
---|
294 | ro_data%lev2a = l_data%lev2a
|
---|
295 |
|
---|
296 | CALL ropp_io_free(l_data)
|
---|
297 |
|
---|
298 | ENDIF
|
---|
299 |
|
---|
300 | IF (direct_ion) THEN
|
---|
301 |
|
---|
302 | ro_data%lev2c%direct_ion = .TRUE.
|
---|
303 |
|
---|
304 | CALL ropp_fm_iono_set_default(ro_data)
|
---|
305 |
|
---|
306 | END IF
|
---|
307 |
|
---|
308 | !-------------------------------------------------------------------------------
|
---|
309 | ! 8. Copy data in RO structure to state and refrac obs vectors
|
---|
310 | !-------------------------------------------------------------------------------
|
---|
311 |
|
---|
312 | IF (checksat) state%check_qsat = .TRUE. ! Switch on check against saturation
|
---|
313 |
|
---|
314 | CALL ropp_fm_roprof2state(ro_data, state)
|
---|
315 |
|
---|
316 | IF (compress) state%non_ideal = .TRUE. ! Switch on non-ideal gas compressibility option
|
---|
317 |
|
---|
318 | IF (new_op) THEN
|
---|
319 | state%new_ref_op = .TRUE. ! Use new refrac interpolation
|
---|
320 | state%new_bangle_op = .TRUE. ! Use new bangle interpolation
|
---|
321 | ENDIF
|
---|
322 |
|
---|
323 | IF (ro_data%lev2a%Npoints > 0) THEN
|
---|
324 | CALL ropp_fm_roprof2obs(ro_data, obs_refrac) ! Set to obs levels
|
---|
325 | obs_refrac%refrac(:) = ropp_MDFV
|
---|
326 | ELSE
|
---|
327 | IF (use_247L) THEN
|
---|
328 | CALL set_obs_levels_refrac_247(ro_data, obs_refrac, state) ! Pre-defined levels
|
---|
329 | ELSE
|
---|
330 | CALL set_obs_levels_refrac(ro_data, obs_refrac, &
|
---|
331 | geop_min=geop_min, geop_max=geop_max, n_geop=n_geop) ! Uniformly spaced levels
|
---|
332 | ENDIF
|
---|
333 | ENDIF
|
---|
334 |
|
---|
335 | !-------------------------------------------------------------------------------
|
---|
336 | ! 9. Calculate refractivity and its gradient
|
---|
337 | !-------------------------------------------------------------------------------
|
---|
338 |
|
---|
339 | IF (state%state_ok) THEN
|
---|
340 |
|
---|
341 | IF (state%new_ref_op) THEN
|
---|
342 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
---|
343 | ELSE
|
---|
344 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
---|
345 | END IF
|
---|
346 |
|
---|
347 | IF (do_adj) THEN
|
---|
348 | ALLOCATE(gradient_refrac(SIZE(obs_refrac%refrac),SIZE(state%state)))
|
---|
349 | CALL ropp_fm_refrac_1d_grad(state, obs_refrac, gradient_refrac)
|
---|
350 | ENDIF
|
---|
351 |
|
---|
352 | ENDIF
|
---|
353 |
|
---|
354 | !-------------------------------------------------------------------------------
|
---|
355 | ! 10. Copy data in RO and refrac structure to bending angle obs vector
|
---|
356 | !-------------------------------------------------------------------------------
|
---|
357 |
|
---|
358 | IF (ro_data%lev1b%Npoints > 0) THEN
|
---|
359 | CALL ropp_fm_roprof2obs(ro_data, obs_bangle) !!set to obs levels
|
---|
360 | obs_bangle%bangle(:) = ropp_MDFV
|
---|
361 | ELSE
|
---|
362 | CALL set_obs_levels_bangle(state, ro_data, obs_refrac, obs_bangle) !default
|
---|
363 | END IF
|
---|
364 |
|
---|
365 | !-------------------------------------------------------------------------------
|
---|
366 | ! 11. Calculate bending angle and its gradient
|
---|
367 | !-------------------------------------------------------------------------------
|
---|
368 |
|
---|
369 | IF (state%state_ok) THEN
|
---|
370 |
|
---|
371 | CALL ropp_fm_bangle_1d(state, obs_bangle)
|
---|
372 |
|
---|
373 | IF (do_adj .AND. (.NOT. direct_ion)) THEN
|
---|
374 | ALLOCATE(gradient_bangle(SIZE(obs_bangle%bangle),SIZE(state%state)))
|
---|
375 | CALL ropp_fm_bangle_1d_grad(state, obs_bangle, gradient_bangle)
|
---|
376 | END IF
|
---|
377 |
|
---|
378 | ENDIF
|
---|
379 |
|
---|
380 | !-------------------------------------------------------------------------------
|
---|
381 | ! 12. Copy simulated observations to RO structure and write data
|
---|
382 | !-------------------------------------------------------------------------------
|
---|
383 |
|
---|
384 | CALL ropp_fm_obs2roprof(obs_refrac, ro_data)
|
---|
385 |
|
---|
386 | CALL ropp_fm_obs2roprof(obs_bangle, ro_data)
|
---|
387 |
|
---|
388 | IF (state%state_ok) THEN
|
---|
389 |
|
---|
390 | IF (do_adj) THEN
|
---|
391 | CALL ropp_io_addvar(ro_data, &
|
---|
392 | name = "gradient_refrac", &
|
---|
393 | long_name = &
|
---|
394 | "Gradient of the refractivity forward model", &
|
---|
395 | units = "1", &
|
---|
396 | range = (/MINVAL(gradient_refrac), &
|
---|
397 | MAXVAL(gradient_refrac)/), &
|
---|
398 | DATA = gradient_refrac)
|
---|
399 | ENDIF
|
---|
400 |
|
---|
401 | IF (do_adj .AND. (.NOT. direct_ion)) THEN
|
---|
402 | CALL ropp_io_addvar(ro_data, &
|
---|
403 | name = "gradient_bangle" , &
|
---|
404 | long_name = &
|
---|
405 | "Gradient of the bending angle forward model", &
|
---|
406 | units = "rad", &
|
---|
407 | range = (/MINVAL(gradient_bangle), &
|
---|
408 | MAXVAL(gradient_bangle)/), &
|
---|
409 | DATA = gradient_bangle)
|
---|
410 | ENDIF
|
---|
411 |
|
---|
412 | !-------------------------------------------------------------------------------
|
---|
413 | ! 13. Update RO structure with computed state vector variables
|
---|
414 | !-------------------------------------------------------------------------------
|
---|
415 |
|
---|
416 | CALL ropp_fm_state2roprof(state, ro_data)
|
---|
417 |
|
---|
418 | END IF
|
---|
419 |
|
---|
420 | !-------------------------------------------------------------------------------
|
---|
421 | ! 14. Write data
|
---|
422 | !-------------------------------------------------------------------------------
|
---|
423 |
|
---|
424 | IF (direct_ion) CALL ropp_fm_iono_unpack(ro_data)
|
---|
425 |
|
---|
426 | CALL ropp_io_write(ro_data, ofile, append=.TRUE., ranchk=ranchk)
|
---|
427 |
|
---|
428 | !-------------------------------------------------------------------------------
|
---|
429 | ! 15. Clean up
|
---|
430 | !-------------------------------------------------------------------------------
|
---|
431 |
|
---|
432 | IF (state%state_ok .AND. do_adj) THEN
|
---|
433 | DEALLOCATE (gradient_refrac)
|
---|
434 | ENDIF
|
---|
435 |
|
---|
436 | IF (state%state_ok .AND. do_adj .AND. (.NOT. direct_ion)) THEN
|
---|
437 | DEALLOCATE (gradient_bangle)
|
---|
438 | ENDIF
|
---|
439 |
|
---|
440 | CALL ropp_fm_free(state)
|
---|
441 | CALL ropp_fm_free(obs_refrac)
|
---|
442 | CALL ropp_fm_free(obs_bangle)
|
---|
443 | CALL ropp_io_free(ro_data)
|
---|
444 |
|
---|
445 | END DO
|
---|
446 |
|
---|
447 | END DO
|
---|
448 |
|
---|
449 | CALL EXIT(msg_exit_status)
|
---|
450 |
|
---|
451 | CONTAINS
|
---|
452 |
|
---|
453 | !-------------------------------------------------------------------------------
|
---|
454 | ! 16a. Calculate uniformly spaced observation levels for refractivity
|
---|
455 | !-------------------------------------------------------------------------------
|
---|
456 |
|
---|
457 | SUBROUTINE set_obs_levels_refrac(ro_data, obs_refrac, &
|
---|
458 | geop_min, geop_max, n_geop)
|
---|
459 | !
|
---|
460 | ! n_geop uniformly spaced geopotential heights between geop_min and geop_max (gpm).
|
---|
461 | !
|
---|
462 |
|
---|
463 | ! 16a.1 Declarations
|
---|
464 | ! -----------------
|
---|
465 |
|
---|
466 | USE typesizes, ONLY: wp => EightByteReal
|
---|
467 | USE ropp_io_types
|
---|
468 | USE ropp_fm
|
---|
469 |
|
---|
470 | IMPLICIT NONE
|
---|
471 |
|
---|
472 | ! Input/Output variables
|
---|
473 | TYPE(ROprof) :: ro_data
|
---|
474 | TYPE(Obs1dRefrac) :: obs_refrac
|
---|
475 | REAL(wp), OPTIONAL :: geop_min
|
---|
476 | REAL(wp), OPTIONAL :: geop_max
|
---|
477 | INTEGER, OPTIONAL :: n_geop
|
---|
478 |
|
---|
479 | ! Local variables
|
---|
480 | REAL(wp) :: zmin, zmax
|
---|
481 | INTEGER :: i, nz
|
---|
482 | CHARACTER(len=256) :: routine
|
---|
483 |
|
---|
484 | CALL message_get_routine(routine)
|
---|
485 | CALL message_set_routine('set_obs_levels_refrac')
|
---|
486 |
|
---|
487 | ! 16a. Vertical geopotential height levels between geop_min and geop_max
|
---|
488 | ! ----------------------------------------------------------------------
|
---|
489 |
|
---|
490 | zmin = 200.0_wp
|
---|
491 | IF ( PRESENT(geop_min) ) zmin = geop_min
|
---|
492 |
|
---|
493 | zmax = 60.0e3_wp
|
---|
494 | IF ( PRESENT(geop_max) ) zmax = geop_max
|
---|
495 |
|
---|
496 | nz = 300
|
---|
497 | IF ( PRESENT(n_geop) ) nz = n_geop
|
---|
498 |
|
---|
499 | IF ( (zmin >= zmax) .OR. (n_geop <= 1) ) THEN
|
---|
500 | CALL message(msg_warn, 'Invalid geop_min, geop_max or n_geop' // &
|
---|
501 | ' ... resetting all to default values')
|
---|
502 | zmin = 200.0_wp
|
---|
503 | zmax = 60000.0_wp
|
---|
504 | nz = 300
|
---|
505 | END IF
|
---|
506 |
|
---|
507 | ALLOCATE(obs_refrac%refrac(nz))
|
---|
508 | ALLOCATE(obs_refrac%geop(nz))
|
---|
509 | ALLOCATE(obs_refrac%weights(nz))
|
---|
510 |
|
---|
511 | obs_refrac%refrac(:) = 0.0_wp
|
---|
512 | obs_refrac%geop(:) = (/ (zmin+(i-1)*(zmax-zmin)/REAL(nz-1,wp), i=1,nz) /)
|
---|
513 | obs_refrac%weights(:) = 1.0_wp
|
---|
514 | obs_refrac%lon = ro_data%GEOref%lon
|
---|
515 | obs_refrac%lat = ro_data%GEOref%lat
|
---|
516 |
|
---|
517 | CALL message_set_routine(routine)
|
---|
518 |
|
---|
519 | END SUBROUTINE set_obs_levels_refrac
|
---|
520 |
|
---|
521 | !-------------------------------------------------------------------------------
|
---|
522 | ! 16b. Calculate standard 247 observation levels for refractivity
|
---|
523 | !-------------------------------------------------------------------------------
|
---|
524 |
|
---|
525 | SUBROUTINE set_obs_levels_refrac_247(ro_data, obs_refrac, state)
|
---|
526 | !
|
---|
527 | ! 247 geopotential height levels, going up to about 60 km, chosen in such a
|
---|
528 | ! way that the resulting impact heights match the 'standard' ones in
|
---|
529 | ! impact_height_eum_247 in ropp_fm/common/ropp_fm_levels.f90
|
---|
530 | !
|
---|
531 | ! 16b.1 Declarations
|
---|
532 | ! -----------------
|
---|
533 |
|
---|
534 | USE typesizes, ONLY: wp => EightByteReal
|
---|
535 | USE ropp_io_types
|
---|
536 | USE ropp_fm
|
---|
537 |
|
---|
538 | IMPLICIT NONE
|
---|
539 |
|
---|
540 | TYPE(ROprof) :: ro_data
|
---|
541 | TYPE(Obs1dRefrac) :: obs_refrac, obs_refrac2
|
---|
542 | TYPE(State1dFM) :: state
|
---|
543 |
|
---|
544 | INTEGER, PARAMETER :: n=247
|
---|
545 | REAL(wp), DIMENSION(n) :: impact_height
|
---|
546 | REAL(wp), DIMENSION(n) :: tmp
|
---|
547 | REAL(wp), PARAMETER :: refrac_surface_default=300.0_wp
|
---|
548 | REAL(wp), PARAMETER :: max_refrac=400.0_wp
|
---|
549 | REAL(wp) :: refrac_surface
|
---|
550 | REAL(wp), PARAMETER :: tol=1.0e-3_wp ! Demand < 1mm diffs
|
---|
551 | REAL(wp) :: roc, und
|
---|
552 | INTEGER, PARAMETER :: max_iter=500
|
---|
553 | INTEGER :: iter, imin
|
---|
554 | CHARACTER(LEN=3) :: smax_iter
|
---|
555 | CHARACTER(LEN=256) :: routine
|
---|
556 |
|
---|
557 | ! 16b.2 Initialisations
|
---|
558 | ! ---------------------
|
---|
559 |
|
---|
560 | CALL message_get_routine(routine)
|
---|
561 | CALL message_set_routine('set_obs_levels_refrac_247')
|
---|
562 |
|
---|
563 | impact_height = impact_height_eum_247 ! The particular 247L set
|
---|
564 |
|
---|
565 | ALLOCATE(obs_refrac%refrac(n))
|
---|
566 | ALLOCATE(obs_refrac%geop(n))
|
---|
567 | ALLOCATE(obs_refrac%weights(n))
|
---|
568 |
|
---|
569 | ALLOCATE(obs_refrac2%refrac(n))
|
---|
570 | ALLOCATE(obs_refrac2%geop(n))
|
---|
571 | ALLOCATE(obs_refrac2%weights(n))
|
---|
572 |
|
---|
573 | ! 16b.3 Vertical geopotential height levels
|
---|
574 | ! -----------------------------------------
|
---|
575 |
|
---|
576 | ! We seek solutions h_i of
|
---|
577 | ! (nr = ) (1 + 1e-6 N(Z(h_i)))*(h_i + RoC + und) = a_i + RoC
|
---|
578 | ! where a_i are the given impact heights, RoC is the radius of curvature
|
---|
579 | ! and und is the undulation. h_i is the geometric height;
|
---|
580 | ! Z_i is the geopotential height. Non-linear because N depends on h.
|
---|
581 | ! Simple iteration converges to a solution (slowly).
|
---|
582 | ! When geop_refrac is below the lowest state refrac, the refracs are
|
---|
583 | ! (now) missing data. In such cases, replace the missing refracs with ones
|
---|
584 | ! calculated with the old refrac scheme with this nullification switched off.
|
---|
585 | ! Because the same principle is applied in set_obs_levels_bangle, the
|
---|
586 | ! resulting impact heights are still good.
|
---|
587 |
|
---|
588 | ! 16b.4 Generate radius of curvature
|
---|
589 | ! ----------------------------------
|
---|
590 |
|
---|
591 | IF ( ro_data%GEOref%roc > ropp_MDTV ) THEN
|
---|
592 | roc = ro_data%GEOref%roc
|
---|
593 | ELSE
|
---|
594 | CALL message (msg_warn, 'RoC missing from data structure ... ' // &
|
---|
595 | 'setting equal to effective radius')
|
---|
596 | roc = R_eff(ro_data%GEOref%lat) ! Maybe +21km? See RSR 14.
|
---|
597 | ENDIF
|
---|
598 |
|
---|
599 | ! 16b.5 Generate undulation
|
---|
600 | ! -------------------------
|
---|
601 |
|
---|
602 | IF ( ro_data%GEOref%undulation > ropp_MDTV ) THEN
|
---|
603 | und = ro_data%GEOref%undulation
|
---|
604 | ELSE
|
---|
605 | CALL message(msg_warn, "Undulation missing ... will assume to " // &
|
---|
606 | "be zero when calculating geopotential heights.")
|
---|
607 | und = 0.0_wp
|
---|
608 | ENDIF
|
---|
609 |
|
---|
610 | ! 16b.6 Initialise
|
---|
611 | ! ----------------
|
---|
612 |
|
---|
613 | IF ( (state%temp(1) > ropp_MDTV) .AND. (state%pres(1) > ropp_MDTV) ) THEN
|
---|
614 | refrac_surface = kappa1 * state%pres(1) / state%temp(1) ! roughly
|
---|
615 | ELSE
|
---|
616 | refrac_surface = refrac_surface_default
|
---|
617 | END IF
|
---|
618 |
|
---|
619 | obs_refrac%geop = ((impact_height + roc)/(1.0_wp + 1.0e-6_wp*refrac_surface)) - &
|
---|
620 | (roc + und) ! roughly
|
---|
621 |
|
---|
622 | CALL ropp_fm_refrac_1d(state, obs_refrac, nonull=.TRUE.) ! Initialise with the old interp scheme sans missing data
|
---|
623 |
|
---|
624 | ! 16b.7 Iterate on GPH
|
---|
625 | ! --------------------
|
---|
626 |
|
---|
627 | iter = 0
|
---|
628 |
|
---|
629 | DO
|
---|
630 |
|
---|
631 | tmp = ((impact_height + roc)/(1.0_wp + 1.0e-6_wp*obs_refrac%refrac)) - &
|
---|
632 | (roc + und) ! geometric height
|
---|
633 |
|
---|
634 | obs_refrac%geop = geometric2geopotential(ro_data%GEOref%lat, tmp)
|
---|
635 |
|
---|
636 | IF ( state%new_ref_op ) THEN
|
---|
637 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
---|
638 | ELSE
|
---|
639 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
---|
640 | END IF
|
---|
641 |
|
---|
642 | IF ( COUNT(obs_refrac%refrac <= ropp_MDTV) > 0 ) THEN ! rederive approximately some zapped refracs
|
---|
643 |
|
---|
644 | obs_refrac2 = obs_refrac
|
---|
645 |
|
---|
646 | CALL ropp_fm_refrac_1d(state, obs_refrac2, nonull=.TRUE.) ! Recalculate sans missing data
|
---|
647 |
|
---|
648 | WHERE (obs_refrac%refrac <= ropp_MDTV) &
|
---|
649 | obs_refrac%refrac = obs_refrac2%refrac
|
---|
650 |
|
---|
651 | END IF
|
---|
652 |
|
---|
653 | WHERE (obs_refrac%refrac < ropp_ZERO) obs_refrac%refrac = ropp_ZERO
|
---|
654 |
|
---|
655 | WHERE (obs_refrac%refrac > max_refrac) obs_refrac%refrac = max_refrac
|
---|
656 |
|
---|
657 | tmp = (1.0_wp + 1.0e-6_wp*obs_refrac%refrac)*(tmp + roc + und) - &
|
---|
658 | (impact_height + roc) ! residual
|
---|
659 |
|
---|
660 | IF ( MAXVAL(ABS(tmp)) < tol ) EXIT
|
---|
661 |
|
---|
662 | iter = iter + 1
|
---|
663 |
|
---|
664 | IF ( iter > max_iter ) THEN
|
---|
665 | WRITE (smax_iter, '(i3)') max_iter
|
---|
666 | CALL message(msg_fatal, 'GPH iteration failed to converge in ' // &
|
---|
667 | smax_iter // ' iterations')
|
---|
668 | END IF
|
---|
669 |
|
---|
670 | ENDDO
|
---|
671 |
|
---|
672 | WRITE (smax_iter, '(i3)') iter
|
---|
673 | CALL message(msg_diag, 'GPH iteration converged in ' // &
|
---|
674 | smax_iter // ' iterations')
|
---|
675 |
|
---|
676 | ! 16b.8 Set other elements of obs_refrac structure
|
---|
677 | ! ------------------------------------------------
|
---|
678 |
|
---|
679 | obs_refrac%refrac = 0.0_wp ! Refrac will be calculated in the main program
|
---|
680 | obs_refrac%weights = 1.0_wp
|
---|
681 | obs_refrac%lon = ro_data%GEOref%lon
|
---|
682 | obs_refrac%lat = ro_data%GEOref%lat
|
---|
683 |
|
---|
684 | ! 16b.9 Clean up
|
---|
685 | ! --------------
|
---|
686 |
|
---|
687 | CALL ropp_fm_free(obs_refrac2)
|
---|
688 |
|
---|
689 | CALL message_set_routine(routine)
|
---|
690 |
|
---|
691 | END SUBROUTINE set_obs_levels_refrac_247
|
---|
692 |
|
---|
693 |
|
---|
694 | !-------------------------------------------------------------------------------
|
---|
695 | ! 17. Calculate obs levels for bending angle (consistent with obs_refrac)
|
---|
696 | !-------------------------------------------------------------------------------
|
---|
697 |
|
---|
698 | SUBROUTINE set_obs_levels_bangle(state, ro_data, obs_refrac, obs_bangle)
|
---|
699 |
|
---|
700 | ! 17.1 Declarations
|
---|
701 | ! -----------------
|
---|
702 |
|
---|
703 | USE typesizes, ONLY: wp => EightByteReal
|
---|
704 | USE geodesy
|
---|
705 | USE ropp_io_types
|
---|
706 | USE ropp_fm
|
---|
707 |
|
---|
708 | IMPLICIT NONE
|
---|
709 |
|
---|
710 | TYPE(ROprof) :: ro_data
|
---|
711 | TYPE(Obs1dRefrac) :: obs_refrac, obs_refrac2
|
---|
712 | TYPE(Obs1dbangle) :: obs_bangle
|
---|
713 | TYPE(State1dFM) :: state
|
---|
714 |
|
---|
715 | REAL(wp), DIMENSION(:), ALLOCATABLE :: tmp
|
---|
716 |
|
---|
717 | INTEGER :: n, imin
|
---|
718 | REAL(wp), PARAMETER :: max_refrac=400.0_wp
|
---|
719 |
|
---|
720 | CHARACTER(LEN=256) :: routine
|
---|
721 |
|
---|
722 | CALL message_get_routine(routine)
|
---|
723 | CALL message_set_routine('set_obs_levels_bangle')
|
---|
724 |
|
---|
725 | ! 17.2 Allocate arrays
|
---|
726 | ! --------------------
|
---|
727 |
|
---|
728 | n = SIZE(obs_refrac%geop)
|
---|
729 |
|
---|
730 | obs_bangle%n_L1 = n
|
---|
731 |
|
---|
732 | ALLOCATE(tmp(n))
|
---|
733 |
|
---|
734 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
---|
735 | ALLOCATE(obs_bangle%bangle(n))
|
---|
736 | ALLOCATE(obs_bangle%impact(n))
|
---|
737 | ALLOCATE(obs_bangle%weights(n))
|
---|
738 | ELSE
|
---|
739 | ALLOCATE(obs_bangle%bangle(2*n))
|
---|
740 | ALLOCATE(obs_bangle%impact(2*n))
|
---|
741 | ALLOCATE(obs_bangle%weights(2*n))
|
---|
742 | ENDIF
|
---|
743 |
|
---|
744 | ALLOCATE(obs_refrac2%refrac(n))
|
---|
745 | ALLOCATE(obs_refrac2%geop(n))
|
---|
746 | ALLOCATE(obs_refrac2%weights(n))
|
---|
747 |
|
---|
748 | ! 17.3 Calculate refractivities
|
---|
749 | ! -----------------------------
|
---|
750 |
|
---|
751 | IF ( state%new_ref_op ) THEN
|
---|
752 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
---|
753 | ELSE
|
---|
754 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
---|
755 | END IF
|
---|
756 |
|
---|
757 | IF ( COUNT(obs_refrac%refrac <= ropp_MDTV) > 0 ) THEN ! rederive approximately some zapped refracs
|
---|
758 |
|
---|
759 | obs_refrac2 = obs_refrac
|
---|
760 |
|
---|
761 | CALL ropp_fm_refrac_1d(state, obs_refrac2, nonull=.TRUE.) ! Estimate sans missing data
|
---|
762 |
|
---|
763 | WHERE (obs_refrac%refrac <= ropp_MDTV) &
|
---|
764 | obs_refrac%refrac = obs_refrac2%refrac
|
---|
765 |
|
---|
766 | END IF
|
---|
767 |
|
---|
768 | WHERE (obs_refrac%refrac < ropp_ZERO) obs_refrac%refrac = ropp_ZERO
|
---|
769 |
|
---|
770 | WHERE (obs_refrac%refrac > max_refrac) obs_refrac%refrac = max_refrac
|
---|
771 |
|
---|
772 | ! 17.4 Set scalar arguments of the observation vector
|
---|
773 | ! ---------------------------------------------------
|
---|
774 |
|
---|
775 | obs_bangle%g_sfc = gravity(ro_data%GEOref%lat)
|
---|
776 | obs_bangle%r_earth = R_eff(ro_data%GEOref%lat)
|
---|
777 | obs_bangle%undulation = ro_data%GEOref%undulation
|
---|
778 | obs_bangle%lon = ro_data%GEOref%lon
|
---|
779 | obs_bangle%lat = ro_data%GEOref%lat
|
---|
780 | obs_bangle%azimuth = ro_data%GEOref%azimuth
|
---|
781 |
|
---|
782 | IF ( ro_data%GEOref%roc > 0.0_wp ) THEN
|
---|
783 | obs_bangle%r_curve = ro_data%GEOref%roc
|
---|
784 | ELSE
|
---|
785 | CALL message (msg_warn, 'RoC missing from data structure ... ' // &
|
---|
786 | 'setting equal to effective radius')
|
---|
787 | obs_bangle%r_curve = obs_bangle%r_earth ! Maybe +21km? See RSR 14.
|
---|
788 | ENDIF
|
---|
789 |
|
---|
790 | ! 17.5 Calculate levels to coincide with the geopotential levels
|
---|
791 | ! --------------------------------------------------------------
|
---|
792 |
|
---|
793 | tmp = geopotential2geometric(ro_data%GEOref%lat, obs_refrac%geop) + &
|
---|
794 | obs_bangle%r_curve
|
---|
795 |
|
---|
796 | IF ( ro_data%GEOref%undulation > ropp_MDTV ) THEN
|
---|
797 | tmp = tmp + obs_bangle%undulation
|
---|
798 | ELSE
|
---|
799 | CALL message(msg_warn, "Undulation missing. Will assume to " // &
|
---|
800 | "be zero when calculating impact parameters.")
|
---|
801 | ENDIF
|
---|
802 |
|
---|
803 | tmp = (1.0_wp + obs_refrac%refrac*1.e-6_wp) * tmp
|
---|
804 |
|
---|
805 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
---|
806 | obs_bangle%impact = tmp
|
---|
807 | ELSE
|
---|
808 | obs_bangle%impact(1:n) = tmp
|
---|
809 | obs_bangle%impact(n+1:2*n) = tmp
|
---|
810 | ENDIF
|
---|
811 |
|
---|
812 | ! 17.6 Fill other arrays
|
---|
813 | ! ----------------------
|
---|
814 |
|
---|
815 | obs_bangle%bangle(:) = 0.0_wp
|
---|
816 | obs_bangle%weights(:) = 1.0_wp
|
---|
817 |
|
---|
818 | ! 17.7 Clean up
|
---|
819 | ! -------------
|
---|
820 |
|
---|
821 | IF ( state%new_ref_op ) THEN
|
---|
822 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
---|
823 | ELSE
|
---|
824 | CALL ropp_fm_refrac_1d(state, obs_refrac) ! Regenerate avec missing data
|
---|
825 | END IF
|
---|
826 |
|
---|
827 | DEALLOCATE(tmp)
|
---|
828 |
|
---|
829 | CALL ropp_fm_free(obs_refrac2)
|
---|
830 |
|
---|
831 | CALL message_set_routine(routine)
|
---|
832 |
|
---|
833 | END SUBROUTINE set_obs_levels_bangle
|
---|
834 |
|
---|
835 | !-------------------------------------------------------------------------------
|
---|
836 | ! 18. Usage information
|
---|
837 | !-------------------------------------------------------------------------------
|
---|
838 |
|
---|
839 | SUBROUTINE usage()
|
---|
840 | PRINT *, 'Purpose:'
|
---|
841 | PRINT *, ' Bending angles and refractivity forward model'
|
---|
842 | PRINT *, 'Usage:'
|
---|
843 | PRINT *, ' > ropp_fm_bg2ro_1d [<options>] <input_file(s)>'
|
---|
844 | PRINT *, 'Options:'
|
---|
845 | PRINT *, ' -o <output_file> name of ROPP netCDF output file'
|
---|
846 | PRINT *, ' -l <levels_file> optional name of (observation) file'
|
---|
847 | PRINT *, ' (non-multi) containing output level information'
|
---|
848 | PRINT *, ' -f forward model only, no gradient calculation'
|
---|
849 | PRINT *, ' -use_logp use log(pressure) for forward model'
|
---|
850 | PRINT *, ' -use_logq use log(spec humidity) for forward model'
|
---|
851 | PRINT *, ' -comp include non ideal gas compressibility'
|
---|
852 | PRINT *, ' -check_qsat include check against saturation'
|
---|
853 | PRINT *, ' -new_op use alternative refrac and bangle interpolation'
|
---|
854 | PRINT *, ' -direct_ion model L1 and L2 directly'
|
---|
855 | PRINT *, ' -247L output refrac and bangle on standard 247L'
|
---|
856 | PRINT *, ' -zmin <geop_min> minimum refractivity geopotential (gpm)'
|
---|
857 | PRINT *, ' -zmax <geop_max> maximum refractivity geopotential (gpm)'
|
---|
858 | PRINT *, ' -nz <n_geop> number of uniformly spaced refractivity geopotentials (gpm)'
|
---|
859 | PRINT *, ' -d output additional diagnostics'
|
---|
860 | PRINT *, ' -h this help'
|
---|
861 | PRINT *, ' -v version information'
|
---|
862 | PRINT *, ''
|
---|
863 | END SUBROUTINE usage
|
---|
864 |
|
---|
865 | !-------------------------------------------------------------------------------
|
---|
866 | ! 19. Version information
|
---|
867 | !-------------------------------------------------------------------------------
|
---|
868 |
|
---|
869 | SUBROUTINE version_info()
|
---|
870 | CHARACTER (LEN=40) :: version
|
---|
871 | version = ropp_fm_version()
|
---|
872 | PRINT *, 'ropp_fm_bg2ro_1d - Bending angles and refractivity forward model.'
|
---|
873 | PRINT *, ''
|
---|
874 | PRINT *, 'This program is part of ROPP (FM) Release ' // TRIM(version)
|
---|
875 | PRINT *, ''
|
---|
876 | END SUBROUTINE version_info
|
---|
877 |
|
---|
878 | END PROGRAM ropp_fm_bg2ro_1d
|
---|