| 1 | ! $Id: ropp_fm_bg2ro_1d.f90 4432 2015-01-19 14:26:46Z 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 | CHARACTER(len = 4) :: slev1b, slev2a
|
|---|
| 153 |
|
|---|
| 154 | !-------------------------------------------------------------------------------
|
|---|
| 155 | ! 2. Default settings
|
|---|
| 156 | !-------------------------------------------------------------------------------
|
|---|
| 157 |
|
|---|
| 158 | CALL message_set_routine ( 'ropp_fm_bg2ro_1d' )
|
|---|
| 159 |
|
|---|
| 160 | CALL message(msg_noin, '')
|
|---|
| 161 | CALL message(msg_noin, &
|
|---|
| 162 | '-----------------------------------------------------------------------')
|
|---|
| 163 | CALL message(msg_noin, &
|
|---|
| 164 | ' ROPP Forward Model' )
|
|---|
| 165 | CALL message(msg_noin, &
|
|---|
| 166 | '-----------------------------------------------------------------------')
|
|---|
| 167 | CALL message(msg_noin, '')
|
|---|
| 168 |
|
|---|
| 169 | !-------------------------------------------------------------------------------
|
|---|
| 170 | ! 3. Command line arguments
|
|---|
| 171 | !-------------------------------------------------------------------------------
|
|---|
| 172 |
|
|---|
| 173 | argc = iargc()
|
|---|
| 174 | i = 1
|
|---|
| 175 | n_files = 0
|
|---|
| 176 | ALLOCATE(ifiles(argc))
|
|---|
| 177 |
|
|---|
| 178 | geop_min = 200.0_wp
|
|---|
| 179 | geop_max = 60000.0_wp
|
|---|
| 180 | n_geop = 300
|
|---|
| 181 |
|
|---|
| 182 | DO WHILE(i <= argc)
|
|---|
| 183 | CALL getarg(i, buffer)
|
|---|
| 184 | SELECT CASE (buffer)
|
|---|
| 185 | CASE('-o') ! Output file name (netCDF output)
|
|---|
| 186 | CALL getarg(i+1, buffer)
|
|---|
| 187 | ofile = buffer
|
|---|
| 188 | i = i + 1
|
|---|
| 189 | CASE ('-l') ! Use level structure defined here
|
|---|
| 190 | CALL getarg(i+1, buffer)
|
|---|
| 191 | lfile = buffer
|
|---|
| 192 | i = i + 1
|
|---|
| 193 | lfile_exist = .TRUE.
|
|---|
| 194 | CASE ('-f') ! Perform forward model only
|
|---|
| 195 | do_adj = .FALSE.
|
|---|
| 196 | CASE ('-use_logp') ! Use log(pressure) for FM
|
|---|
| 197 | state%use_logp = .TRUE.
|
|---|
| 198 | CASE ('-use_logq') ! Use log(shum) for FM
|
|---|
| 199 | state%use_logq = .TRUE.
|
|---|
| 200 | CASE ('-comp') ! Non ideal gas switch
|
|---|
| 201 | compress = .TRUE.
|
|---|
| 202 | CASE ('-check_qsat') ! Check against saturation
|
|---|
| 203 | checksat = .TRUE.
|
|---|
| 204 | CASE ('-new_op') ! New interpolation
|
|---|
| 205 | new_op = .TRUE.
|
|---|
| 206 | CASE ('-direct_ion') ! Model L1 and L2 bangles directly
|
|---|
| 207 | direct_ion = .TRUE.
|
|---|
| 208 | CASE ('--no-ranchk') ! Disable rangecheck; for experts only
|
|---|
| 209 | CALL message ( msg_warn, "Range checking is disabled" )
|
|---|
| 210 | ranchk = .FALSE. ! Do not document as a user option.
|
|---|
| 211 | CASE ('-247L', '-247l', '-247') ! Output refrac and bangle on standard 247L
|
|---|
| 212 | use_247L = .TRUE.
|
|---|
| 213 | CASE ('-zmin', '-Zmin', '-ZMIN') ! Min refrac geopotential
|
|---|
| 214 | CALL getarg(i+1, buffer)
|
|---|
| 215 | READ(buffer, *) geop_min
|
|---|
| 216 | i = i + 1
|
|---|
| 217 | CASE ('-zmax', '-Zmax', '-ZMAX') ! Max refrac geopotential
|
|---|
| 218 | CALL getarg(i+1, buffer)
|
|---|
| 219 | READ(buffer, *) geop_max
|
|---|
| 220 | i = i + 1
|
|---|
| 221 | CASE ('-nz', '-Nz', '-NZ') ! Number of refractivity levels
|
|---|
| 222 | CALL getarg(i+1, buffer)
|
|---|
| 223 | READ(buffer, *) n_geop
|
|---|
| 224 | i = i + 1
|
|---|
| 225 | CASE('-d') ! Additional diagnostic mode
|
|---|
| 226 | msg_MODE = VerboseMode
|
|---|
| 227 | CASE('-h', '--help', '?') ! Help
|
|---|
| 228 | give_help = .TRUE.
|
|---|
| 229 | CASE('-v', '-V', '--version') ! Version information
|
|---|
| 230 | CALL version_info()
|
|---|
| 231 | CALL EXIT(msg_exit_ok)
|
|---|
| 232 | CASE default ! Input file name
|
|---|
| 233 | IF ( buffer(1:1) /= '-' ) THEN
|
|---|
| 234 | n_files = n_files + 1
|
|---|
| 235 | ifiles(n_files) = buffer
|
|---|
| 236 | END IF
|
|---|
| 237 | END SELECT
|
|---|
| 238 | i = i + 1
|
|---|
| 239 | END DO
|
|---|
| 240 |
|
|---|
| 241 | IF ( n_files == 0 .AND. .NOT. give_help ) &
|
|---|
| 242 | CALL message ( msg_error, "No input file(s) specified" )
|
|---|
| 243 |
|
|---|
| 244 | IF (argc == 0 .OR. n_files == 0 .OR. give_help) THEN
|
|---|
| 245 | CALL usage()
|
|---|
| 246 | CALL EXIT(msg_exit_status)
|
|---|
| 247 | END IF
|
|---|
| 248 |
|
|---|
| 249 | !-------------------------------------------------------------------------------
|
|---|
| 250 | ! 4. Remove pre-existing output file
|
|---|
| 251 | !-------------------------------------------------------------------------------
|
|---|
| 252 |
|
|---|
| 253 | CALL file_delete(ofile, idummy)
|
|---|
| 254 |
|
|---|
| 255 | !-------------------------------------------------------------------------------
|
|---|
| 256 | ! 4. Set default units
|
|---|
| 257 | !-------------------------------------------------------------------------------
|
|---|
| 258 |
|
|---|
| 259 | CALL ropp_fm_set_units(ro_data)
|
|---|
| 260 |
|
|---|
| 261 | !-------------------------------------------------------------------------------
|
|---|
| 262 | ! 5. Loop over all input files
|
|---|
| 263 | !-------------------------------------------------------------------------------
|
|---|
| 264 |
|
|---|
| 265 | DO k = 1, n_files
|
|---|
| 266 |
|
|---|
| 267 | !-------------------------------------------------------------------------------
|
|---|
| 268 | ! 6. Loop over all profiles
|
|---|
| 269 | !-------------------------------------------------------------------------------
|
|---|
| 270 |
|
|---|
| 271 | n_profiles = ropp_io_nrec(ifiles(k))
|
|---|
| 272 |
|
|---|
| 273 | DO i = 1, n_profiles
|
|---|
| 274 |
|
|---|
| 275 | WRITE(istr, '(i4)') i
|
|---|
| 276 | WRITE(nstr, '(i6)') n_profiles
|
|---|
| 277 | CALL message(msg_noin, '')
|
|---|
| 278 | CALL message(msg_info, "Processing profile " // istr // " of " // nstr )
|
|---|
| 279 |
|
|---|
| 280 | !-------------------------------------------------------------------------------
|
|---|
| 281 | ! 7. Read data
|
|---|
| 282 | !-------------------------------------------------------------------------------
|
|---|
| 283 |
|
|---|
| 284 | CALL ropp_io_read(ro_data, ifiles(k), rec = i, ranchk = ranchk)
|
|---|
| 285 |
|
|---|
| 286 | CALL message(msg_info, "(" // TRIM(ro_data%occ_id) // ") \n")
|
|---|
| 287 |
|
|---|
| 288 | IF (lfile_exist) THEN
|
|---|
| 289 |
|
|---|
| 290 | CALL message(msg_info, "Reading levels information from " // lfile // " \n")
|
|---|
| 291 |
|
|---|
| 292 | CALL ropp_io_read(l_data, lfile, ranchk=ranchk)
|
|---|
| 293 |
|
|---|
| 294 | ro_data%dtocc = l_data%dtocc
|
|---|
| 295 | ro_data%georef = l_data%georef
|
|---|
| 296 | ro_data%lev1b = l_data%lev1b
|
|---|
| 297 | ro_data%lev2a = l_data%lev2a
|
|---|
| 298 |
|
|---|
| 299 | WRITE (slev1b, '(i4)') ro_data%lev1b%Npoints
|
|---|
| 300 | CALL message(msg_info, "There are " // slev1b // &
|
|---|
| 301 | " level 1b points in " // lfile // " \n")
|
|---|
| 302 |
|
|---|
| 303 | WRITE (slev2a, '(i4)') ro_data%lev2a%Npoints
|
|---|
| 304 | CALL message(msg_info, "There are " // slev2a // &
|
|---|
| 305 | " level 2a points in " // lfile // " \n")
|
|---|
| 306 |
|
|---|
| 307 | CALL ropp_io_free(l_data)
|
|---|
| 308 |
|
|---|
| 309 | END IF
|
|---|
| 310 |
|
|---|
| 311 | IF (direct_ion) THEN
|
|---|
| 312 |
|
|---|
| 313 | ro_data%lev2c%direct_ion = .TRUE.
|
|---|
| 314 |
|
|---|
| 315 | CALL ropp_fm_iono_set_default(ro_data)
|
|---|
| 316 |
|
|---|
| 317 | END IF
|
|---|
| 318 |
|
|---|
| 319 | !-------------------------------------------------------------------------------
|
|---|
| 320 | ! 8. Copy data in RO structure to state and refrac obs vectors
|
|---|
| 321 | !-------------------------------------------------------------------------------
|
|---|
| 322 |
|
|---|
| 323 | IF (checksat) state%check_qsat = .TRUE. ! Switch on check against saturation
|
|---|
| 324 |
|
|---|
| 325 | CALL ropp_fm_roprof2state(ro_data, state)
|
|---|
| 326 |
|
|---|
| 327 | IF (compress) state%non_ideal = .TRUE. ! Switch on non-ideal gas compressibility option
|
|---|
| 328 |
|
|---|
| 329 | IF (new_op) THEN
|
|---|
| 330 | state%new_ref_op = .TRUE. ! Use new refrac interpolation
|
|---|
| 331 | state%new_bangle_op = .TRUE. ! Use new bangle interpolation
|
|---|
| 332 | END IF
|
|---|
| 333 |
|
|---|
| 334 | IF (ro_data%lev2a%Npoints > 0) THEN
|
|---|
| 335 | CALL ropp_fm_roprof2obs(ro_data, obs_refrac) ! Set to obs levels
|
|---|
| 336 | obs_refrac%refrac(:) = ropp_MDFV
|
|---|
| 337 | ELSE
|
|---|
| 338 | IF (use_247L) THEN
|
|---|
| 339 | CALL set_obs_levels_refrac_247(ro_data, obs_refrac, state) ! Pre-defined levels
|
|---|
| 340 | ELSE
|
|---|
| 341 | CALL set_obs_levels_refrac(ro_data, obs_refrac, &
|
|---|
| 342 | geop_min=geop_min, geop_max=geop_max, n_geop=n_geop) ! Uniformly spaced levels
|
|---|
| 343 | END IF
|
|---|
| 344 | END IF
|
|---|
| 345 |
|
|---|
| 346 | !-------------------------------------------------------------------------------
|
|---|
| 347 | ! 9. Calculate refractivity and its gradient
|
|---|
| 348 | !-------------------------------------------------------------------------------
|
|---|
| 349 |
|
|---|
| 350 | IF (state%state_ok) THEN
|
|---|
| 351 |
|
|---|
| 352 | IF (state%new_ref_op) THEN
|
|---|
| 353 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
|---|
| 354 | ELSE
|
|---|
| 355 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
|---|
| 356 | END IF
|
|---|
| 357 |
|
|---|
| 358 | IF (do_adj) THEN
|
|---|
| 359 | ALLOCATE(gradient_refrac(SIZE(obs_refrac%refrac),SIZE(state%state)))
|
|---|
| 360 | CALL ropp_fm_refrac_1d_grad(state, obs_refrac, gradient_refrac)
|
|---|
| 361 | END IF
|
|---|
| 362 |
|
|---|
| 363 | END IF
|
|---|
| 364 |
|
|---|
| 365 | !-------------------------------------------------------------------------------
|
|---|
| 366 | ! 10. Copy data in RO and refrac structure to bending angle obs vector
|
|---|
| 367 | !-------------------------------------------------------------------------------
|
|---|
| 368 |
|
|---|
| 369 | IF (ro_data%lev1b%Npoints > 0) THEN
|
|---|
| 370 | CALL ropp_fm_roprof2obs(ro_data, obs_bangle) ! Set to obs levels
|
|---|
| 371 | obs_bangle%bangle(:) = ropp_MDFV
|
|---|
| 372 | ELSE
|
|---|
| 373 | IF (use_247L) THEN
|
|---|
| 374 | CALL set_obs_levels_bangle_247(ro_data, obs_bangle) ! Pre-defined levels
|
|---|
| 375 | ELSE
|
|---|
| 376 | CALL set_obs_levels_bangle(state, ro_data, obs_refrac, obs_bangle) !default
|
|---|
| 377 | END IF
|
|---|
| 378 | END IF
|
|---|
| 379 |
|
|---|
| 380 | !-------------------------------------------------------------------------------
|
|---|
| 381 | ! 11. Calculate bending angle and its gradient
|
|---|
| 382 | !-------------------------------------------------------------------------------
|
|---|
| 383 |
|
|---|
| 384 | IF (state%state_ok) THEN
|
|---|
| 385 |
|
|---|
| 386 | CALL ropp_fm_bangle_1d(state, obs_bangle)
|
|---|
| 387 |
|
|---|
| 388 | IF (do_adj .AND. (.NOT. direct_ion)) THEN
|
|---|
| 389 | ALLOCATE(gradient_bangle(SIZE(obs_bangle%bangle),SIZE(state%state)))
|
|---|
| 390 | CALL ropp_fm_bangle_1d_grad(state, obs_bangle, gradient_bangle)
|
|---|
| 391 | END IF
|
|---|
| 392 |
|
|---|
| 393 | END IF
|
|---|
| 394 |
|
|---|
| 395 | !-------------------------------------------------------------------------------
|
|---|
| 396 | ! 12. Copy simulated observations to RO structure and write data
|
|---|
| 397 | !-------------------------------------------------------------------------------
|
|---|
| 398 |
|
|---|
| 399 | CALL ropp_fm_obs2roprof(obs_refrac, ro_data)
|
|---|
| 400 |
|
|---|
| 401 | CALL ropp_fm_obs2roprof(obs_bangle, ro_data)
|
|---|
| 402 |
|
|---|
| 403 | IF (state%state_ok) THEN
|
|---|
| 404 |
|
|---|
| 405 | IF (do_adj) THEN
|
|---|
| 406 | CALL ropp_io_addvar(ro_data, &
|
|---|
| 407 | name = "gradient_refrac", &
|
|---|
| 408 | long_name = &
|
|---|
| 409 | "Gradient of the refractivity forward model", &
|
|---|
| 410 | units = "1", &
|
|---|
| 411 | range = (/MINVAL(gradient_refrac), &
|
|---|
| 412 | MAXVAL(gradient_refrac)/), &
|
|---|
| 413 | DATA = gradient_refrac)
|
|---|
| 414 | END IF
|
|---|
| 415 |
|
|---|
| 416 | IF (do_adj .AND. (.NOT. direct_ion)) THEN
|
|---|
| 417 | CALL ropp_io_addvar(ro_data, &
|
|---|
| 418 | name = "gradient_bangle" , &
|
|---|
| 419 | long_name = &
|
|---|
| 420 | "Gradient of the bending angle forward model", &
|
|---|
| 421 | units = "rad", &
|
|---|
| 422 | range = (/MINVAL(gradient_bangle), &
|
|---|
| 423 | MAXVAL(gradient_bangle)/), &
|
|---|
| 424 | DATA = gradient_bangle)
|
|---|
| 425 | END IF
|
|---|
| 426 |
|
|---|
| 427 | !-------------------------------------------------------------------------------
|
|---|
| 428 | ! 13. Update RO structure with computed state vector variables
|
|---|
| 429 | !-------------------------------------------------------------------------------
|
|---|
| 430 |
|
|---|
| 431 | CALL ropp_fm_state2roprof(state, ro_data)
|
|---|
| 432 |
|
|---|
| 433 | END IF
|
|---|
| 434 |
|
|---|
| 435 | !-------------------------------------------------------------------------------
|
|---|
| 436 | ! 14. Write data
|
|---|
| 437 | !-------------------------------------------------------------------------------
|
|---|
| 438 |
|
|---|
| 439 | IF (direct_ion) CALL ropp_fm_iono_unpack(ro_data)
|
|---|
| 440 |
|
|---|
| 441 | CALL ropp_io_write(ro_data, ofile, append=.TRUE., ranchk=ranchk)
|
|---|
| 442 |
|
|---|
| 443 | !-------------------------------------------------------------------------------
|
|---|
| 444 | ! 15. Clean up
|
|---|
| 445 | !-------------------------------------------------------------------------------
|
|---|
| 446 |
|
|---|
| 447 | IF (state%state_ok .AND. do_adj) THEN
|
|---|
| 448 | DEALLOCATE (gradient_refrac)
|
|---|
| 449 | END IF
|
|---|
| 450 |
|
|---|
| 451 | IF (state%state_ok .AND. do_adj .AND. (.NOT. direct_ion)) THEN
|
|---|
| 452 | DEALLOCATE (gradient_bangle)
|
|---|
| 453 | END IF
|
|---|
| 454 |
|
|---|
| 455 | CALL ropp_fm_free(state)
|
|---|
| 456 | CALL ropp_fm_free(obs_refrac)
|
|---|
| 457 | CALL ropp_fm_free(obs_bangle)
|
|---|
| 458 | CALL ropp_io_free(ro_data)
|
|---|
| 459 |
|
|---|
| 460 | END DO
|
|---|
| 461 |
|
|---|
| 462 | END DO
|
|---|
| 463 |
|
|---|
| 464 | CALL EXIT(msg_exit_status)
|
|---|
| 465 |
|
|---|
| 466 | CONTAINS
|
|---|
| 467 |
|
|---|
| 468 | !-------------------------------------------------------------------------------
|
|---|
| 469 | ! 16a. Calculate uniformly spaced observation levels for refractivity
|
|---|
| 470 | !-------------------------------------------------------------------------------
|
|---|
| 471 |
|
|---|
| 472 | SUBROUTINE set_obs_levels_refrac(ro_data, obs_refrac, &
|
|---|
| 473 | geop_min, geop_max, n_geop)
|
|---|
| 474 | !
|
|---|
| 475 | ! n_geop uniformly spaced geopotential heights between geop_min and geop_max (gpm).
|
|---|
| 476 | !
|
|---|
| 477 |
|
|---|
| 478 | ! 16a.1 Declarations
|
|---|
| 479 | ! -----------------
|
|---|
| 480 |
|
|---|
| 481 | USE typesizes, ONLY: wp => EightByteReal
|
|---|
| 482 | USE ropp_io_types
|
|---|
| 483 | USE ropp_fm
|
|---|
| 484 |
|
|---|
| 485 | IMPLICIT NONE
|
|---|
| 486 |
|
|---|
| 487 | ! Input/Output variables
|
|---|
| 488 | TYPE(ROprof) :: ro_data
|
|---|
| 489 | TYPE(Obs1dRefrac) :: obs_refrac
|
|---|
| 490 | REAL(wp), OPTIONAL :: geop_min
|
|---|
| 491 | REAL(wp), OPTIONAL :: geop_max
|
|---|
| 492 | INTEGER, OPTIONAL :: n_geop
|
|---|
| 493 |
|
|---|
| 494 | ! Local variables
|
|---|
| 495 | REAL(wp) :: zmin, zmax
|
|---|
| 496 | INTEGER :: i, nz
|
|---|
| 497 | CHARACTER(len=256) :: routine
|
|---|
| 498 |
|
|---|
| 499 | CALL message_get_routine(routine)
|
|---|
| 500 | CALL message_set_routine('set_obs_levels_refrac')
|
|---|
| 501 |
|
|---|
| 502 | ! 16a. Vertical geopotential height levels between geop_min and geop_max
|
|---|
| 503 | ! ----------------------------------------------------------------------
|
|---|
| 504 |
|
|---|
| 505 | zmin = 200.0_wp
|
|---|
| 506 | IF ( PRESENT(geop_min) ) zmin = geop_min
|
|---|
| 507 |
|
|---|
| 508 | zmax = 60.0e3_wp
|
|---|
| 509 | IF ( PRESENT(geop_max) ) zmax = geop_max
|
|---|
| 510 |
|
|---|
| 511 | nz = 300
|
|---|
| 512 | IF ( PRESENT(n_geop) ) nz = n_geop
|
|---|
| 513 |
|
|---|
| 514 | IF ( (zmin >= zmax) .OR. (n_geop <= 1) ) THEN
|
|---|
| 515 | CALL message(msg_warn, 'Invalid geop_min, geop_max or n_geop' // &
|
|---|
| 516 | ' ... resetting all to default values')
|
|---|
| 517 | zmin = 200.0_wp
|
|---|
| 518 | zmax = 60000.0_wp
|
|---|
| 519 | nz = 300
|
|---|
| 520 | END IF
|
|---|
| 521 |
|
|---|
| 522 | ALLOCATE(obs_refrac%refrac(nz))
|
|---|
| 523 | ALLOCATE(obs_refrac%geop(nz))
|
|---|
| 524 | ALLOCATE(obs_refrac%weights(nz))
|
|---|
| 525 |
|
|---|
| 526 | obs_refrac%refrac(:) = 0.0_wp
|
|---|
| 527 | obs_refrac%geop(:) = (/ (zmin+(i-1)*(zmax-zmin)/REAL(nz-1, wp), i=1,nz) /)
|
|---|
| 528 | obs_refrac%weights(:) = 1.0_wp
|
|---|
| 529 | obs_refrac%lon = ro_data%GEOref%lon
|
|---|
| 530 | obs_refrac%lat = ro_data%GEOref%lat
|
|---|
| 531 |
|
|---|
| 532 | CALL message_set_routine(routine)
|
|---|
| 533 |
|
|---|
| 534 | END SUBROUTINE set_obs_levels_refrac
|
|---|
| 535 |
|
|---|
| 536 |
|
|---|
| 537 | !-------------------------------------------------------------------------------
|
|---|
| 538 | ! 16b. Calculate standard 247 observation levels for refractivity
|
|---|
| 539 | !-------------------------------------------------------------------------------
|
|---|
| 540 |
|
|---|
| 541 | SUBROUTINE set_obs_levels_refrac_247(ro_data, obs_refrac, state)
|
|---|
| 542 | !
|
|---|
| 543 | ! 247 geopotential height levels, going up to about 60 km, chosen in such a
|
|---|
| 544 | ! way that the resulting impact heights match the 'standard' ones in
|
|---|
| 545 | ! impact_height_eum_247 in ropp_fm/common/ropp_fm_levels.f90
|
|---|
| 546 | !
|
|---|
| 547 | ! 16b.1 Declarations
|
|---|
| 548 | ! -----------------
|
|---|
| 549 |
|
|---|
| 550 | USE typesizes, ONLY: wp => EightByteReal
|
|---|
| 551 | USE ropp_io_types
|
|---|
| 552 | USE ropp_fm
|
|---|
| 553 |
|
|---|
| 554 | IMPLICIT NONE
|
|---|
| 555 |
|
|---|
| 556 | TYPE(ROprof) :: ro_data
|
|---|
| 557 | TYPE(Obs1dRefrac) :: obs_refrac
|
|---|
| 558 | TYPE(State1dFM) :: state
|
|---|
| 559 |
|
|---|
| 560 | INTEGER, PARAMETER :: n=247
|
|---|
| 561 | REAL(wp), DIMENSION(n) :: impact_height
|
|---|
| 562 | REAL(wp), DIMENSION(n) :: tmp
|
|---|
| 563 | REAL(wp), PARAMETER :: refrac_surface_default=300.0_wp
|
|---|
| 564 | REAL(wp) :: refrac_surface
|
|---|
| 565 | REAL(wp), PARAMETER :: tol=1.0e-3_wp ! Demand < 1mm diffs
|
|---|
| 566 | REAL(wp) :: max_refrac
|
|---|
| 567 | REAL(wp) :: min_geop
|
|---|
| 568 | REAL(wp) :: roc, und, lat
|
|---|
| 569 | INTEGER, PARAMETER :: max_iter=1000
|
|---|
| 570 | INTEGER :: iter, imiss
|
|---|
| 571 | INTEGER :: lowest_refrac_index
|
|---|
| 572 |
|
|---|
| 573 | CHARACTER(LEN=3) :: smax_iter
|
|---|
| 574 | CHARACTER(LEN=256) :: routine
|
|---|
| 575 |
|
|---|
| 576 | ! 16b.2 Initialisations
|
|---|
| 577 | ! ---------------------
|
|---|
| 578 |
|
|---|
| 579 | CALL message_get_routine(routine)
|
|---|
| 580 | CALL message_set_routine('set_obs_levels_refrac_247')
|
|---|
| 581 |
|
|---|
| 582 | impact_height = impact_height_eum_247 ! The particular 247L set
|
|---|
| 583 |
|
|---|
| 584 | max_refrac = ro_data%lev2a%range%refrac(2)
|
|---|
| 585 |
|
|---|
| 586 | min_geop = ro_data%lev2b%range%geop(1)
|
|---|
| 587 |
|
|---|
| 588 | ALLOCATE(obs_refrac%refrac(n))
|
|---|
| 589 | ALLOCATE(obs_refrac%geop(n))
|
|---|
| 590 | ALLOCATE(obs_refrac%weights(n))
|
|---|
| 591 |
|
|---|
| 592 | ! 16b.3 Vertical geopotential height levels
|
|---|
| 593 | ! -----------------------------------------
|
|---|
| 594 |
|
|---|
| 595 | ! We seek solutions h_i of
|
|---|
| 596 | ! (nr = ) (1 + 1e-6 N(Z(h_i)))*(h_i + RoC + und) = a_i + RoC
|
|---|
| 597 | ! where a_i are the given impact heights, RoC is the radius of curvature
|
|---|
| 598 | ! and und is the undulation. h_i is the geometric height;
|
|---|
| 599 | ! Z_i is the geopotential height. Non-linear because N depends on Z.
|
|---|
| 600 | ! When geop_refrac is below the lowest state refrac, the refracs are
|
|---|
| 601 | ! (now) missing data. In such cases, replace the missing refracs with ones
|
|---|
| 602 | ! calculated with the old refrac scheme with this nullification switched off.
|
|---|
| 603 | ! Because the same principle is applied in set_obs_levels_bangle, the
|
|---|
| 604 | ! resulting impact heights are still good.
|
|---|
| 605 |
|
|---|
| 606 | ! 16b.4 Generate radius of curvature
|
|---|
| 607 | ! ----------------------------------
|
|---|
| 608 |
|
|---|
| 609 | IF ( ro_data%GEOref%roc > ropp_MDTV ) THEN
|
|---|
| 610 | roc = ro_data%GEOref%roc
|
|---|
| 611 | ELSE
|
|---|
| 612 | CALL message (msg_warn, 'RoC missing from data structure ... ' // &
|
|---|
| 613 | 'setting equal to effective radius')
|
|---|
| 614 | roc = R_eff(ro_data%GEOref%lat) ! Maybe +21km? See RSR 14.
|
|---|
| 615 | END IF
|
|---|
| 616 |
|
|---|
| 617 | ! 16b.5 Generate undulation
|
|---|
| 618 | ! -------------------------
|
|---|
| 619 |
|
|---|
| 620 | IF ( ro_data%GEOref%undulation > ropp_MDTV ) THEN
|
|---|
| 621 | und = ro_data%GEOref%undulation
|
|---|
| 622 | ELSE
|
|---|
| 623 | CALL message(msg_warn, "Undulation missing ... will assume to " // &
|
|---|
| 624 | "be zero when calculating geopotential heights.")
|
|---|
| 625 | und = 0.0_wp
|
|---|
| 626 | END IF
|
|---|
| 627 |
|
|---|
| 628 | ! 16b.6 Generate latitude
|
|---|
| 629 | ! -----------------------
|
|---|
| 630 |
|
|---|
| 631 | IF ( ro_data%GEOref%lat > ropp_MDTV ) THEN
|
|---|
| 632 | lat = ro_data%GEOref%lat
|
|---|
| 633 | ELSE
|
|---|
| 634 | CALL message(msg_warn, "Latitude missing ... will assume to " // &
|
|---|
| 635 | "be zero when calculating geopotential heights.")
|
|---|
| 636 | lat = 0.0_wp
|
|---|
| 637 | END IF
|
|---|
| 638 |
|
|---|
| 639 | ! 16b.7 Initialise
|
|---|
| 640 | ! ----------------
|
|---|
| 641 |
|
|---|
| 642 | IF ( (state%temp(1) > ropp_MDTV) .AND. (state%pres(1) > ropp_MDTV) ) THEN
|
|---|
| 643 | refrac_surface = kappa1 * state%pres(1) / state%temp(1) ! roughly
|
|---|
| 644 | ELSE
|
|---|
| 645 | refrac_surface = refrac_surface_default
|
|---|
| 646 | END IF
|
|---|
| 647 |
|
|---|
| 648 | obs_refrac%geop = ((impact_height + roc)/(1.0_wp + 1.0e-6_wp*refrac_surface)) - &
|
|---|
| 649 | (roc + und) ! roughly
|
|---|
| 650 |
|
|---|
| 651 | CALL ropp_fm_refrac_1d(state, obs_refrac, nonull=.TRUE.) ! Initialise with the old interp scheme sans missing data
|
|---|
| 652 |
|
|---|
| 653 | ! 16b.8 Iterate on GPH
|
|---|
| 654 | ! --------------------
|
|---|
| 655 |
|
|---|
| 656 | iter = 0
|
|---|
| 657 |
|
|---|
| 658 | DO
|
|---|
| 659 |
|
|---|
| 660 | tmp = ((impact_height + roc)/(1.0_wp + 1.0e-6_wp*obs_refrac%refrac)) - &
|
|---|
| 661 | (roc + und) ! geometric height
|
|---|
| 662 |
|
|---|
| 663 | obs_refrac%geop = geometric2geopotential(lat, tmp)
|
|---|
| 664 |
|
|---|
| 665 | IF ( state%new_ref_op ) THEN
|
|---|
| 666 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
|---|
| 667 | ELSE
|
|---|
| 668 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
|---|
| 669 | END IF
|
|---|
| 670 |
|
|---|
| 671 | IF ( ANY(obs_refrac%refrac <= ropp_MDTV) ) THEN ! rederive approximately the zapped refracs
|
|---|
| 672 |
|
|---|
| 673 | lowest_refrac_index = SUM( MINLOC( (/ (i, i=1,n) /), mask=obs_refrac%refrac>ropp_MDTV ) )
|
|---|
| 674 |
|
|---|
| 675 | IF ( (lowest_refrac_index > 1) .AND. (lowest_refrac_index < n) ) THEN
|
|---|
| 676 |
|
|---|
| 677 | DO imiss=lowest_refrac_index-1,1,-1
|
|---|
| 678 | obs_refrac%refrac(imiss) = obs_refrac%refrac(imiss+1) + &
|
|---|
| 679 | (obs_refrac%refrac(lowest_refrac_index) - obs_refrac%refrac(lowest_refrac_index+1))
|
|---|
| 680 | END DO
|
|---|
| 681 |
|
|---|
| 682 | tmp(1:lowest_refrac_index-1) = ((impact_height(1:lowest_refrac_index-1) + roc) / &
|
|---|
| 683 | (1.0_wp + 1.0e-6_wp*obs_refrac%refrac(1:lowest_refrac_index-1))) - &
|
|---|
| 684 | (roc + und) ! geometric height exactly right in this region
|
|---|
| 685 | obs_refrac%geop(1:lowest_refrac_index-1) = geometric2geopotential(lat, tmp(1:lowest_refrac_index-1))
|
|---|
| 686 |
|
|---|
| 687 | END IF
|
|---|
| 688 |
|
|---|
| 689 | END IF
|
|---|
| 690 |
|
|---|
| 691 | tmp = (1.0_wp + 1.0e-6_wp*obs_refrac%refrac)*(tmp + roc + und) - &
|
|---|
| 692 | (impact_height + roc) ! residual
|
|---|
| 693 |
|
|---|
| 694 | IF ( MAXVAL(ABS(tmp)) < tol ) EXIT
|
|---|
| 695 |
|
|---|
| 696 | iter = iter + 1
|
|---|
| 697 |
|
|---|
| 698 | IF ( iter > max_iter ) THEN
|
|---|
| 699 | WRITE (smax_iter, '(i3)') max_iter
|
|---|
| 700 | CALL message(msg_fatal, 'GPH iteration failed to converge in ' // &
|
|---|
| 701 | smax_iter // ' iterations')
|
|---|
| 702 | END IF
|
|---|
| 703 |
|
|---|
| 704 | WHERE ( obs_refrac%refrac > max_refrac ) obs_refrac%refrac = max_refrac
|
|---|
| 705 |
|
|---|
| 706 | WHERE ( obs_refrac%geop < min_geop ) obs_refrac%geop = min_geop
|
|---|
| 707 |
|
|---|
| 708 | END DO
|
|---|
| 709 |
|
|---|
| 710 | WRITE (smax_iter, '(i3)') iter
|
|---|
| 711 | CALL message(msg_diag, 'GPH iteration converged in ' // &
|
|---|
| 712 | smax_iter // ' iterations')
|
|---|
| 713 |
|
|---|
| 714 | ! 16b.9 Set other elements of obs_refrac structure
|
|---|
| 715 | ! ------------------------------------------------
|
|---|
| 716 |
|
|---|
| 717 | obs_refrac%refrac = 0.0_wp ! Refrac will be calculated in the main program
|
|---|
| 718 | obs_refrac%weights = 1.0_wp
|
|---|
| 719 | obs_refrac%lon = ro_data%GEOref%lon
|
|---|
| 720 | obs_refrac%lat = ro_data%GEOref%lat
|
|---|
| 721 |
|
|---|
| 722 | ! 16b.10 Clean up
|
|---|
| 723 | ! ---------------
|
|---|
| 724 |
|
|---|
| 725 | CALL message_set_routine(routine)
|
|---|
| 726 |
|
|---|
| 727 | END SUBROUTINE set_obs_levels_refrac_247
|
|---|
| 728 |
|
|---|
| 729 |
|
|---|
| 730 | !-------------------------------------------------------------------------------
|
|---|
| 731 | ! 17. Calculate obs levels for bending angle (consistent with obs_refrac)
|
|---|
| 732 | !-------------------------------------------------------------------------------
|
|---|
| 733 |
|
|---|
| 734 | SUBROUTINE set_obs_levels_bangle(state, ro_data, obs_refrac, obs_bangle)
|
|---|
| 735 |
|
|---|
| 736 | ! 17.1 Declarations
|
|---|
| 737 | ! -----------------
|
|---|
| 738 |
|
|---|
| 739 | USE typesizes, ONLY: wp => EightByteReal
|
|---|
| 740 | USE geodesy
|
|---|
| 741 | USE ropp_io_types
|
|---|
| 742 | USE ropp_fm
|
|---|
| 743 |
|
|---|
| 744 | IMPLICIT NONE
|
|---|
| 745 |
|
|---|
| 746 | TYPE(ROprof) :: ro_data
|
|---|
| 747 | TYPE(Obs1dRefrac) :: obs_refrac
|
|---|
| 748 | TYPE(Obs1dbangle) :: obs_bangle
|
|---|
| 749 | TYPE(State1dFM) :: state
|
|---|
| 750 |
|
|---|
| 751 | REAL(wp), DIMENSION(:), ALLOCATABLE :: tmp
|
|---|
| 752 | REAL(wp) :: max_refrac
|
|---|
| 753 | REAL(wp) :: min_geop
|
|---|
| 754 |
|
|---|
| 755 | INTEGER :: n, imiss
|
|---|
| 756 | INTEGER :: lowest_refrac_index
|
|---|
| 757 |
|
|---|
| 758 | CHARACTER(LEN=256) :: routine
|
|---|
| 759 |
|
|---|
| 760 | CALL message_get_routine(routine)
|
|---|
| 761 | CALL message_set_routine('set_obs_levels_bangle')
|
|---|
| 762 |
|
|---|
| 763 | ! 17.2 Allocate arrays
|
|---|
| 764 | ! --------------------
|
|---|
| 765 |
|
|---|
| 766 | max_refrac = ro_data%lev2a%range%refrac(2)
|
|---|
| 767 |
|
|---|
| 768 | min_geop = ro_data%lev2b%range%geop(1)
|
|---|
| 769 |
|
|---|
| 770 | n = SIZE(obs_refrac%geop)
|
|---|
| 771 |
|
|---|
| 772 | obs_bangle%n_L1 = n
|
|---|
| 773 |
|
|---|
| 774 | ALLOCATE(tmp(n))
|
|---|
| 775 |
|
|---|
| 776 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
|---|
| 777 | ALLOCATE(obs_bangle%bangle(n))
|
|---|
| 778 | ALLOCATE(obs_bangle%impact(n))
|
|---|
| 779 | ALLOCATE(obs_bangle%weights(n))
|
|---|
| 780 | ELSE
|
|---|
| 781 | ALLOCATE(obs_bangle%bangle(2*n))
|
|---|
| 782 | ALLOCATE(obs_bangle%impact(2*n))
|
|---|
| 783 | ALLOCATE(obs_bangle%weights(2*n))
|
|---|
| 784 | END IF
|
|---|
| 785 |
|
|---|
| 786 | ! 17.3 Calculate refractivities
|
|---|
| 787 | ! -----------------------------
|
|---|
| 788 |
|
|---|
| 789 | IF ( state%new_ref_op ) THEN
|
|---|
| 790 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
|---|
| 791 | ELSE
|
|---|
| 792 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
|---|
| 793 | END IF
|
|---|
| 794 |
|
|---|
| 795 | IF ( ANY(obs_refrac%refrac <= ropp_MDTV) ) THEN ! rederive approximately the zapped refracs
|
|---|
| 796 |
|
|---|
| 797 | lowest_refrac_index = SUM( MINLOC( (/ (i, i=1,n) /), mask=obs_refrac%refrac>ropp_MDTV ) )
|
|---|
| 798 |
|
|---|
| 799 | IF ( (lowest_refrac_index > 1) .AND. (lowest_refrac_index < n) ) THEN
|
|---|
| 800 |
|
|---|
| 801 | DO imiss=lowest_refrac_index-1,1,-1
|
|---|
| 802 | obs_refrac%refrac(imiss) = obs_refrac%refrac(imiss+1) + &
|
|---|
| 803 | (obs_refrac%refrac(lowest_refrac_index) - obs_refrac%refrac(lowest_refrac_index+1))
|
|---|
| 804 | END DO
|
|---|
| 805 |
|
|---|
| 806 | END IF
|
|---|
| 807 |
|
|---|
| 808 | END IF
|
|---|
| 809 |
|
|---|
| 810 | WHERE ( obs_refrac%refrac > max_refrac ) obs_refrac%refrac = max_refrac
|
|---|
| 811 |
|
|---|
| 812 | WHERE ( obs_refrac%geop < min_geop ) obs_refrac%geop = min_geop
|
|---|
| 813 |
|
|---|
| 814 | ! 17.4 Set scalar arguments of the observation vector
|
|---|
| 815 | ! ---------------------------------------------------
|
|---|
| 816 |
|
|---|
| 817 | obs_bangle%g_sfc = gravity(ro_data%GEOref%lat)
|
|---|
| 818 | obs_bangle%r_earth = R_eff(ro_data%GEOref%lat)
|
|---|
| 819 | obs_bangle%undulation = ro_data%GEOref%undulation
|
|---|
| 820 | obs_bangle%lon = ro_data%GEOref%lon
|
|---|
| 821 | obs_bangle%lat = ro_data%GEOref%lat
|
|---|
| 822 | obs_bangle%azimuth = ro_data%GEOref%azimuth
|
|---|
| 823 |
|
|---|
| 824 | IF ( ro_data%GEOref%roc > 0.0_wp ) THEN
|
|---|
| 825 | obs_bangle%r_curve = ro_data%GEOref%roc
|
|---|
| 826 | ELSE
|
|---|
| 827 | CALL message (msg_warn, 'RoC missing from data structure ... ' // &
|
|---|
| 828 | 'setting equal to effective radius')
|
|---|
| 829 | obs_bangle%r_curve = obs_bangle%r_earth ! Maybe +21km? See RSR 14.
|
|---|
| 830 | END IF
|
|---|
| 831 |
|
|---|
| 832 | ! 17.5 Calculate levels to coincide with the geopotential levels
|
|---|
| 833 | ! --------------------------------------------------------------
|
|---|
| 834 |
|
|---|
| 835 | tmp = geopotential2geometric(ro_data%GEOref%lat, obs_refrac%geop) + &
|
|---|
| 836 | obs_bangle%r_curve
|
|---|
| 837 |
|
|---|
| 838 | IF ( ro_data%GEOref%undulation > ropp_MDTV ) THEN
|
|---|
| 839 | tmp = tmp + obs_bangle%undulation
|
|---|
| 840 | ELSE
|
|---|
| 841 | CALL message(msg_warn, "Undulation missing. Will assume to " // &
|
|---|
| 842 | "be zero when calculating impact parameters.")
|
|---|
| 843 | END IF
|
|---|
| 844 |
|
|---|
| 845 | tmp = (1.0_wp + obs_refrac%refrac*1.e-6_wp) * tmp
|
|---|
| 846 |
|
|---|
| 847 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
|---|
| 848 | obs_bangle%impact = tmp
|
|---|
| 849 | ELSE
|
|---|
| 850 | obs_bangle%impact(1:n) = tmp
|
|---|
| 851 | obs_bangle%impact(n+1:2*n) = tmp
|
|---|
| 852 | END IF
|
|---|
| 853 |
|
|---|
| 854 | ! 17.6 Fill other arrays
|
|---|
| 855 | ! ----------------------
|
|---|
| 856 |
|
|---|
| 857 | obs_bangle%bangle(:) = 0.0_wp
|
|---|
| 858 | obs_bangle%weights(:) = 1.0_wp
|
|---|
| 859 |
|
|---|
| 860 | ! 17.7 Clean up
|
|---|
| 861 | ! -------------
|
|---|
| 862 |
|
|---|
| 863 | IF ( state%new_ref_op ) THEN ! Regenerate avec missing data
|
|---|
| 864 | CALL ropp_fm_refrac_1d_new(state, obs_refrac)
|
|---|
| 865 | ELSE
|
|---|
| 866 | CALL ropp_fm_refrac_1d(state, obs_refrac)
|
|---|
| 867 | END IF
|
|---|
| 868 |
|
|---|
| 869 | DEALLOCATE(tmp)
|
|---|
| 870 |
|
|---|
| 871 | CALL message_set_routine(routine)
|
|---|
| 872 |
|
|---|
| 873 | END SUBROUTINE set_obs_levels_bangle
|
|---|
| 874 |
|
|---|
| 875 |
|
|---|
| 876 | !-------------------------------------------------------------------------------
|
|---|
| 877 | ! 17b. Calculate standard 247 observation levels for bending angle
|
|---|
| 878 | !-------------------------------------------------------------------------------
|
|---|
| 879 |
|
|---|
| 880 | SUBROUTINE set_obs_levels_bangle_247(ro_data, obs_bangle)
|
|---|
| 881 |
|
|---|
| 882 | ! 17b.1 Declarations
|
|---|
| 883 | ! ------------------
|
|---|
| 884 |
|
|---|
| 885 | USE typesizes, ONLY: wp => EightByteReal
|
|---|
| 886 | USE geodesy
|
|---|
| 887 | USE ropp_io_types
|
|---|
| 888 | USE ropp_fm
|
|---|
| 889 |
|
|---|
| 890 | IMPLICIT NONE
|
|---|
| 891 |
|
|---|
| 892 | TYPE(ROprof) :: ro_data
|
|---|
| 893 | TYPE(Obs1dbangle) :: obs_bangle
|
|---|
| 894 |
|
|---|
| 895 | INTEGER, PARAMETER :: n=247
|
|---|
| 896 | REAL(wp), DIMENSION(n) :: impact_height
|
|---|
| 897 |
|
|---|
| 898 | CHARACTER(LEN=256) :: routine
|
|---|
| 899 |
|
|---|
| 900 | CALL message_get_routine(routine)
|
|---|
| 901 | CALL message_set_routine('set_obs_levels_bangle_247')
|
|---|
| 902 |
|
|---|
| 903 | ! 17b.2 Allocate arrays
|
|---|
| 904 | ! ---------------------
|
|---|
| 905 |
|
|---|
| 906 | obs_bangle%n_L1 = n
|
|---|
| 907 |
|
|---|
| 908 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
|---|
| 909 | ALLOCATE(obs_bangle%bangle(n))
|
|---|
| 910 | ALLOCATE(obs_bangle%impact(n))
|
|---|
| 911 | ALLOCATE(obs_bangle%weights(n))
|
|---|
| 912 | ELSE
|
|---|
| 913 | ALLOCATE(obs_bangle%bangle(2*n))
|
|---|
| 914 | ALLOCATE(obs_bangle%impact(2*n))
|
|---|
| 915 | ALLOCATE(obs_bangle%weights(2*n))
|
|---|
| 916 | END IF
|
|---|
| 917 |
|
|---|
| 918 | ! 17b.3 Define standard impact heights
|
|---|
| 919 | ! ------------------------------------
|
|---|
| 920 |
|
|---|
| 921 | impact_height = impact_height_eum_247 ! The particular 247L set
|
|---|
| 922 |
|
|---|
| 923 | ! 17b.4 Set scalar arguments of the observation vector
|
|---|
| 924 | ! ----------------------------------------------------
|
|---|
| 925 |
|
|---|
| 926 | obs_bangle%g_sfc = gravity(ro_data%GEOref%lat)
|
|---|
| 927 | obs_bangle%r_earth = R_eff(ro_data%GEOref%lat)
|
|---|
| 928 | obs_bangle%undulation = ro_data%GEOref%undulation
|
|---|
| 929 | obs_bangle%lon = ro_data%GEOref%lon
|
|---|
| 930 | obs_bangle%lat = ro_data%GEOref%lat
|
|---|
| 931 | obs_bangle%azimuth = ro_data%GEOref%azimuth
|
|---|
| 932 |
|
|---|
| 933 | IF ( ro_data%GEOref%roc > 0.0_wp ) THEN
|
|---|
| 934 | obs_bangle%r_curve = ro_data%GEOref%roc
|
|---|
| 935 | ELSE
|
|---|
| 936 | CALL message (msg_warn, 'RoC missing from data structure ... ' // &
|
|---|
| 937 | 'setting equal to effective radius')
|
|---|
| 938 | obs_bangle%r_curve = obs_bangle%r_earth ! Maybe +21km? See RSR 14.
|
|---|
| 939 | END IF
|
|---|
| 940 |
|
|---|
| 941 | ! 17b.5 Calculate impact parameters
|
|---|
| 942 | ! ---------------------------------
|
|---|
| 943 |
|
|---|
| 944 | IF ( .NOT. ro_data%Lev2c%direct_ion ) THEN
|
|---|
| 945 | obs_bangle%impact = impact_height + obs_bangle%r_curve
|
|---|
| 946 | ELSE
|
|---|
| 947 | obs_bangle%impact(1:n) = impact_height + obs_bangle%r_curve
|
|---|
| 948 | obs_bangle%impact(n+1:2*n) = impact_height + obs_bangle%r_curve
|
|---|
| 949 | END IF
|
|---|
| 950 |
|
|---|
| 951 | ! 17b.6 Fill other arrays
|
|---|
| 952 | ! -----------------------
|
|---|
| 953 |
|
|---|
| 954 | obs_bangle%bangle(:) = 0.0_wp
|
|---|
| 955 | obs_bangle%weights(:) = 1.0_wp
|
|---|
| 956 |
|
|---|
| 957 | ! 17b.7 Clean up
|
|---|
| 958 | ! --------------
|
|---|
| 959 |
|
|---|
| 960 | CALL message_set_routine(routine)
|
|---|
| 961 |
|
|---|
| 962 | END SUBROUTINE set_obs_levels_bangle_247
|
|---|
| 963 |
|
|---|
| 964 |
|
|---|
| 965 | !-------------------------------------------------------------------------------
|
|---|
| 966 | ! 18. Usage information
|
|---|
| 967 | !-------------------------------------------------------------------------------
|
|---|
| 968 |
|
|---|
| 969 | SUBROUTINE usage()
|
|---|
| 970 | PRINT *, 'Purpose:'
|
|---|
| 971 | PRINT *, ' Bending angles and refractivity forward model'
|
|---|
| 972 | PRINT *, 'Usage:'
|
|---|
| 973 | PRINT *, ' > ropp_fm_bg2ro_1d [<options>] <input_file(s)>'
|
|---|
| 974 | PRINT *, 'Options:'
|
|---|
| 975 | PRINT *, ' -o <output_file> name of ROPP netCDF output file'
|
|---|
| 976 | PRINT *, ' -l <levels_file> optional name of (observation) file'
|
|---|
| 977 | PRINT *, ' (non-multi) containing output level information'
|
|---|
| 978 | PRINT *, ' -f forward model only, no gradient calculation'
|
|---|
| 979 | PRINT *, ' -use_logp use log(pressure) for forward model'
|
|---|
| 980 | PRINT *, ' -use_logq use log(spec humidity) for forward model'
|
|---|
| 981 | PRINT *, ' -comp include non ideal gas compressibility'
|
|---|
| 982 | PRINT *, ' -check_qsat include check against saturation'
|
|---|
| 983 | PRINT *, ' -new_op use alternative refrac and bangle interpolation'
|
|---|
| 984 | PRINT *, ' -direct_ion model L1 and L2 directly'
|
|---|
| 985 | PRINT *, ' -247L output refrac and bangle on standard 247L'
|
|---|
| 986 | PRINT *, ' -zmin <geop_min> minimum refractivity geopotential (gpm)'
|
|---|
| 987 | PRINT *, ' -zmax <geop_max> maximum refractivity geopotential (gpm)'
|
|---|
| 988 | PRINT *, ' -nz <n_geop> number of uniformly spaced refractivity geopotentials (gpm)'
|
|---|
| 989 | PRINT *, ' -d output additional diagnostics'
|
|---|
| 990 | PRINT *, ' -h this help'
|
|---|
| 991 | PRINT *, ' -v version information'
|
|---|
| 992 | PRINT *, ''
|
|---|
| 993 | END SUBROUTINE usage
|
|---|
| 994 |
|
|---|
| 995 |
|
|---|
| 996 | !-------------------------------------------------------------------------------
|
|---|
| 997 | ! 19. Version information
|
|---|
| 998 | !-------------------------------------------------------------------------------
|
|---|
| 999 |
|
|---|
| 1000 | SUBROUTINE version_info()
|
|---|
| 1001 | CHARACTER (LEN=40) :: version
|
|---|
| 1002 | version = ropp_fm_version()
|
|---|
| 1003 | PRINT *, 'ropp_fm_bg2ro_1d - Bending angles and refractivity forward model.'
|
|---|
| 1004 | PRINT *, ''
|
|---|
| 1005 | PRINT *, 'This program is part of ROPP (FM) Release ' // TRIM(version)
|
|---|
| 1006 | PRINT *, ''
|
|---|
| 1007 | END SUBROUTINE version_info
|
|---|
| 1008 |
|
|---|
| 1009 |
|
|---|
| 1010 | END PROGRAM ropp_fm_bg2ro_1d
|
|---|