UFO
ufo_roobserror_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2017-2018 UCAR
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 
6 !> Fortran module to implement RO observational error
7 
9 use fckit_configuration_module, only: fckit_configuration
10 use kinds
12 use obsspace_mod
13 use oops_variables_mod
14 use missing_values_mod
16 use fckit_log_module, only : fckit_log
17 
18 implicit none
20 public :: ufo_roobserror_prior
21 public :: max_string
22 private
23 
24 ! ------------------------------------------------------------------------------
26  character(len=max_string) :: variable
27  character(len=max_string) :: errmodel
28  character(len=max_string) :: rmatrix_filename
29  character(len=max_string) :: err_variable
30  type(oops_variables), public :: obsvar
31  type(c_ptr) :: obsdb
32  integer :: n_horiz ! For ROPP-2D multiplier of the number of geovals
33 end type ufo_roobserror
34 
35 ! ------------------------------------------------------------------------------
36 contains
37 ! ------------------------------------------------------------------------------
38 
39 subroutine ufo_roobserror_create(self, obspace, f_conf)
40 use iso_c_binding
41 use oops_variables_mod
42 implicit none
43 type(ufo_roobserror), intent(inout) :: self
44 type(c_ptr), value, intent(in) :: obspace
45 type(fckit_configuration), intent(in) :: f_conf
46 character(len=:), allocatable :: str
47 
48 self%errmodel = "NBAM"
49 if (f_conf%has("errmodel")) then
50  call f_conf%get_or_die("errmodel",str)
51  self%errmodel = str
52 end if
53 
54 self % rmatrix_filename = ""
55 if (f_conf % has("rmatrix_filename")) then
56  call f_conf % get_or_die("rmatrix_filename", str)
57  self % rmatrix_filename = str
58 end if
59 
60 self % err_variable = ""
61 if (f_conf % has("err_variable")) then
62  call f_conf % get_or_die("err_variable", str)
63  self % err_variable = str
64 end if
65 
66 ! Get the number of extra geovals as a multiplier, default to 1
67 self % n_horiz = 1
68 if (f_conf % has("n_horiz")) then
69  call f_conf % get_or_die("n_horiz", self % n_horiz)
70 end if
71 
72 self%obsdb = obspace
73 
74 end subroutine ufo_roobserror_create
75 
76 ! ------------------------------------------------------------------------------
77 
78 subroutine ufo_roobserror_delete(self)
79 implicit none
80 type(ufo_roobserror), intent(inout) :: self
81 end subroutine ufo_roobserror_delete
82 
83 ! ------------------------------------------------------------------------------
84 
85 subroutine ufo_roobserror_prior(self, model_nobs, model_nlevs, air_temperature, &
86  geopotential_height)
87 
88 use fckit_log_module, only : fckit_log
89 use ufo_utils_mod, only: cmp_strings
90 
91 implicit none
92 
93 type(ufo_roobserror), intent(in) :: self
94 integer, intent(in) :: model_nobs
95 integer, intent(in) :: model_nlevs
96 real, intent(in) :: air_temperature(:,:)
97 real, intent(in) :: geopotential_height(:,:)
98 
99 integer :: nobs
100 real(kind_real), allocatable :: obsz(:), obslat(:)
101 integer, allocatable :: obssatid(:) ! Satellite identifier
102 integer, allocatable :: obsorigc(:) ! Originating centre number for each ob
103 real(kind_real), allocatable :: obsimpa(:) ! The observation impact alitude
104 real(kind_real), allocatable :: obsimph(:) ! The observation impact height
105 real(kind_real), allocatable :: obsimpp(:) ! The observation impact parameter
106 real(kind_real), allocatable :: obsgeoid(:) ! The geoid undulation at the observation location
107 real(kind_real), allocatable :: obslocr(:) ! The local radius of curvature at the observation location
108 real(kind_real), allocatable :: obsvalue(:)
109 real(kind_real), allocatable :: obserr(:)
110 integer(c_int), allocatable :: obssaid(:)
111 integer(c_int), allocatable :: qcflags(:)
112 real(kind_real) :: missing
113 character(max_string) :: err_msg
114 
115 missing = missing_value(missing)
116 nobs = obsspace_get_nlocs(self%obsdb)
117 allocate(qcflags(nobs))
118 allocate(obserr(nobs))
119 qcflags(:) = 0
120 
121 if (model_nobs /= nobs * self % n_horiz) then
122  write(err_msg, '(A,2I8)') 'nobs from model and observations must be equal', nobs, model_nobs
123  call abor1_ftn(err_msg)
124 end if
125 
126 ! read QC flags
127 call obsspace_get_db(self%obsdb, "FortranQC", trim(self%variable),qcflags )
128 
129 !-------------------------------
130 select case (trim(self%variable))
131 
132 !-------------------------------
133 case ("bending_angle")
134 
135  allocate(obsimpp(nobs))
136  allocate(obsgeoid(nobs))
137  allocate(obslocr(nobs))
138  allocate(obsimph(nobs))
139  allocate(obsimpa(nobs))
140  call obsspace_get_db(self%obsdb, "MetaData", "impact_parameter", obsimpp)
141  call obsspace_get_db(self%obsdb, "MetaData", "geoid_height_above_reference_ellipsoid",obsgeoid)
142  call obsspace_get_db(self%obsdb, "MetaData", "earth_radius_of_curvature", obslocr)
143  obsimph(:) = obsimpp(:) - obslocr(:)
144  obsimpa(:) = obsimpp(:) - obsgeoid(:) - obslocr(:)
145 
146  select case (trim(self%errmodel))
147  case ("NBAM")
148  allocate(obssaid(nobs))
149  allocate(obslat(nobs))
150  call obsspace_get_db(self%obsdb, "MetaData", "occulting_sat_id", obssaid)
151  call obsspace_get_db(self%obsdb, "MetaData", "latitude", obslat)
152  call bending_angle_obserr_nbam(obslat, obsimpa, obssaid, nobs, obserr, qcflags, missing)
153  write(err_msg,*) "ufo_roobserror_mod: setting up bending_angle obs error with NBAM method"
154  call fckit_log%info(err_msg)
155  deallocate(obssaid)
156  deallocate(obslat)
157  ! update obs error
158  call obsspace_put_db(self%obsdb, "FortranERR", trim(self%variable), obserr)
159 
160  case ("ECMWF")
161  allocate(obsvalue(nobs))
162  call obsspace_get_db(self%obsdb, "ObsValue", "bending_angle", obsvalue)
163  call bending_angle_obserr_ecmwf(obsimpa, obsvalue, nobs, obserr, qcflags, missing)
164  write(err_msg,*) "ufo_roobserror_mod: setting up bending_angle obs error with ECMWF method"
165  call fckit_log%info(err_msg)
166  deallocate(obsvalue)
167  ! update obs error
168  call obsspace_put_db(self%obsdb, "FortranERR", trim(self%variable), obserr)
169  case ("NRL")
170  allocate(obsvalue(nobs))
171  allocate(obslat(nobs))
172  call obsspace_get_db(self%obsdb, "ObsValue", "bending_angle", obsvalue)
173  call obsspace_get_db(self%obsdb, "MetaData", "latitude", obslat)
174  call bending_angle_obserr_nrl(obslat, obsimpa, obsvalue, nobs, obserr, qcflags, missing)
175  write(err_msg,*) "ufo_roobserror_mod: setting up bending_angle obs error with NRL method"
176  call fckit_log%info(err_msg)
177  deallocate(obsvalue)
178  deallocate(obslat)
179  ! update obs error
180  call obsspace_put_db(self%obsdb, "FortranERR", trim(self%variable), obserr)
181 
182  case ("MetOffice")
183  write(err_msg,*) "ufo_roobserror_mod: setting up bending_angle obs error with the Met Office method"
184  call fckit_log%info(err_msg)
185  if (cmp_strings(self % rmatrix_filename, "")) then
186  err_msg = "If you choose the Met Office method, then you must specify rmatrix_filename"
187  call abor1_ftn(err_msg)
188  end if
189  allocate(obssatid(nobs))
190  allocate(obsorigc(nobs))
191  allocate(obsvalue(nobs))
192  call obsspace_get_db(self%obsdb, "MetaData", "occulting_sat_id", obssatid)
193  call obsspace_get_db(self%obsdb, "MetaData", "originating_center", obsorigc)
194  call obsspace_get_db(self%obsdb, "ObsValue", "bending_angle", obsvalue)
195  call obsspace_get_db(self%obsdb, "ObsError", trim(self%variable), obserr)
196  if (self % err_variable == "latitude") then
197  allocate(obslat(nobs))
198  call obsspace_get_db(self%obsdb, "MetaData", "latitude", obslat)
199  call gnssro_obserr_latitude(nobs, self % rmatrix_filename, obssatid, obsorigc, obslat, obsimph, &
200  obsvalue, obserr, qcflags, missing)
201  deallocate(obslat)
202  else if (self % err_variable == "average_temperature") then
203  call gnssro_obserr_avtemp(nobs, self % n_horiz, self % rmatrix_filename, obssatid, obsorigc, &
204  model_nlevs, air_temperature, geopotential_height, obsimph, obsvalue, &
205  obserr, qcflags, missing)
206  else
207  err_msg = "The error variable should be either 'latitude' or 'average_temperature', but you gave " // &
208  trim(self % err_variable)
209  call fckit_log%info(err_msg)
210  end if
211  deallocate(obsvalue)
212  deallocate(obssatid)
213  deallocate(obsorigc)
214  ! up date obs error
215  call obsspace_put_db(self%obsdb, "FortranERR", trim(self%variable), obserr)
216 
217  case default
218  write(err_msg,*) "ufo_roobserror_mod: bending_angle error model must be NBAM, ECMWF, NRL or MetOffice"
219  call fckit_log%info(err_msg)
220  end select
221  deallocate(obsimpp)
222  deallocate(obsgeoid)
223  deallocate(obslocr)
224  deallocate(obsimph)
225  deallocate(obsimpa)
226 
227 !-------------------------------
228 case ("refractivity")
229 
230  select case (trim(self%errmodel))
231 
232  case ("NBAM")
233 
234  allocate(obsz(nobs))
235  allocate(obslat(nobs))
236  call obsspace_get_db(self%obsdb, "MetaData", "altitude", obsz)
237  call obsspace_get_db(self%obsdb, "MetaData", "latitude", obslat)
238  call refractivity_obserr_nbam(obslat, obsz, nobs, obserr, qcflags, missing)
239  write(err_msg,*) "ufo_roobserror_mod: setting up refractivity obs error with NBAM method"
240  call fckit_log%info(err_msg)
241  deallocate(obsz)
242  deallocate(obslat)
243  ! up date obs error
244  call obsspace_put_db(self%obsdb, "FortranERR", trim(self%variable), obserr)
245 
246  case ("ECMWF")
247  write(err_msg,*) "ufo_roobserror_mod: ECMWF refractivity error model is not available now"
248  call fckit_log%info(err_msg)
249 
250  case default
251  write(err_msg,*) "ufo_roobserror_mod: only NBAM refractivity model is available now"
252  call fckit_log%info(err_msg)
253  end select
254 
255 case default
256  call abor1_ftn("ufo_roobserror_prior: variable has to be bending_angle or refractivity")
257 end select
258 
259 deallocate(qcflags)
260 deallocate(obserr)
261 
262 end subroutine ufo_roobserror_prior
263 
264 end module ufo_roobserror_mod
subroutine bending_angle_obserr_nbam(obsLat, obsImpH, obsSaid, nobs, obsErr, QCflags, missing)
subroutine bending_angle_obserr_ecmwf(obsImpH, obsValue, nobs, obsErr, QCflags, missing)
subroutine gnssro_obserr_latitude(nobs, rmatrix_filename, obsSatid, obsOrigC, obsLat, obsZ, obsValue, obsErr, QCflags, missing)
subroutine refractivity_obserr_nbam(obsLat, obsZ, nobs, obsErr, QCflags, missing)
subroutine gnssro_obserr_avtemp(nobs, n_horiz, rmatrix_filename, obsSatid, obsOrigC, nlevs, air_temperature, geopotential_height, obsZ, obsValue, obsErr, QCflags, missing)
subroutine bending_angle_obserr_nrl(obsLat, obsImpH, obsValue, nobs, obsErr, QCflags, missing)
integer, parameter max_string
Fortran module to implement RO observational error.
subroutine, public ufo_roobserror_prior(self, model_nobs, model_nlevs, air_temperature, geopotential_height)
subroutine, public ufo_roobserror_create(self, obspace, f_conf)
subroutine, public ufo_roobserror_delete(self)
Fortran module with various useful routines.
logical function, public cmp_strings(str1, str2)