UFO
ufo_radiancerttov_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 for radiancerttov observation operator
7 
9 
10  use fckit_configuration_module, only: fckit_configuration
11  use fckit_log_module, only : fckit_log
12  use iso_c_binding
13  use kinds
14  use missing_values_mod
15 
16  use obsspace_mod
17 
19  use ufo_vars_mod
21 
22  use rttov_types
23  use rttov_const, only : errorstatus_success
24  use rttov_unix_env
25 
26  implicit none
27  private
28 
29  !> Fortran derived type for the observation type
30  type, public :: ufo_radiancerttov
31  private
32  character(len=MAXVARLEN), public, allocatable :: varin(:) ! variables requested from the model
33  integer, allocatable :: channels(:)
34  type(rttov_conf) :: conf
35  type(ufo_rttov_io) :: rtprof
36  contains
37  procedure :: setup => ufo_radiancerttov_setup
38  procedure :: delete => ufo_radiancerttov_delete
39  procedure :: simobs => ufo_radiancerttov_simobs
40  end type ufo_radiancerttov
41 
42 contains
43 
44  ! ------------------------------------------------------------------------------
45  subroutine ufo_radiancerttov_setup(self, f_confOper, channels)
46 
47  implicit none
48  class(ufo_radiancerttov), intent(inout) :: self
49  type(fckit_configuration), intent(in) :: f_confOper
50  integer(c_int), intent(in) :: channels(:) !List of channels to use
51 
52  type(fckit_configuration) :: f_confOpts ! RTcontrol
53  integer :: ind, jspec
54 
55  call f_confoper % get_or_die("obs options",f_confopts)
56 
57  call rttov_conf_setup(self % conf,f_confopts,f_confoper)
58 
59  if ( ufo_vars_getindex(self%conf%Absorbers, var_mixr) < 1 .and. &
60  ufo_vars_getindex(self%conf%Absorbers, var_q) < 1 ) then
61  write(message,*) 'ufo_radiancerttov_setup error: H2O must be included in RTTOV Absorbers'
62  call abor1_ftn(message)
63  end if
64 
65  nvars_in = size(varin_default) + self%conf%ngas
66 
67  allocate(self%varin(nvars_in))
68  self%varin(1:size(varin_default)) = varin_default
69  ind = size(varin_default) + 1
70 
71  !Use list of Absorbers from conf
72  do jspec = 1, self%conf%ngas
73  self%varin(ind) = self%conf%Absorbers(jspec)
74  ind = ind + 1
75  end do
76 
77  ! save channels
78  allocate(self%channels(size(channels)))
79  self%channels(:) = channels(:)
80 
81  write(message,'(A, 2I6)') 'Finished setting up rttov'
82  call fckit_log%info(message)
83 
84  end subroutine ufo_radiancerttov_setup
85 
86  ! ------------------------------------------------------------------------------
87  subroutine ufo_radiancerttov_delete(self)
88  implicit none
89  class(ufo_radiancerttov), intent(inout) :: self
90 
91  call rttov_conf_delete(self%conf)
92 
93  end subroutine ufo_radiancerttov_delete
94 
95  ! ------------------------------------------------------------------------------
96  subroutine ufo_radiancerttov_simobs(self, geovals, obss, nvars, nlocs, &
97  hofx, hofxdiags, ob_info)
98  use fckit_mpi_module, only: fckit_mpi_comm
100 
101  implicit none
102 
103  class(ufo_radiancerttov), intent(inout) :: self
104  type(ufo_geovals), intent(in) :: geovals
105  type(c_ptr), value, intent(in) :: obss
106  integer, intent(in) :: nvars, nlocs
107 
108  real(c_double), intent(inout) :: hofx(nvars,nlocs)
109  type(ufo_geovals), intent(inout) :: hofxdiags !non-h(x) diagnostics
110  type(ufo_rttovonedvarcheck_ob), optional, intent(inout) :: ob_info
111 
112  real(c_double) :: missing
113  type(fckit_mpi_comm) :: f_comm
114 
115  ! Local Variables
116  character(*), parameter :: routine_name = 'ufo_radiancerttov_simobs'
117  type(rttov_chanprof), allocatable :: chanprof(:)
118  type(ufo_geoval), pointer :: geoval_temp
119 
120  integer :: nprofiles, nlevels
121  integer(kind=jpim) :: errorstatus ! Error status of RTTOV subroutine calls
122 
123  integer :: i_inst, iprof_rttov, iprof, ichan, ichan_sim
124  integer :: nprof_sim, nprof_max_sim, nchan_total
125  integer :: prof_start, prof_end
126 
127  logical :: jacobian_needed
128 
129  include 'rttov_direct.interface'
130  include 'rttov_k.interface'
131 
132  write(message,'(A, A, I0, A, I0, A)') trim(routine_name), ': Simulating observations'
133  call fckit_log%debug(message)
134 
135  !Initialisations
136  missing = missing_value(missing)
137  hofx = missing
138 
139  !Return the name and name length of obsspace communicator (from ioda)
140  call obsspace_get_comm(obss, f_comm)
141 
142  !! Parse hofxdiags%variables into independent/dependent variables and channel assumed formats:
143  ! Note this sets the jacobian_needed flag
144  !! jacobian var --> <ystr>_jacobian_<xstr>_<chstr>
145  !! non-jacobian var --> <ystr>_<chstr>
146  call parse_hofxdiags(hofxdiags, jacobian_needed)
147 
148  ! Get number of profiles and levels from geovals
149  nprofiles = geovals % nlocs
150  call ufo_geovals_get_var(geovals, var_ts, geoval_temp)
151  nlevels = geoval_temp % nval
152  nullify(geoval_temp)
153 
154  ! Allocate RTTOV profiles for ALL geovals for the direct calculation
155  write(message,'(A, A, I0, A, I0, A)') &
156  trim(routine_name), ': Allocating ', nprofiles, ' profiles with ', nlevels, ' levels'
157  call fckit_log%debug(message)
158 
159  call self % RTprof % alloc_profs(errorstatus, self % conf, nprofiles, nlevels, init=.true., asw=1)
160 
161  !Assign the atmospheric and surface data from the GeoVaLs
162  write(message,'(A, A, I0, A, I0, A)') &
163  trim(routine_name), ': Creating RTTOV profiles from geovals'
164  call fckit_log%debug(message)
165  if(present(ob_info)) then
166  call self % RTprof % setup(geovals,obss,self % conf,ob_info=ob_info)
167  else
168  call self % RTprof % setup(geovals,obss,self % conf)
169  endif
170 
171  !DAR: Removing sensor_loop until it's demonstrated to be needed and properly tested
172  ! at the moment self % channels is a single 1D array so cannot adequately contain more than one set of channels
173 ! Sensor_Loop:do i_inst = 1, self % conf % nSensors
174  i_inst = 1
175 
176  ! Number of channels to be simulated for this instrument (from the configuration, not necessarily the full instrument complement)
177  nchan_inst = size(self % channels)
178 
179  ! Maximum number of profiles to be processed by RTTOV per pass
180  if(self % conf % prof_by_prof) then
181  nprof_max_sim = 1
182  else
183  nprof_max_sim = max(1,self % conf % nchan_max_sim / nchan_inst)
184  endif
185  nprof_sim = min(nprof_max_sim, nprofiles)
186 
187  ! Determine the total number of radiances to simulate (nchan_sim).
188  nchan_sim = nprof_sim * size(self%channels)
189 
190  ! Allocate structures for RTTOV direct code (and, if needed, K code)
191  write(message,'(A,A,I0,A,I0,A)') &
192  trim(routine_name), ': Allocating resources for RTTOV direct code: ', nprof_sim, ' and ', nchan_sim, ' channels'
193  call fckit_log%debug(message)
194  call self % RTprof % alloc_direct(errorstatus, self % conf, nprof_sim, nchan_sim, nlevels, init=.true., asw=1)
195 
196  if (jacobian_needed) then
197  write(message,'(A,A,I0,A,I0,A)') &
198  trim(routine_name), ': Allocating resources for RTTOV K code: ', nprof_sim, ' and ', nchan_sim, ' channels'
199  call fckit_log%debug(message)
200 
201  call self % RTprof % alloc_profs_k(errorstatus, self % conf, nchan_sim, nlevels, init=.true., asw=1)
202  call self % RTprof % alloc_k(errorstatus, self % conf, nprof_sim, nchan_sim, nlevels, init=.true., asw=1)
203  endif
204 
205  ! Used for keeping track of profiles for setting emissivity
206  allocate(self % RTprof % chanprof ( nprofiles * nchan_inst ))
207 
208  prof_start = 1; prof_end = nprofiles
209  nchan_total = 0
210 
211  rttov_loop : do while (prof_start <= prof_end)
212 
213  ! Reduce number of simulated profiles/channel if at end of the of profiles to be processed
214  nprof_sim = min(nprof_sim, prof_end - prof_start + 1)
215  nchan_sim = nprof_sim * size(self%channels)
216 
217  ! allocate and initialise local chanprof structure
218  allocate(chanprof( nchan_sim ))
219  chanprof(:) % prof = 0
220  chanprof(:) % chan = 0
221 
222  ! index for simulated channel
223  ichan_sim = 0_jpim
224 
225  ! Build the list of profile/channel indices in chanprof
226  do iprof_rttov = 1, nprof_sim
227  errorstatus = errorstatus_success
228 
229  ! iprof is the index for the full set of RTTOV profiles
230  iprof = prof_start + iprof_rttov - 1
231 
232  ! print profile information if requested
233  if(any(self % conf % inspect == iprof)) call self % RTprof % print(self % conf, iprof, i_inst)
234 
235  ! check RTTOV profile and flag it if it fails the check
236  if(self % conf % RTTOV_profile_checkinput) call self % RTprof % check(self % conf, iprof, i_inst, errorstatus)
237 
238  if (errorstatus == errorstatus_success) then
239  do ichan = 1, nchan_inst
240  ichan_sim = ichan_sim + 1_jpim
241  chanprof(ichan_sim) % prof = iprof_rttov ! this refers to the slice of the RTprofile array passed to RTTOV
242  chanprof(ichan_sim) % chan = self % channels(ichan)
243  self % RTprof % chanprof(nchan_total + ichan_sim) % prof = iprof ! this refers to the index of the profile from the geoval
244  self % RTprof % chanprof(nchan_total + ichan_sim) % chan = self % channels(ichan)
245  end do
246  nchan_sim = ichan_sim
247  endif
248 
249  end do
250 
251  ! Set surface emissivity
252  call self % RTProf % init_emissivity(self % conf, prof_start)
253 
254  ! --------------------------------------------------------------------------
255  ! Call RTTOV model
256  ! --------------------------------------------------------------------------
257  !N.B. different from TL/AD as we don't need to retain the full profiles_k so data can be overwritten
258 
259  if (jacobian_needed) then
260  call rttov_k( &
261  errorstatus, &! out error flag
262  chanprof(1:nchan_sim), &! in LOCAL channel and profile index structure
263  self % conf % rttov_opts, &! in options structure
264  self % RTProf % profiles(prof_start:prof_start + nprof_sim -1), &! in profile array
265  self % RTProf % profiles_k(1:nchan_sim), &! in profile array
266  self % conf % rttov_coef_array(i_inst), &! in coefficients structure
267  self % RTProf % transmission, &! inout computed transmittances
268  self % RTProf % transmission_k, &! inout computed transmittances
269  self % RTProf % radiance, &! inout computed radiances
270  self % RTProf % radiance_k, &! inout computed radiances
271  calcemis = self % RTProf % calcemis(1:nchan_sim), &! in flag for internal emissivity calcs
272  emissivity = self % RTProf % emissivity(1:nchan_sim), &!, &! inout input/output emissivities per channel
273  emissivity_k = self % RTProf % emissivity_k(1:nchan_sim))!, &! inout input/output emissivities per channel
274 
275  if ( errorstatus /= errorstatus_success ) then
276  write(message,'(A, A, 2I6)') trim(routine_name), 'after rttov_k: error ', errorstatus, i_inst, &
277  ' skipping profiles ', prof_start, ' -- ', prof_start + nprof_sim - 1
278  call fckit_log%info(message)
279  end if
280 
281  else
282  call rttov_direct( &
283  errorstatus, &! out error flag
284  chanprof(1:nchan_sim), &! in channel and profile index structure
285  self % conf % rttov_opts, &! in options structure
286  self % RTProf % profiles(prof_start:prof_start + nprof_sim -1), &! in profile array
287  self % conf % rttov_coef_array(i_inst), &! in coefficients structure
288  self % RTProf % transmission, &! inout computed transmittances
289  self % RTProf % radiance, &! inout computed radiances
290  calcemis = self % RTProf % calcemis(1:nchan_sim), &! in flag for internal emissivity calcs
291  emissivity = self % RTProf % emissivity(1:nchan_sim))!, &! inout input/output emissivities per channel
292 
293  if ( errorstatus /= errorstatus_success ) then
294  write(message,'(A, A, 2I6)') trim(routine_name), 'after rttov_direct: error ', errorstatus, i_inst, &
295  ' skipping profiles ', prof_start, ' -- ', prof_start + nprof_sim - 1
296  call fckit_log%info(message)
297  end if
298  endif ! jacobian_needed
299 
300  ! Put simulated brightness temperature into hofx
301  if ( errorstatus == errorstatus_success ) then
302  do ichan = 1, nchan_sim, size(self%channels)
303  iprof = self % RTProf % chanprof(nchan_total + ichan)%prof
304  hofx(1:size(self%channels),iprof) = self % RTprof % radiance % bt(ichan:ichan+size(self%channels)-1)
305  enddo
306 
307  ! Put simulated diagnostics into hofxdiags
308  if(hofxdiags%nvar > 0) call populate_hofxdiags(self % RTProf, chanprof, self % conf, prof_start, hofxdiags)
309  endif
310 
311  ! increment profile and channel counters
312  nchan_total = nchan_total + nchan_sim
313  prof_start = prof_start + nprof_sim
314 
315  ! deallocate local chanprof so it can be re-allocated with a different number of channels if reqd.
316  deallocate(chanprof)
317  if (jacobian_needed) call self % RTprof % zero_k()
318 
319  end do rttov_loop
320 
321  ! Deallocate structures for rttov_direct
322  if(jacobian_needed) then
323  call self % RTprof % alloc_k(errorstatus, self % conf, -1, -1, -1, asw=0)
324  call self % RTprof % alloc_profs_k(errorstatus, self % conf, size(self % RTprof % profiles_k), -1, asw=0)
325  ! deallocation of profiles_k isn't done by default in alloc_profs_k because it can contain the trajectory
326  ! which is currently used for the TL/AD but the 1dvar doesn't use it so it can be safely done here
327  deallocate (self % RTprof % profiles_k)
328  endif
329  call self % RTprof % alloc_direct(errorstatus, self % conf, -1, -1, -1, asw=0)
330  call self % RTprof % alloc_profs(errorstatus, self % conf, size(self % RTprof % profiles), -1, asw=0)
331 
332  deallocate(self % RTprof % chanprof)
333 
334  if (errorstatus /= errorstatus_success) then
335  write(message,'(A, 2I6)') &
336  'after rttov_alloc_direct (deallocation): errorstatus, i_inst =', errorstatus, i_inst
337  call abor1_ftn(message)
338  end if
339 
340  !end do Sensor_Loop
341 
342  end subroutine ufo_radiancerttov_simobs
343 
344  ! ------------------------------------------------------------------------------
345 
346 end module ufo_radiancerttov_mod
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran module for radiancerttov observation operator.
subroutine ufo_radiancerttov_setup(self, f_confOper, channels)
subroutine ufo_radiancerttov_simobs(self, geovals, obss, nvars, nlocs, hofx, hofxdiags, ob_info)
subroutine ufo_radiancerttov_delete(self)
Fortran module to provide code shared between nonlinear and tlm/adm radiance calculations.
subroutine, public parse_hofxdiags(hofxdiags, jacobian_needed)
subroutine, public rttov_conf_setup(conf, f_confOpts, f_confOper)
character(len=max_string), public message
subroutine, public rttov_conf_delete(conf)
character(len=maxvarlen), dimension(:), pointer, public varin_default
subroutine, public populate_hofxdiags(RTProf, chanprof, conf, prof_start, hofxdiags)
Fortran module which contains the observation metadata for a single observation.
integer function, public ufo_vars_getindex(vars, varname)
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_mixr
character(len=maxvarlen), parameter, public var_ts
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators
Fortran derived type for the observation type.