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, hofx, hofxdiags)
97  use fckit_mpi_module, only: fckit_mpi_comm
98 
99  implicit none
100 
101  class(ufo_radiancerttov), intent(inout) :: self
102  type(ufo_geovals), intent(in) :: geovals
103  type(c_ptr), value, intent(in) :: obss
104  integer, intent(in) :: nvars, nlocs
105 
106  real(c_double), intent(inout) :: hofx(nvars,nlocs)
107  type(ufo_geovals), intent(inout) :: hofxdiags !non-h(x) diagnostics
108 
109  real(c_double) :: missing
110  type(fckit_mpi_comm) :: f_comm
111 
112  ! Local Variables
113  character(*), parameter :: ROUTINE_NAME = 'ufo_radiancerttov_simobs'
114  type(ufo_geoval), pointer :: temp
115 
116  integer :: nprofiles
117  integer(kind=jpim) :: errorstatus ! Return error status of RTTOV subroutine calls
118 
119  integer :: i_inst, nlevels, nchan_total, ichan, iprof, prof
120  integer :: nprof_sim, nprof_max_sim
121  integer :: prof_start, prof_end
122 
123  logical :: jacobian_needed
124  logical, allocatable :: skip_profiles(:)
125 
126  logical :: obs_info
127 
128  logical :: layer_quantities
129 
130  include 'rttov_direct.interface'
131  include 'rttov_k.interface'
132  include 'rttov_print_profile.interface'
133  include 'rttov_user_profile_checkinput.interface'
134 
135  !DAR: What is this?
136  call obsspace_get_comm(obss, f_comm)
137 
138  ! Get number of profile and layers from geovals
139  ! ---------------------------------------------
140 
141  nprofiles = geovals % nlocs
142  if (ufo_vars_getindex(geovals%variables, var_ts) > 0) then
143  call ufo_geovals_get_var(geovals, var_ts, temp)
144  nlevels = temp % nval
145  layer_quantities = .false.
146  endif
147 
148  nullify(temp)
149 
150  missing = missing_value(missing)
151  hofx = missing
152 
153  errorstatus = 0_jpim
154  nchan_total = 0
155 
156  !DARFIX: This isn't ideal because it's not going to work for multiple instruments but we'll deal with that later
157  nchan_inst = size(self % channels)
158 
159  !! Parse hofxdiags%variables into independent/dependent variables and channel
160  !! assumed formats:
161  ! Note this sets jacobian_needed
162  !! jacobian var --> <ystr>_jacobian_<xstr>_<chstr>
163  !! non-jacobian var --> <ystr>_<chstr>
164  call parse_hofxdiags(hofxdiags, jacobian_needed)
165 
166  sensor_loop:do i_inst = 1, self % conf % nSensors
167 
168  ! Ensure the options and coefficients are consistent
169  call rttov_user_options_checkinput(errorstatus, self % conf % rttov_opts, &
170  self % conf % rttov_coef_array(i_inst))
171 
172  if (errorstatus /= errorstatus_success) then
173  write(message,'(A, I6)') 'after rttov_user_options_checkinput: error = ',&
174  errorstatus
175  call fckit_log%info(message)
176  end if
177 
178  ! keep journal of which profiles have no obs data these will be skipped
179  allocate(skip_profiles(nprofiles))
180  skip_profiles(:) = .false.
181  call ufo_rttov_skip_profiles(nprofiles,nchan_inst,self%channels,obss,skip_profiles)
182 
183  ! Determine the total number of radiances to simulate (nchan_sim).
184  ! In this example we simulate all specified channels for each profile, but
185  ! in general one can simulate a different number of channels for each profile.
186 
187  nprof_max_sim = self % conf % nchan_max_sim / nchan_inst
188  nprof_sim = min(nprof_max_sim, nprofiles)
189 
190  prof_start = 1
191  prof_end = nprofiles
192 
193  !DARFIX should actually be packed count of skip_profiles * SIZE(channels)
194  nprof_sim = min(nprof_sim, prof_end - prof_start + 1)
195  nchan_sim = nprof_sim * size(self%channels)
196 
197  ! --------------------------------------------------------------------------
198  ! Allocate RTTOV input and output structures
199  ! --------------------------------------------------------------------------
200  if (.not. jacobian_needed) then
201  ! allocate RTTOV resources
202  call self % RTprof % alloc(errorstatus, self % conf, nprof_sim, nchan_sim, nlevels, init=.true., asw=1)
203  else
204  call self % RTprof % alloc(errorstatus, self % conf, nprof_sim, nchan_sim, nlevels, init=.true., asw=2)
205  endif
206 
207  self % RTProf % profiles(:) % skin % surftype = -1_jpim
208 
209  do while (prof_start <= prof_end)
210  self % RTprof % chanprof(:) % prof = 0
211  self % RTprof % chanprof(:) % chan = 0
212 
213  nchan_sim = 0_jpim
214  nprof_sim = min(nprof_sim, prof_end - prof_start + 1)
215 
216  ! --------------------------------------------------------------------------
217  ! Build the list of profile/channel indices in chanprof
218  ! --------------------------------------------------------------------------
219 
220  do iprof = 1, min(nprof_sim, prof_end - prof_start + 1)
221  if(.not. skip_profiles(prof_start + iprof - 1)) then
222  do ichan = 1, nchan_inst
223 
224  nchan_sim = nchan_sim + 1_jpim
225  self % RTprof % chanprof(nchan_sim) % prof = iprof
226  self % RTprof % chanprof(nchan_sim) % chan = self % channels(ichan)
227  end do
228  else
229  if (debug) write(*,*) 'skipping ', iprof, prof_start + iprof - 1
230  end if
231  end do
232 
233  !Assign the data from the GeoVaLs
234  !--------------------------------
235 
236  obs_info = .false. ! this will be replaced by an optional structure coming from 1DVar
237  if(obs_info) then
238  call load_atm_data_rttov(geovals,obss,self % RTprof % profiles,prof_start,self % conf,layer_quantities,obs_info=obs_info)
239  call load_geom_data_rttov(obss,self % RTprof % profiles,prof_start,obs_info=obs_info)
240  else
241  call load_atm_data_rttov(geovals,obss,self % RTprof % profiles,prof_start,self%conf,layer_quantities)
242  call load_geom_data_rttov(obss,self % RTprof % profiles,prof_start)
243  end if
244 
245  ! --------------------------------------------------------------------------
246  ! Set surface emissivity
247  ! --------------------------------------------------------------------------
248 
249  call self % RTProf % init_emissivity(self % conf)
250 
251  if(self % conf % RTTOV_profile_checkinput) then
252  if (self % conf % inspect > 0) then
253  call rttov_print_profile(self % RTprof % profiles(self % conf % inspect))
254  endif
255 
256  ! no error checking, could check multiple profiles in loop but what would be the point
257  call rttov_user_profile_checkinput(rttov_errorstatus, &
258  self % conf % rttov_opts, &
259  self % conf % rttov_coef_array(i_inst), &
260  self % RTprof % profiles(self % conf % inspect))
261  endif
262 
263 
264  ! --------------------------------------------------------------------------
265  ! Call RTTOV model
266  ! --------------------------------------------------------------------------
267 
268  if (jacobian_needed) then
269 
270  call rttov_k( &
271  errorstatus, &! out error flag
272  self % RTProf % chanprof(nchan_total + 1:nchan_total + nchan_sim), &! in LOCAL channel and profile index structure
273  self % conf % rttov_opts, &! in options structure
274  self % RTProf % profiles, &! in profile array
275  self % RTProf % profiles_k(nchan_total + 1 : nchan_total + nchan_sim), &! in profile array
276  self % conf % rttov_coef_array(i_inst), &! in coefficients structure
277  self % RTProf % transmission, &! inout computed transmittances
278  self % RTProf % transmission_k, &! inout computed transmittances
279  self % RTProf % radiance, &! inout computed radiances
280  self % RTProf % radiance_k, &! inout computed radiances
281  calcemis = self % RTProf % calcemis, &! in flag for internal emissivity calcs
282  emissivity = self % RTProf % emissivity, &!, &! inout input/output emissivities per channel
283  emissivity_k = self % RTProf % emissivity_k)!, &! inout input/output emissivities per channel
284 
285  if ( errorstatus /= errorstatus_success ) then
286  write(message,'(A, 2I6)') 'after rttov_k: error ', errorstatus, i_inst
287  call abor1_ftn(message)
288  end if
289 
290  else
291  call rttov_direct( &
292  errorstatus, &! out error flag
293  self % RTprof % chanprof(1:nchan_sim), &! in channel and profile index structure
294  self % conf % rttov_opts, &! in options structure
295  self % RTProf % profiles(1:nprof_sim), &! in profile array
296  self % conf % rttov_coef_array(i_inst), &! in coefficients structure
297  self % RTProf % transmission, &! inout computed transmittances
298  self % RTProf % radiance, &! inout computed radiances
299  calcemis = self % RTProf % calcemis(1:nchan_sim), &! in flag for internal emissivity calcs
300  emissivity = self % RTProf % emissivity(1:nchan_sim))!, &! inout input/output emissivities per channel
301 
302  if ( errorstatus /= errorstatus_success ) then
303  write(message,'(A, 2I6)') 'after rttov_direct: error ', errorstatus, i_inst
304  call abor1_ftn(message)
305  end if
306  endif ! jacobian_needed
307 
308  !DARFIX: This should be available only when debugging
309  ! Write out progress through batch
310  if (debug) write(*,'(A1, i0, A, i0)',advance="NO") achar(13), prof_start+nprof_sim-1, ' locations processed out of ', geovals%nlocs
311 
312  ! Put simulated brightness temperature into hofx
313  ! ----------------------------------------------
314  do ichan=1, nchan_sim, size(self%channels)
315  prof = self % RTProf % chanprof(ichan)%prof
316  hofx(1:size(self%channels),prof_start + prof - 1) = self % RTprof % radiance % bt(ichan:ichan+size(self%channels)-1)
317  enddo
318 
319  ! Put simulated diagnostics into hofxdiags
320  ! ----------------------------------------------
321  if(hofxdiags%nvar > 0) call populate_hofxdiags(self % RTProf, self % RTProf % chanprof, hofxdiags)
322 
323  nchan_total = nchan_total + nchan_sim
324  prof_start = prof_start + nprof_sim
325 
326  end do
327 
328  ! Deallocate structures for rttov_direct
329 
330  call self % RTprof % alloc(errorstatus, self % conf, nprof_sim, nchan_sim, nlevels, asw=0)
331 
332  if (errorstatus /= errorstatus_success) then
333  write(message,'(A, 2I6)') &
334  'after rttov_alloc_direct (deallocation): errorstatus, i_inst =', &
335  errorstatus, i_inst
336  call abor1_ftn(message)
337  end if
338 
339  end do sensor_loop
340  write(*,*)
341 
342  end subroutine ufo_radiancerttov_simobs
343 
344  ! ------------------------------------------------------------------------------
345 
346 end module ufo_radiancerttov_mod
ufo_radiancerttov_mod
Fortran module for radiancerttov observation operator.
Definition: ufo_radiancerttov_mod.F90:8
ufo_radiancerttov_utils_mod::nchan_sim
integer, public nchan_sim
Definition: ufo_radiancerttov_utils_mod.F90:98
ufo_radiancerttov_utils_mod::debug
logical, public debug
Definition: ufo_radiancerttov_utils_mod.F90:100
ufo_radiancerttov_utils_mod::load_atm_data_rttov
subroutine, public load_atm_data_rttov(geovals, obss, profiles, prof_start, conf, layer_quantities, obs_info)
Definition: ufo_radiancerttov_utils_mod.F90:318
ufo_radiancerttov_mod::ufo_radiancerttov_setup
subroutine ufo_radiancerttov_setup(self, f_confOper, channels)
Definition: ufo_radiancerttov_mod.F90:46
ufo_radiancerttov_utils_mod::rttov_conf
Definition: ufo_radiancerttov_utils_mod.F90:126
ufo_radiancerttov_utils_mod::message
character(len=max_string), public message
Definition: ufo_radiancerttov_utils_mod.F90:45
ufo_radiancerttov_mod::ufo_radiancerttov
Fortran derived type for the observation type.
Definition: ufo_radiancerttov_mod.F90:30
ufo_radiancerttov_mod::ufo_radiancerttov_simobs
subroutine ufo_radiancerttov_simobs(self, geovals, obss, nvars, nlocs, hofx, hofxdiags)
Definition: ufo_radiancerttov_mod.F90:97
ufo_radiancerttov_utils_mod::load_geom_data_rttov
subroutine, public load_geom_data_rttov(obss, profiles, prof_start1, obs_info)
Definition: ufo_radiancerttov_utils_mod.F90:779
ufo_radiancerttov_utils_mod::ufo_rttov_skip_profiles
subroutine, public ufo_rttov_skip_profiles(nprofiles, nchannels, channels, obss, Skip_Profiles)
Definition: ufo_radiancerttov_utils_mod.F90:1272
ufo_radiancerttov_utils_mod::rttov_errorstatus
integer, public rttov_errorstatus
Definition: ufo_radiancerttov_utils_mod.F90:48
ufo_radiancerttov_utils_mod::rttov_conf_setup
subroutine, public rttov_conf_setup(conf, f_confOpts, f_confOper)
Definition: ufo_radiancerttov_utils_mod.F90:161
ufo_vars_mod::ufo_vars_getindex
integer function, public ufo_vars_getindex(vars, varname)
Definition: ufo_variables_mod.F90:204
ufo_vars_mod::var_mixr
character(len=maxvarlen), parameter, public var_mixr
Definition: ufo_variables_mod.F90:21
ufo_geovals_mod
Definition: ufo_geovals_mod.F90:7
ufo_radiancerttov_utils_mod
Fortran module to provide code shared between nonlinear and tlm/adm radiance calculations.
Definition: ufo_radiancerttov_utils_mod.F90:8
ufo_radiancerttov_utils_mod::ufo_rttov_io
Definition: ufo_radiancerttov_utils_mod.F90:104
ufo_radiancerttov_mod::ufo_radiancerttov_delete
subroutine ufo_radiancerttov_delete(self)
Definition: ufo_radiancerttov_mod.F90:88
ufo_radiancerttov_utils_mod::nchan_inst
integer, public nchan_inst
Definition: ufo_radiancerttov_utils_mod.F90:97
ufo_aodcrtm_mod::varin_default
character(len=maxvarlen), dimension(5), parameter varin_default
Definition: ufo_aodcrtm_mod.F90:35
ufo_vars_mod
Definition: ufo_variables_mod.F90:8
ufo_geovals_mod::ufo_geovals_get_var
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Definition: ufo_geovals_mod.F90:128
ufo_radiancerttov_utils_mod::nvars_in
integer, public nvars_in
Definition: ufo_radiancerttov_utils_mod.F90:47
ufo_vars_mod::var_q
character(len=maxvarlen), parameter, public var_q
Definition: ufo_variables_mod.F90:22
ufo_vars_mod::var_ts
character(len=maxvarlen), parameter, public var_ts
Definition: ufo_variables_mod.F90:19
ufo_radiancerttov_utils_mod::populate_hofxdiags
subroutine, public populate_hofxdiags(RTProf, chanprof, hofxdiags)
Definition: ufo_radiancerttov_utils_mod.F90:1547
ufo_geovals_mod::ufo_geovals
type to hold interpolated fields required by the obs operators
Definition: ufo_geovals_mod.F90:47
ufo_radiancerttov_utils_mod::rttov_conf_delete
subroutine, public rttov_conf_delete(conf)
Definition: ufo_radiancerttov_utils_mod.F90:305
ufo_geovals_mod::ufo_geoval
type to hold interpolated field for one variable, one observation
Definition: ufo_geovals_mod.F90:40
conf
Definition: conf.py:1
ufo_radiancerttov_utils_mod::parse_hofxdiags
subroutine, public parse_hofxdiags(hofxdiags, jacobian_needed)
Definition: ufo_radiancerttov_utils_mod.F90:1726