FV3 Bundle
ufo_radiance_tlad_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 handle tl/ad for radiance observations
7 
9 
10  use iso_c_binding
11  use config_mod
12  use kinds
13 
16  use ufo_vars_mod
18  use crtm_module
19  use obsspace_mod
20 
21  implicit none
22  private
23 
24  !> Fortran derived type for radiance trajectory
25  type, extends(ufo_basis_tlad), public :: ufo_radiance_tlad
26  private
27  type(rad_conf) :: rc
28  integer :: n_profiles
29  integer :: n_layers
30  integer :: n_channels
31  type(crtm_atmosphere_type), allocatable :: atm_k(:,:)
32  type(crtm_surface_type), allocatable :: sfc_k(:,:)
33  contains
34  procedure :: setup => ufo_radiance_tlad_setup
36  procedure :: settraj => ufo_radiance_tlad_settraj
37  procedure :: simobs_tl => ufo_radiance_simobs_tl
38  procedure :: simobs_ad => ufo_radiance_simobs_ad
39  end type ufo_radiance_tlad
40 
41 contains
42 
43 ! ------------------------------------------------------------------------------
44 
45 subroutine ufo_radiance_tlad_setup(self, c_conf)
46 
47 implicit none
48 class(ufo_radiance_tlad), intent(inout) :: self
49 type(c_ptr), intent(in) :: c_conf
50 
51  call rad_conf_setup(self%rc,c_conf)
52 
53 end subroutine ufo_radiance_tlad_setup
54 
55 ! ------------------------------------------------------------------------------
56 
57 subroutine ufo_radiance_tlad_delete(self)
58 
59 implicit none
60 class(ufo_radiance_tlad), intent(inout) :: self
61 
62  self%ltraj = .false.
63  call rad_conf_delete(self%rc)
64 
65  if (allocated(self%atm_k)) then
66  call crtm_atmosphere_destroy(self%atm_K)
67  deallocate(self%atm_k)
68  endif
69 
70  if (allocated(self%sfc_k)) then
71  call crtm_surface_destroy(self%sfc_K)
72  deallocate(self%sfc_k)
73  endif
74 
75 end subroutine ufo_radiance_tlad_delete
76 
77 ! ------------------------------------------------------------------------------
78 
79 subroutine ufo_radiance_tlad_settraj(self, geovals, obss)
80 
81 implicit none
82 
83 class(ufo_radiance_tlad), intent(inout) :: self
84 type(ufo_geovals), intent(in) :: geovals
85 type(c_ptr), value, intent(in) :: obss
86 
87 ! Local Variables
88 character(*), parameter :: PROGRAM_NAME = 'ufo_radiance_mod.F90'
89 character(255) :: message, version
90 integer :: err_stat, alloc_stat
91 integer :: n, k1, ierr
92 type(ufo_geoval), pointer :: temp
93 
94 ! Define the "non-demoninational" arguments
95 type(CRTM_ChannelInfo_type) :: chinfo(self%rc%n_Sensors)
96 type(CRTM_Geometry_type), allocatable :: geo(:)
97 
98 ! Define the FORWARD variables
99 type(CRTM_Atmosphere_type), allocatable :: atm(:)
100 type(CRTM_Surface_type), allocatable :: sfc(:)
101 type(CRTM_RTSolution_type), allocatable :: rts(:,:)
102 
103 ! Define the K-MATRIX variables
104 type(CRTM_RTSolution_type), allocatable :: rts_K(:,:)
105 
106 
107  ! Get number of profile and layers from geovals
108  ! ---------------------------------------------
109  self%n_Profiles = geovals%nobs
110  call ufo_geovals_get_var(geovals, var_tv, temp, status=ierr)
111  self%n_Layers = temp%nval
112  nullify(temp)
113 
114  ! Program header
115  ! --------------
116  call crtm_version( version )
117  call program_message( program_name, &
118  'Check/example program for the CRTM Forward and K-Matrix (setTraj) functions using '//&
119  trim(self%rc%ENDIAN_type)//' coefficient datafiles', &
120  'CRTM Version: '//trim(version) )
121 
122 
123  ! Initialise all the sensors at once
124  ! ----------------------------------
125  !** NOTE: CRTM_Init points to the various binary files needed for CRTM. See the
126  !** CRTM_Lifecycle.f90 for more details.
127 
128  write( *,'(/5x,"Initializing the CRTM (setTraj) ...")' )
129  err_stat = crtm_init( self%rc%SENSOR_ID, &
130  chinfo, &
131  file_path=trim(self%rc%COEFFICIENT_PATH), &
132  quiet=.true.)
133  if ( err_stat /= success ) THEN
134  message = 'Error initializing CRTM (setTraj)'
135  call display_message( program_name, message, failure )
136  stop
137  end if
138 
139  ! Loop over all sensors. Not necessary if we're calling CRTM for each sensor
140  ! ----------------------------------------------------------------------------
141  sensor_loop:do n = 1, self%rc%n_Sensors
142 
143 
144  ! Determine the number of channels for the current sensor
145  ! -------------------------------------------------------
146  self%N_Channels = crtm_channelinfo_n_channels(chinfo(n))
147 
148 
149  ! Allocate the ARRAYS
150  ! -------------------
151  allocate( geo( self%n_Profiles ) , &
152  atm( self%n_Profiles ) , &
153  sfc( self%n_Profiles ) , &
154  rts( self%N_Channels, self%n_Profiles ) , &
155  self%atm_K( self%N_Channels, self%n_Profiles ) , &
156  self%sfc_K( self%N_Channels, self%n_Profiles ) , &
157  rts_k( self%N_Channels, self%n_Profiles ) , &
158  stat = alloc_stat )
159  if ( alloc_stat /= 0 ) THEN
160  message = 'Error allocating structure arrays (setTraj)'
161  call display_message( program_name, message, failure )
162  stop
163  end if
164 
165 
166  ! Create the input FORWARD structure (atm)
167  ! ----------------------------------------
168  call crtm_atmosphere_create( atm, self%n_Layers, self%rc%n_Absorbers, self%rc%n_Clouds, self%rc%n_Aerosols )
169  if ( any(.NOT. crtm_atmosphere_associated(atm)) ) THEN
170  message = 'Error allocating CRTM Forward Atmosphere structure (setTraj)'
171  CALL display_message( program_name, message, failure )
172  stop
173  END IF
174 
175 
176  ! Create the input FORWARD structure (sfc)
177  ! ----------------------------------------
178  call crtm_surface_create(sfc, self%N_Channels)
179  IF ( any(.NOT. crtm_surface_associated(sfc)) ) THEN
180  message = 'Error allocating CRTM Surface structure (setTraj)'
181  CALL display_message( program_name, message, failure )
182  stop
183  END IF
184 
185 
186  ! Create output K-MATRIX structure (atm)
187  ! --------------------------------------
188  call crtm_atmosphere_create( self%atm_K, self%n_Layers, self%rc%n_Absorbers, self%rc%n_Clouds, self%rc%n_Aerosols )
189  if ( any(.NOT. crtm_atmosphere_associated(self%atm_K)) ) THEN
190  message = 'Error allocating CRTM K-matrix Atmosphere structure (setTraj)'
191  CALL display_message( program_name, message, failure )
192  stop
193  END IF
194 
195 
196  ! Create output K-MATRIX structure (sfc)
197  ! --------------------------------------
198  call crtm_surface_create(self%sfc_K, self%N_Channels)
199  IF ( any(.NOT. crtm_surface_associated(self%sfc_K)) ) THEN
200  message = 'Error allocating CRTM K-matrix Surface structure (setTraj)'
201  CALL display_message( program_name, message, failure )
202  stop
203  END IF
204 
205 
206  !Assign the data from the GeoVaLs
207  !--------------------------------
208  call load_atm_data(self%N_PROFILES,self%N_LAYERS,geovals,atm)
209  call load_sfc_data(self%N_PROFILES,self%N_LAYERS,self%N_Channels,geovals,sfc,chinfo,obss)
210  call load_geom_data(obss,geo)
211 
212 
213  ! Zero the K-matrix OUTPUT structures
214  ! -----------------------------------
215  call crtm_atmosphere_zero( self%atm_K )
216  call crtm_surface_zero( self%sfc_K )
217 
218 
219  ! Inintialize the K-matrix INPUT so that the results are dTb/dx
220  ! -------------------------------------------------------------
221  rts_k%Radiance = zero
222  rts_k%Brightness_Temperature = one
223 
224 
225  ! Call the K-matrix model
226  ! -----------------------
227  err_stat = crtm_k_matrix( atm , & ! FORWARD Input
228  sfc , & ! FORWARD Input
229  rts_k , & ! K-MATRIX Input
230  geo , & ! Input
231  chinfo(n:n) , & ! Input
232  self%atm_K , & ! K-MATRIX Output
233  self%sfc_K , & ! K-MATRIX Output
234  rts ) ! FORWARD Output
235  if ( err_stat /= success ) THEN
236  message = 'Error calling CRTM (setTraj) K-Matrix Model for '//trim(self%rc%SENSOR_ID(n))
237  call display_message( program_name, message, failure )
238  stop
239  end if
240 
241 
242  ! Deallocate the structures
243  ! -------------------------
244  call crtm_geometry_destroy(geo)
245  call crtm_atmosphere_destroy(atm)
246  call crtm_rtsolution_destroy(rts_k)
247  call crtm_rtsolution_destroy(rts)
248  call crtm_surface_destroy(sfc)
249 
250 
251  ! Deallocate all arrays
252  ! ---------------------
253  deallocate(geo, atm, sfc, rts, rts_k, stat = alloc_stat)
254  if ( alloc_stat /= 0 ) THEN
255  message = 'Error deallocating structure arrays (setTraj)'
256  call display_message( program_name, message, failure )
257  stop
258  end if
259 
260  end do sensor_loop
261 
262 
263  ! Destroy CRTM instance
264  ! ---------------------
265  write( *, '( /5x, "Destroying the CRTM (setTraj)..." )' )
266  err_stat = crtm_destroy( chinfo )
267  if ( err_stat /= success ) THEN
268  message = 'Error destroying CRTM (setTraj)'
269  call display_message( program_name, message, failure )
270  stop
271  end if
272 
273 
274  ! Set flag that the tracectory was set
275  ! ------------------------------------
276  self%ltraj = .true.
277 
278 end subroutine ufo_radiance_tlad_settraj
279 
280 ! ------------------------------------------------------------------------------
281 
282 subroutine ufo_radiance_simobs_tl(self, geovals, hofx, obss)
284 implicit none
285 class(ufo_radiance_tlad), intent(in) :: self
286 type(ufo_geovals), intent(in) :: geovals
287 real(c_double), intent(inout) :: hofx(:)
288 type(c_ptr), value, intent(in) :: obss
289 
290 character(len=*), parameter :: myname_="ufo_radiance_simobs_tl"
291 character(max_string) :: err_msg
292 integer :: job, jprofile, jchannel, jlevel, ierr
293 type(ufo_geoval), pointer :: tv_d
294 
295 
296  ! Initial checks
297  ! --------------
298 
299  ! Check if trajectory was set
300  if (.not. self%ltraj) then
301  write(err_msg,*) myname_, ' trajectory wasnt set!'
302  call abor1_ftn(err_msg)
303  endif
304 
305  ! Check if nobs is consistent in geovals & hofx
306  if (geovals%nobs /= self%n_Profiles) then
307  write(err_msg,*) myname_, ' error: nobs inconsistent!'
308  call abor1_ftn(err_msg)
309  endif
310 
311  ! Initialize hofx
312  ! ---------------
313  hofx(:) = 0.0_kind_real
314 
315 
316  ! Temperature
317  ! -----------
318 
319  ! Check if variable is in geovals and get it
320  call ufo_geovals_get_var(geovals, var_tv, tv_d, status=ierr )
321  if (ierr/=0) then
322  write(err_msg,*) myname_, trim(var_tv), ' doesnt exist'
323  call abor1_ftn(err_msg)
324  endif
325 
326  ! Check model levels is consistent in geovals & crtm
327  if (tv_d%nval /= self%n_Layers) then
328  write(err_msg,*) myname_, ' error: layers inconsistent!'
329  call abor1_ftn(err_msg)
330  endif
331 
332  ! Multiply by Jacobian and add to hofx
333  job = 0
334  do jprofile = 1, self%n_Profiles
335  do jchannel = 1, self%n_Channels
336  job = job + 1
337  do jlevel = 1, tv_d%nval
338  hofx(job) = hofx(job) + &
339  self%atm_K(jchannel,jprofile)%Temperature(jlevel) * tv_d%vals(jlevel,jprofile)
340  enddo
341  enddo
342  enddo
343 
344 
345 end subroutine ufo_radiance_simobs_tl
346 
347 ! ------------------------------------------------------------------------------
348 
349 subroutine ufo_radiance_simobs_ad(self, geovals, hofx, obss)
351 implicit none
352 class(ufo_radiance_tlad), intent(in) :: self
353 type(ufo_geovals), intent(inout) :: geovals
354 real(c_double), intent(in) :: hofx(:)
355 type(c_ptr), value, intent(in) :: obss
356 
357 character(len=*), parameter :: myname_="ufo_radiance_simobs_ad"
358 character(max_string) :: err_msg
359 integer :: job, jprofile, jchannel, jlevel, ierr
360 type(ufo_geoval), pointer :: tv_d
361 
362 
363  ! Initial checks
364  ! --------------
365 
366  ! Check if trajectory was set
367  if (.not. self%ltraj) then
368  write(err_msg,*) myname_, ' trajectory wasnt set!'
369  call abor1_ftn(err_msg)
370  endif
371 
372  ! Check if nobs is consistent in geovals & hofx
373  if (geovals%nobs /= self%n_Profiles) then
374  write(err_msg,*) myname_, ' error: nobs inconsistent!'
375  call abor1_ftn(err_msg)
376  endif
377 
378 
379  ! Temperature
380  ! -----------
381 
382  ! Check if variable is in geovals and get it
383  call ufo_geovals_get_var(geovals, var_tv, tv_d, status=ierr )
384  if (ierr/=0) then
385  write(err_msg,*) myname_, trim(var_tv), ' doesnt exist'
386  call abor1_ftn(err_msg)
387  endif
388 
389  ! allocate if not yet allocated
390  if (.not. allocated(tv_d%vals)) then
391  tv_d%nobs = self%n_Profiles
392  tv_d%nval = self%n_Layers
393  allocate(tv_d%vals(tv_d%nval,tv_d%nobs))
394  tv_d%vals = 0.0_kind_real
395  endif
396 
397 
398  ! Multiply by Jacobian and add to hofx (adjoint)
399  job = 0
400  do jprofile = 1, self%n_Profiles
401  do jchannel = 1, self%n_Channels
402  job = job + 1
403  do jlevel = 1, tv_d%nval
404  tv_d%vals(jlevel,jprofile) = tv_d%vals(jlevel,jprofile) + &
405  self%atm_K(jchannel,jprofile)%Temperature(jlevel) * hofx(job)
406  enddo
407  enddo
408  enddo
409 
410 
411  ! Once all geovals set replace flag
412  ! ---------------------------------
413  if (.not. geovals%linit ) geovals%linit=.true.
414 
415 
416 end subroutine ufo_radiance_simobs_ad
417 
418 ! ------------------------------------------------------------------------------
419 
420 end module ufo_radiance_tlad_mod
subroutine, public ufo_geovals_get_var(self, varname, geoval, status)
real(fp), parameter, public zero
subroutine ufo_radiance_simobs_ad(self, geovals, hofx, obss)
Fortran module to provide code shared between nonlinear and tlm/adm radiance calculations.
subroutine ufo_radiance_tlad_setup(self, c_conf)
subroutine, public load_atm_data(N_PROFILES, N_LAYERS, geovals, atm)
subroutine, public load_sfc_data(n_Profiles, n_Layers, N_Channels, geovals, sfc, chinfo, obss)
Fortran module to handle tl/ad for radiance observations.
subroutine, public load_geom_data(obss, geo)
subroutine ufo_radiance_tlad_delete(self)
subroutine, public rad_conf_setup(rc, c_conf)
subroutine, public rad_conf_delete(rc)
real(fp), parameter, public one
Fortran derived type for radiance trajectory.
subroutine crtm_version(version)
Definition: CRTM_Module.F90:79
type to hold interpolated fields required by the obs operators
subroutine ufo_radiance_simobs_tl(self, geovals, hofx, obss)
Fortran interface to ObsSpace.
Definition: obsspace_mod.F90:9
character(len=maxvarlen), public var_tv
subroutine ufo_radiance_tlad_settraj(self, geovals, obss)
type to hold interpolated field for one variable, one observation
subroutine, public delete(self)
Definition: qg_fields.F90:136