UFO
ufo_groundgnss_metoffice_utils_mod.F90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! (C) British Crown Copyright 2020 Met Office
3 !
4 ! This software is licensed under the terms of the Apache Licence Version 2.0
5 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 !-------------------------------------------------------------------------------
7 
9 
10 !use iso_c_binding
11 use fckit_log_module, only: fckit_log
12 use kinds, only: kind_real
13 
14 ! Generic routines from elsewhere in jedi
15 use missing_values_mod
16 use ufo_constants_mod, only: &
17  rd, & ! Gas constant for dry air
18  grav, & ! Gravitational field strength
19  n_alpha, & ! Refractivity constant a
20  n_beta ! Refractivity constant b
21 
22 implicit none
23 public :: ops_groundgnss_ztd
25 REAL(kind_real), PARAMETER :: refrac_scale = 1.0e-6
26 private
27 
28 contains
29 
30 !-------------------------------------------------------------------------------
31 ! Ground based GNSS Observation operator
32 !-------------------------------------------------------------------------------
33 SUBROUTINE ops_groundgnss_ztd (nlevq, &
34  refrac, &
35  zb, &
36  zStation, &
37  Model_ZTD)
38 
39 IMPLICIT NONE
40 
41  INTEGER, INTENT(IN) :: nlevq ! no. of temperature/theta levels
42  REAL(kind_real), INTENT(IN) :: refrac(:) ! refractivty
43  REAL(kind_real), INTENT(IN) :: zb(:) ! The geometric height of the model theta levels
44  REAL(kind_real), INTENT(IN) :: zstation ! Station heights
45  REAL(kind_real), INTENT(INOUT) :: model_ztd ! Model background ZTD
46 
47 
48  REAL(kind_real) :: localzenithdelay ! Zenith total delay
49  INTEGER :: level ! level iterator
50  REAL(kind_real) :: stationrefrac ! refrac at station
51  REAL(kind_real) :: c ! scale height
52  REAL(kind_real) :: const ! refrac constant
53  REAL(kind_real) :: term1 ! refrac term1
54  REAL(kind_real) :: term2 ! refrac term2
55  INTEGER :: lowest_level ! lowest height level
56 
57  !------------------------------------------------------------
58  ! Calculate the zenith delay for each layer and add to total
59  !------------------------------------------------------------
60 
61  stationrefrac = 0.0
62 
63  DO level = 1, nlevq
64  IF (zb(level) > zstation) THEN
65  lowest_level = level
66  EXIT
67  END IF
68  END DO
69 
70  ! Start at bottom level
71 
72  DO level = lowest_level, nlevq
73 
74  localzenithdelay = 0.0
75 
76  IF (level == lowest_level .AND. level /= 1) THEN
77 
78  ! If station lies above the lowest model level, interpolate refractivity
79  ! to station height
80 
81  c = (log(refrac(level) / refrac(level - 1))) / (zb(level - 1) - zb(level))
82  stationrefrac = refrac(level - 1) * exp(-c * (zstation - zb(level - 1)))
83  const = -stationrefrac / c * exp(c * zstation)
84  term1 = exp(-c * (zb(level)))
85  term2 = exp(-c * zstation)
86  localzenithdelay = refrac_scale * const * (term1 - term2)
87 
88  ELSE IF (level == 1) THEN
89 
90  ! If station lies below model level 1 (ie. the lowest level for which refractivity is
91  ! calculated, then use c from the first full layer, but integrate down to height of
92  ! station
93 
94  c = (log(refrac(level + 1) / refrac(level))) / (zb(level) - zb(level + 1))
95  const = -refrac(level) / c * exp(c * (zb(level)))
96  term1 = exp(-c * (zb(level + 1)))
97  term2 = exp(-c * zstation)
98  localzenithdelay = refrac_scale * const * (term1 - term2)
99 
100  ELSE IF (level <= nlevq .AND. level > 2) THEN
101 
102  ! If not at top level
103 
104  c = (log(refrac(level) / refrac(level - 1))) / (zb(level - 1) - zb(level))
105  const = -refrac(level - 1) / c * exp(c * (zb(level - 1)))
106  term1 = exp(-c * (zb(level)))
107  term2 = exp(-c * (zb(level - 1)))
108  localzenithdelay = refrac_scale * const * (term1 - term2)
109 
110  END IF
111 
112  model_ztd = model_ztd + localzenithdelay
113  END DO
114 END SUBROUTINE ops_groundgnss_ztd
115 
116 
118  nlevq, &
119  za, &
120  zb, &
121  TopCorrection)
122 
123  IMPLICIT NONE
124 
125  REAL(kind_real), INTENT(IN) :: p(:) ! Pressure on pressure (rho) levels
126  INTEGER, INTENT(IN) :: nlevq ! no. of temperature/theta levels
127  REAL(kind_real), INTENT(IN) :: za(:) ! heights of pressure (rho) levels
128  REAL(kind_real), INTENT(IN) :: zb(:) ! Heights of temperature/theta levels
129  REAL(kind_real), INTENT(INOUT) :: topcorrection ! ZTD Top of atmos correction
130 
131 
132  INTEGER :: level ! Loop counter
133  REAL(kind_real) :: pn(nlevq) ! Pressure on theta levels
134  REAL(kind_real) :: pwt1 ! Weighting variable
135  REAL(kind_real) :: pwt2 ! Weighting variable
136  REAL(kind_real) :: tcconstant ! Top correction constant
137  REAL(kind_real), PARAMETER :: hpa_to_pa = 100.0 ! hPa to Pascal conversion
138 
139 
140  DO level = 1, nlevq
141 
142  pwt1 = (za(level + 1) - zb(level)) / (za(level + 1) - za(level))
143  pwt2 = 1.0 - pwt1
144 
145  pn(level) = exp(pwt1 * log(p(level)) + pwt2 * log(p(level + 1)))
146 
147  END DO
148 
149  tcconstant = (refrac_scale * n_alpha * rd)/ (hpa_to_pa * grav)
150 
151  topcorrection = tcconstant * pn(nlevq)
152 
153 END SUBROUTINE ops_groundgnss_topcorrection
154 
real(kind_real), parameter, public rd
subroutine, public ops_groundgnss_topcorrection(P, nlevq, za, zb, TopCorrection)
subroutine, public ops_groundgnss_ztd(nlevq, refrac, zb, zStation, Model_ZTD)