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