FV3 Bundle
ufo_aod_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 aod observations
7 
8 MODULE ufo_aod_mod
9 
10  use iso_c_binding
11  use ufo_vars_mod
12  use ioda_locs_mod
13  use ufo_geovals_mod
14  use kinds
15  USE ufo_aod_misc
16  use crtm_module
17  USE ufo_basis_mod, only: ufo_basis
18  use obsspace_mod
19 
20  implicit none
21 
22  public :: ufo_aod
23 
24  private
25  integer, parameter :: max_string=800
26  LOGICAL, PARAMETER :: ice4qsat=.true.
27 
28  REAL(fp),PARAMETER:: &
29  &ttp = 2.7316e+2_fp, &
30  &psat = 6.1078e+2_fp,&
31  &rd = 2.8705e+2_fp,&
32  &rv = 4.6150e+2_fp,&
33  &cv = 7.1760e+2_fp,&
34  &cliq = 4.1855e+3_fp,&
35  &csol = 2.1060e+3_fp,&
36  &cvap = 1.8460e+3_fp,&
37  &hvap = 2.5000e+6_fp,&
38  &hfus = 3.3358e+5_fp,&
39  &grav = 9.81_fp
40 
41  REAL(fp),PARAMETER :: &
42  &tmix = ttp-20._fp,&
43  &hsub = hvap+hfus,&
44  &eps = rd/rv,&
45  &omeps=one-eps,&
46  &dldt =cvap-cliq,&
47  &dldti = cvap-csol,&
48  &xa = -(dldt/rv),&
49  &xai = -(dldti/rv),&
50  &xb = xa+hvap/(rv*ttp),&
51  &xbi = xai+hsub/(rv*ttp)
52 
53  LOGICAL :: flip_vertical
54 
55 
56  !> Fortran derived type for aod trajectory
57  type, extends(ufo_basis) :: ufo_aod
58  contains
59  procedure :: simobs => ufo_aod_simobs
60  end type ufo_aod
61 
62 contains
63 
64 ! ------------------------------------------------------------------------------
65 
66  SUBROUTINE ufo_aod_simobs(self, geovals, hofx, obss)
67  implicit none
68  class(ufo_aod), intent(in) :: self
69  type(ufo_geovals), intent(in) :: geovals
70  real(kind_real), intent(inout) :: hofx(:)
71  type(c_ptr), value, intent(in) :: obss
72 
73  real(kind_real), allocatable :: Aod_Obs(:,:)
74  real(kind_real), allocatable :: Omg_Aod(:,:)
75 
76  !*************************************************************************************
77  !******* Begin CRTM block ************************************************************
78  !*************************************************************************************
79 
80  ! --------------------------
81  ! Some non-CRTM-y Parameters
82  ! --------------------------
83  CHARACTER(*), PARAMETER :: PROGRAM_NAME = 'ufo_aod_mod.F90'
84 
85 
86  ! ============================================================================
87  ! STEP 2. **** SET UP SOME PARAMETERS FOR THE CRTM RUN ****
88  !
89 
90  ! Directory location of coefficients
91  !** temporary local path for storing coefficient files (2 files per sensor), also several non-sensor specific binary files needed for other things
92  !** NOTE: for some strange reason, this compiled as little endian, even though BIG_ENDIAN was specified on the compiler flags --BTJ
93  CHARACTER(*), PARAMETER :: ENDIAN_TYPE='little_endian'
94  CHARACTER(*), PARAMETER :: COEFFICIENT_PATH='Data/'
95 
96  ! Profile dimensions
97  !** UFO to provide N_LAYERS, N_ABSORBERS, N_CLOUDS, N_AEROSOLS
98 
99 
100  INTEGER, PARAMETER :: N_ABSORBERS = 2 !** UFO
101  INTEGER, PARAMETER :: N_CLOUDS = 0 !** UFO
102  INTEGER, PARAMETER :: n_aerosols_gocart_crtm = 14,n_aerosols=n_aerosols_gocart_crtm
103 
104 
105  INTEGER :: N_PROFILES
106  INTEGER :: N_LAYERS
107 
108 
109  ! Sensor information
110  INTEGER , PARAMETER :: N_SENSORS = 1
111  CHARACTER(*), PARAMETER :: SENSOR_ID(N_SENSORS) = (/'v.viirs-m_npp'/) !** UFO to provide sensor name
112 
113  CHARACTER(max_string) :: err_msg
114 
115 
116  ! ---------
117  ! Local Variables
118  ! ---------
119  CHARACTER(256) :: message, version
120  INTEGER :: err_stat, alloc_stat
121  INTEGER :: n_channels
122  INTEGER :: l, m, n, nc, i,k
123  real(fp) :: cf
124 
125 
126 
127  ! ============================================================================
128  ! STEP 3. **** DEFINE THE CRTM INTERFACE STRUCTURES ****
129  !
130  ! 3a. Define the "non-demoninational" arguments
131  ! ---------------------------------------------
132  TYPE(CRTM_ChannelInfo_type) :: chinfo(N_SENSORS)
133 
134 
135  ! 3b. Define the FORWARD variables
136  ! --------------------------------
137  TYPE(CRTM_Atmosphere_type), ALLOCATABLE :: atm(:)
138  TYPE(CRTM_RTSolution_type), ALLOCATABLE :: rts(:,:)
139 
140 
141  ! 3c. Define the K-MATRIX variables
142  ! ---------------------------------
143  TYPE(CRTM_Atmosphere_type), ALLOCATABLE :: atm_K(:,:)
144  TYPE(CRTM_RTSolution_type), ALLOCATABLE :: rts_K(:,:)
145  ! ============================================================================
146 
147  TYPE(CRTM_Aerosol_type), ALLOCATABLE :: aerosols(:)
148 
149  TYPE(ufo_geoval), pointer :: geoval
150  character(MAXVARLEN) :: varname
151  integer :: ivar
152  integer :: ierr
153 
154  integer :: nobs
155  integer :: nlocs
156  character(len=3) :: chan_num
157  character(len=100) :: var_name
158  REAL(fp), allocatable :: rmse(:)
159  real(fp), allocatable :: diff(:,:)
160  real(kind_real), allocatable :: ztmp(:)
161 
162  ! Program header
163  ! --------------
164 
165  nobs = obsspace_get_nobs(obss)
166  nlocs = obsspace_get_nlocs(obss)
167 
168  n_profiles=geovals%nobs
169 
170  varname=var_aerosols(1)
171 
172  call ufo_geovals_get_var(geovals,varname, geoval,status=ierr)
173  IF (ierr==0) THEN
174  n_layers=SIZE(geoval%vals,1)
175  ELSE
176  err_msg=trim(varname)//' not found - Stopping'
177  CALL abor1_ftn(err_msg)
178  ENDIF
179 
180 
181  ALLOCATE(atm(n_profiles),aerosols(n_aerosols))
182 
183 
184  CALL crtm_version( version )
185  CALL program_message( program_name, &
186  'Check/example program for the CRTM Forward and K-Matrix functions using '//&
187  ENDIAN_TYPE//' coefficient datafiles', &
188  'CRTM Version: '//trim(version) )
189 
190  ! ============================================================================
191  ! STEP 4. **** INITIALIZE THE CRTM ****
192  !
193  ! 4a. Initialise all the sensors at once
194  ! --------------------------------------
195  !** NOTE: CRTM_Init points to the various binary files needed for CRTM. See the
196  !** CRTM_Lifecycle.f90 for more details.
197  WRITE( *,'(/5x,"Initializing the CRTM...")' )
198  err_stat = crtm_init( sensor_id, &
199  chinfo, &
200  file_path=coefficient_path, &
201  quiet=.true.)
202  IF ( err_stat /= success ) THEN
203  message = 'Error initializing CRTM'
204  CALL display_message( program_name, message, failure )
205  stop
206  END IF
207 
208  ! 4b. Output some channel information
209  ! -----------------------------------
210  n_channels = sum(crtm_channelinfo_n_channels(chinfo))
211  !WRITE( *,'(/5x,"Processing a total of ",i0," channels...", i0, " layers..")' ) n_channels, N_LAYERS
212  DO n = 1, n_sensors
213  !WRITE( *,'(7x,i0," from ",a)' ) &
214  ! CRTM_ChannelInfo_n_Channels(chinfo(n)), TRIM(SENSOR_ID(n))
215  END DO
216  ! ============================================================================
217  ! Begin loop over sensors
218  !** UFO: this loop isn't necessary if we're calling CRTM for each sensor -- it's
219  ! not clear to me whether it's more efficient to call all sensors at once
220  ! or do each one individually. I'm leaving this capability intact.
221  !
222  ! ----------------------------------------------------------------------------
223  sensor_loop: DO n = 1, n_sensors
224 
225  ! ==========================================================================
226  ! STEP 5. **** ALLOCATE STRUCTURE ARRAYS ****
227  !
228  ! 5a. Determine the number of channels
229  ! for the current sensor
230  ! ------------------------------------
231  n_channels = crtm_channelinfo_n_channels(chinfo(n))
232 
233  ! 5b. Allocate the ARRAYS
234  ! -----------------------
235  ALLOCATE( rts( n_channels, n_profiles ), &
236  atm_k( n_channels, n_profiles ), &
237  rts_k( n_channels, n_profiles ), &
238  stat = alloc_stat )
239  IF ( alloc_stat /= 0 ) THEN
240  message = 'Error allocating structure arrays'
241  CALL display_message( program_name, message, failure )
242  stop
243  END IF
244 
245  ! 5c. Allocate the STRUCTURE INTERNALS
246  ! NOTE: Only the Atmosphere structures
247  ! are allocated in this example
248  ! ----------------------------------------
249  ! The input FORWARD structure
250  CALL crtm_atmosphere_create( atm, n_layers, n_absorbers, n_clouds, n_aerosols )
251  IF ( any(.NOT. crtm_atmosphere_associated(atm)) ) THEN
252  message = 'Error allocating CRTM Forward Atmosphere structure'
253  CALL display_message( program_name, message, failure )
254  stop
255  END IF
256 
257  ! The output K-MATRIX structure
258  CALL crtm_atmosphere_create( atm_k, n_layers, n_absorbers, n_clouds, n_aerosols )
259  IF ( any(.NOT. crtm_atmosphere_associated(atm_k)) ) THEN
260  message = 'Error allocating CRTM K-matrix Atmosphere structure'
261  CALL display_message( program_name, message, failure )
262  stop
263  END IF
264 
265  CALL crtm_rtsolution_create(rts, n_layers )
266  CALL crtm_rtsolution_create(rts_k, n_layers )
267 
268  ! ==========================================================================
269 
270  ! ==========================================================================
271  ! STEP 6. **** ASSIGN INPUT DATA ****
272  !
273  ! 6a. Atmosphere and Surface input
274  ! NOTE: that this is the hard part (in my opinion :o). The mechanism by
275  ! by which the atmosphere and surface data are loaded in to their
276  ! respective structures below was done purely to keep the step-by-step
277  ! instructions in this program relatively "clean".
278  ! ------------------------------------------------------------------------
279  !** UFO NOTE: this is where input data from UFO/OOPS will be loaded
280  !** subroutines not necessary, but helps cleanly separate atmos
281  !** and surface data.
282 
283  CALL load_atm_data() !** NOTE: could be moved out of sensor loop
284 
285  IF (n_aerosols > 0) CALL load_aerosol_data()
286 
287  CALL crtm_atmosphere_zero( atm_k )
288 
289  ! 7b. Inintialize the K-matrix INPUT so
290  ! that the results are dTb/dx
291  ! -------------------------------------
292  rts_k%Radiance = zero
293  rts_k%Brightness_Temperature = zero
294 
295  DO m = 1, n_profiles
296  DO l = 1, n_channels
297  rts_k(l,m)%layer_optical_depth = one
298  ENDDO
299  ENDDO
300 
301  ! ==========================================================================
302 
303  ! ==========================================================================
304  ! STEP 8. **** CALL THE CRTM FUNCTIONS FOR THE CURRENT SENSOR ****
305  !
306  call crtm_atmosphere_inspect(atm)
307  call crtm_channelinfo_inspect(chinfo(1))
308 
309 ! 8b.1 The K-matrix model for AOD
310 ! ----------------------
311  err_stat = crtm_aod_k( atm, & ! FORWARD Input
312  rts_k , & ! K-MATRIX Input
313  chinfo(n:n) , & ! Input
314  rts , & ! FORWARD Output
315  atm_k ) ! K-MATRIX Output
316  IF ( err_stat /= success ) THEN
317  message = 'Error calling CRTM K-Matrix Model for '//trim(sensor_id(n))
318  CALL display_message( program_name, message, failure )
319  stop
320  END IF
321 
322  ! ============================================================================
323  ! 8c. **** OUTPUT THE RESULTS TO SCREEN (optional) ****
324  !
325  ! User should read the user guide or the source code of the routine
326  ! CRTM_RTSolution_Inspect in the file CRTM_RTSolution_Define.f90 to
327  ! select the needed variables for outputs. These variables are contained
328  ! in the structure RTSolution.
329 
330  ALLOCATE(diff(n_channels,n_profiles),rmse(n_channels))
331 
332  allocate(aod_obs(n_profiles, n_channels))
333  allocate(omg_aod(n_profiles, n_channels))
334  do l = 1, n_channels
335  write(chan_num, '(I0)') l
336 
337  var_name = 'aerosol_optical_depth_' // trim(chan_num) // '_'
338  call obsspace_get_db(obss, "ObsValue", var_name, aod_obs(:,l))
339 
340  var_name = 'obs_minus_forecast_unadjusted_' // trim(chan_num) // '_'
341  call obsspace_get_db(obss, "OmF", var_name, omg_aod(:,l))
342  enddo
343 
344  rmse = 0
345  DO m = 1, n_profiles
346  DO l = 1, n_channels
347  diff(l,m) = sum(rts(l,m)%layer_optical_depth(:)) - (aod_obs(m,l) - omg_aod(m,l))
348  rmse(l) = rmse(l) + diff(l,m)**2
349  END DO
350  ENDDO
351 
352  rmse=sqrt(rmse/n_profiles)
353 
354  print *,'N_profiles', n_profiles
355  DO l = 1, n_channels
356  print *, 'Channel: ',l
357  print *, 'Max difference: ', maxval(abs(diff(l,:)))
358  print *, 'RMSE: ', rmse(l)
359  ENDDO
360 
361  DEALLOCATE(diff,rmse)
362 
363  deallocate(aod_obs)
364  deallocate(omg_aod)
365 
366  ! output to hofx structure
367  hofx(:) = 0.0
368  i = 1
369  do m = 1, n_profiles
370  do l = 1, n_channels
371  hofx(i) = sum(rts(l,m)%layer_optical_depth)
372  i = i + 1
373  enddo
374  enddo
375  ! ==========================================================================
376  ! STEP 9. **** CLEAN UP FOR NEXT SENSOR ****
377  !
378  ! 9a. Deallocate the structures
379  ! -----------------------------
380  CALL crtm_atmosphere_destroy(atm_k)
381  CALL crtm_atmosphere_destroy(atm)
382  CALL crtm_rtsolution_destroy(rts_k)
383  CALL crtm_rtsolution_destroy(rts)
384 
385  !** NOTE: Not 100% clear if any of the RTS structures need to be destroyed.
386 
387  ! 9b. Deallocate the arrays !** NOTE: this is required
388  ! -------------------------
389  DEALLOCATE(rts, rts_k, atm_k, stat = alloc_stat)
390  IF ( alloc_stat /= 0 ) THEN
391  message = 'Error allocating structure arrays'
392  CALL display_message( program_name, message, failure )
393  stop
394  END IF
395  ! ==========================================================================
396 
397  END DO sensor_loop
398 
399  ! ==========================================================================
400  ! 10. **** DESTROY THE CRTM ****
401  !
402  WRITE( *, '( /5x, "Destroying the CRTM..." )' )
403  err_stat = crtm_destroy( chinfo )
404  IF ( err_stat /= success ) THEN
405  message = 'Error destroying CRTM'
406  CALL display_message( program_name, message, failure )
407  stop
408  END IF
409  ! ==========================================================================
410 
411  CONTAINS
412 
413  ! ==========================================================================
414  ! Below are some internal procedures that load the
415  ! necessary input structures with some pretend data
416  ! ==========================================================================
417 
418  !
419  ! Internal subprogam to load some test profile data
420  !
421  SUBROUTINE load_atm_data()
422  implicit none
423  ! Local variables
424  INTEGER :: nc, NL
425  INTEGER :: k1, k2
426 
427  ! 4a.1 Profile #1
428  ! ---------------
429  ! ...Profile and absorber definitions (fake/placeholder()
430 
431 
432 !!$ 1 Temperature
433 !!$ 2 Water vapor
434 !!$ 3 Pressure
435 !!$ 4 Level pressure
436 
437  !** populate the atmosphere structures for CRTM (atm(k1), for the k1-th profile)
438 
439 
440  k1=1
441 
442  varname=var_prs
443  call ufo_geovals_get_var(geovals, varname, geoval)
444 
445  IF (geoval%vals(1,k1) > geoval%vals(n_layers,k1)) THEN
446  flip_vertical=.true.
447  ELSE
448  flip_vertical=.false.
449  ENDIF
450 
451  DO k1 = 1,n_profiles
452 
453  varname=var_t
454  call ufo_geovals_get_var(geovals, varname, geoval)
455  IF (flip_vertical) THEN
456  atm(k1)%Temperature(1:n_layers) = geoval%vals(n_layers:1:-1,k1)
457  ELSE
458  atm(k1)%Temperature(1:n_layers) = geoval%vals(:,k1)
459  ENDIF
460 ! print *, 'Temperature:', atm(k1)%Temperature(1:2), geoval%vals(1:2,k1)
461 
462  varname=var_prs
463  call ufo_geovals_get_var(geovals, varname, geoval)
464  IF (flip_vertical) THEN
465  atm(k1)%Pressure(1:n_layers) = geoval%vals(n_layers:1:-1,k1)
466  ELSE
467  atm(k1)%Pressure(1:n_layers) = geoval%vals(:,k1)
468  ENDIF
469 ! print *, 'Pressure:', atm(k1)%Pressure(1:2), geoval%vals(1:2,k1)
470 
471 
472  varname=var_prsi
473  call ufo_geovals_get_var(geovals, varname, geoval)
474  IF (flip_vertical) THEN
475  atm(k1)%Level_Pressure(0:n_layers) = geoval%vals(n_layers+1:1:-1,k1)
476  ELSE
477  atm(k1)%Level_Pressure(0:n_layers) = geoval%vals(:,k1)
478  ENDIF
479 ! print *, 'level_pressure:', atm(k1)%Level_Pressure(0:1), geoval%vals(1:2,k1)
480 
481  atm(k1)%Climatology = us_standard_atmosphere
482 
483  atm(k1)%Absorber_Id(1:1) = (/ h2o_id /)
484  atm(k1)%Absorber_Units(1:1) = (/ mass_mixing_ratio_units /)
485  varname=var_mixr
486  call ufo_geovals_get_var(geovals, varname, geoval)
487  IF (flip_vertical) THEN
488  atm(k1)%Absorber(1:n_layers,1) = geoval%vals(n_layers:1:-1,k1)
489  ELSE
490  atm(k1)%Absorber(1:n_layers,1) = geoval%vals(:,k1)
491  ENDIF
492 ! print *, 'water vapor:', atm(k1)%Absorber(1:2,1), geoval%vals(1:2,k1)
493 
494  atm(k1)%Absorber_Id(2:2) = (/ o3_id /)
495  atm(k1)%Absorber_Units(2:2) = (/ volume_mixing_ratio_units /)
496  atm(k1)%Absorber(1:n_layers,2)=1.e-10
497 
498  ENDDO
499 
500 
501  END SUBROUTINE load_atm_data
502 
503  SUBROUTINE load_aerosol_data()
505  USE crtm_aerosolcoeff, ONLY: aeroc
506 
507  REAL(fp), DIMENSION(N_LAYERS) :: ugkg_kgm2,qsat,rh,prsl,tsen,p25
508 
509 ! Local variables
510  INTEGER :: nc, NL
511  INTEGER :: k1, k2
512 
513 ! 4a.1 Profile #1
514 ! ---------------
515 ! ...Profile and absorber definitions (fake/placeholder()
516 
517  CHARACTER(len=MAXVARLEN) :: varname
518 
519  INTEGER :: n_aerosols_all
520 
521  INTEGER :: i,ii,k,m
522 
523  DO m=1,n_profiles
524 
525 !ug2kg && hPa2Pa
526  DO k=1,n_layers
527  ugkg_kgm2(k)=1.0e-9_fp*(atm(m)%Level_Pressure(k)-&
528  &atm(m)%Level_Pressure(k-1))*100_fp/grav
529  prsl(k)=atm(m)%Pressure(n_layers-k+1)*0.1_fp ! must be in cb for genqsat
530  tsen(k)=atm(m)%Temperature(n_layers-k+1)
531  ENDDO
532 
533  CALL genqsat(qsat,tsen,prsl,n_layers,ice4qsat)
534 
535  DO k=1,n_layers
536  rh(k)=atm(m)%Absorber(k,1)*1.e-3_fp/&
537  &qsat(n_layers-k+1)
538  ENDDO
539 
540  n_aerosols_all=SIZE(var_aerosols)
541 
542  IF (n_aerosols_all == naerosols_gocart_esrl) THEN
543 
544  DO i=1,n_aerosols_all
545  varname=var_aerosols(i)
546  IF (trim(varname) == 'p25') THEN
547  call ufo_geovals_get_var(geovals,varname, geoval)
548 
549  IF (flip_vertical) THEN
550  p25(1:n_layers)=geoval%vals(n_layers:1:-1,m)
551  ELSE
552  p25(1:n_layers)=geoval%vals(1:n_layers,m)
553  ENDIF
554 
555  p25=max(p25*ugkg_kgm2,zero)
556 
557  EXIT
558  ENDIF
559  ENDDO
560 
561  ELSE
562  p25=0_fp
563  ENDIF
564 
565  ii=0
566 
567  DO i=1,n_aerosols_all
568  varname=var_aerosols(i)
569  IF (trim(varname) == 'p25') cycle
570  ii=ii+1
571  call ufo_geovals_get_var(geovals,varname, geoval)
572 
573  IF (flip_vertical) THEN
574  atm(m)%aerosol(ii)%Concentration(1:n_layers)=geoval%vals(n_layers:1:-1,m)
575  ELSE
576  atm(m)%aerosol(ii)%Concentration(1:n_layers)=geoval%vals(1:n_layers,m)
577  ENDIF
578 
579  atm(m)%aerosol(ii)%Concentration=max(atm(m)%aerosol(ii)%Concentration*ugkg_kgm2,&
580  &small_value)
581 
582  SELECT CASE ( trim(varname))
583  CASE ('sulf')
584  atm(m)%aerosol(ii)%type = sulfate_aerosol
585 !rh needs to be from top to bottom
586  DO k=1,n_layers
587  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
588  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
589  &rh(k))
590  ENDDO
591 
592  CASE ('bc1')
593  atm(m)%aerosol(ii)%type = black_carbon_aerosol
594  atm(m)%Aerosol(ii)%Effective_Radius(:)=&
595  &aeroc%Reff(1,atm(m)%aerosol(ii)%type)
596  CASE ('bc2')
597  atm(m)%aerosol(ii)%type = black_carbon_aerosol
598  DO k=1,n_layers
599  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
600  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
601  &rh(k))
602  ENDDO
603 
604  CASE ('oc1')
605  atm(m)%aerosol(ii)%type = organic_carbon_aerosol
606  atm(m)%Aerosol(ii)%Effective_Radius(:)=&
607  &aeroc%Reff(1,atm(m)%aerosol(ii)%type)
608  CASE ('oc2')
609  atm(m)%aerosol(ii)%type = organic_carbon_aerosol
610  DO k=1,n_layers
611  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
612  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
613  &rh(k))
614  ENDDO
615 
616  CASE ('dust1')
617  atm(m)%aerosol(ii)%type = dust_aerosol
618  atm(m)%Aerosol(ii)%Effective_Radius(:)=0.55_fp
619  atm(m)%aerosol(ii)%Concentration=&
620  &atm(m)%aerosol(ii)%Concentration+0.78_fp*p25
621  CASE ('dust2')
622  atm(m)%aerosol(ii)%type = dust_aerosol
623  atm(m)%Aerosol(ii)%Effective_Radius(:)=1.4_fp
624  atm(m)%aerosol(ii)%Concentration=&
625  &atm(m)%aerosol(ii)%Concentration+0.22_fp*p25
626  CASE ('dust3')
627  atm(m)%aerosol(ii)%type = dust_aerosol
628  atm(m)%Aerosol(ii)%Effective_Radius(:)=2.4_fp
629  CASE ('dust4')
630  atm(m)%aerosol(ii)%type = dust_aerosol
631  atm(m)%Aerosol(ii)%Effective_Radius(:)=4.5_fp
632  CASE ('dust5')
633  atm(m)%aerosol(ii)%type = dust_aerosol
634  atm(m)%Aerosol(ii)%Effective_Radius(:)=8.0_fp
635 
636  CASE ('seas1')
637  atm(m)%aerosol(ii)%type = seasalt_ssam_aerosol
638  DO k=1,n_layers
639  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
640  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
641  &rh(k))
642  ENDDO
643  CASE ('seas2')
644  atm(m)%aerosol(ii)%type = seasalt_sscm1_aerosol
645  DO k=1,n_layers
646  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
647  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
648  &rh(k))
649  ENDDO
650  CASE ('seas3')
651  atm(m)%aerosol(ii)%type = seasalt_sscm2_aerosol
652  DO k=1,n_layers
653  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
654  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
655  &rh(k))
656  ENDDO
657  CASE ('seas4')
658  atm(m)%aerosol(ii)%type = seasalt_sscm3_aerosol
659  DO k=1,n_layers
660  atm(m)%Aerosol(ii)%Effective_Radius(k)=&
661  &gocart_aerosol_size(atm(m)%aerosol(ii)%type, &
662  &rh(k))
663  ENDDO
664  END SELECT
665 
666  ENDDO
667 
668  ENDDO
669 
670  END SUBROUTINE load_aerosol_data
671 
672  FUNCTION gocart_aerosol_size( itype, & ! Input
673  eh ) & ! Input in 0-1
674  result( r_eff ) ! in micrometer
676  IMPLICIT NONE
677 
678 !
679 ! modified from a function provided by Quanhua Liu
680 !
681  INTEGER ,INTENT(in) :: itype
682  REAL(fp) ,INTENT(in) :: eh
683 
684  INTEGER :: j1,j2,k
685  REAL(fp) :: h1
686  REAL(fp) :: r_eff
687 
688  j2 = 0
689  IF ( eh <= aeroc%RH(1) ) THEN
690  j1 = 1
691  ELSE IF ( eh >= aeroc%RH(aeroc%n_RH) ) THEN
692  j1 = aeroc%n_RH
693  ELSE
694  DO k = 1, aeroc%n_RH-1
695  IF ( eh < aeroc%RH(k+1) .AND. eh > aeroc%RH(k) ) THEN
696  j1 = k
697  j2 = k+1
698  h1 = (eh-aeroc%RH(k))/(aeroc%RH(k+1)-aeroc%RH(k))
699  EXIT
700  ENDIF
701  ENDDO
702  ENDIF
703 
704  IF ( j2 == 0 ) THEN
705  r_eff = aeroc%Reff(j1,itype )
706  ELSE
707  r_eff = (1.0_fp-h1)*aeroc%Reff(j1,itype ) + h1*aeroc%Reff(j2,itype )
708  ENDIF
709 
710  RETURN
711 
712  END FUNCTION gocart_aerosol_size
713 
714  SUBROUTINE genqsat(qsat,tsen,prsl,nsig,ice)
716 ! input argument list:
717 ! tsen - input sensibile temperature field (nlat,nlon,nsig)
718 ! prsl - input layer mean pressure field (nlat,nlon,nsig)
719 ! nsig - number of levels
720 ! ice - logical flag: T=include ice and ice-water effects,
721 ! depending on t, in qsat calcuations.
722 ! otherwise, compute qsat with respect to water surface
723 !
724 ! output argument list:
725 ! qsat - saturation specific humidity (output)
726 !
727 ! remarks: see modules used
728 !
729 ! attributes:
730 ! language: f90
731 ! machine: ibm RS/6000 SP
732 !
733 
734  IMPLICIT NONE
735 
736  LOGICAL ,INTENT(in ) :: ice
737  REAL(fp),DIMENSION(nsig), INTENT( out) :: qsat
738  REAL(fp),DIMENSION(nsig),INTENT(in ) :: tsen,prsl
739  INTEGER ,INTENT(in ) :: nsig
740 
741 
742  INTEGER k
743  REAL(fp) pw,tdry,tr,es,es2
744  REAL(fp) w,onep3,esmax
745  REAL(fp) desidt,deswdt,dwdt,desdt,esi,esw
746  REAL(fp) :: mint,estmax
747  INTEGER :: lmint
748 
749  onep3 = 1.e3_fp
750 
751  mint=340._fp
752  lmint=1
753 
754  DO k=1,nsig
755  IF((prsl(k) < 30._fp .AND. &
756  prsl(k) > 2._fp) .AND. &
757  tsen(k) < mint)THEN
758  lmint=k
759  mint=tsen(k)
760  END IF
761  END DO
762 
763  tdry = mint
764  tr = ttp/tdry
765 
766  IF (tdry >= ttp .OR. .NOT. ice) THEN
767  estmax = psat * (tr**xa) * exp(xb*(one-tr))
768  ELSEIF (tdry < tmix) THEN
769  estmax = psat * (tr**xai) * exp(xbi*(one-tr))
770  ELSE
771  w = (tdry - tmix) / (ttp - tmix)
772  estmax = w * psat * (tr**xa) * exp(xb*(one-tr)) &
773  + (one-w) * psat * (tr**xai) * exp(xbi*(one-tr))
774  ENDIF
775 
776  DO k = 1,nsig
777 
778  tdry = tsen(k)
779  tr = ttp/tdry
780  IF (tdry >= ttp .OR. .NOT. ice) THEN
781  es = psat * (tr**xa) * exp(xb*(one-tr))
782  ELSEIF (tdry < tmix) THEN
783  es = psat * (tr**xai) * exp(xbi*(one-tr))
784  ELSE
785  esw = psat * (tr**xa) * exp(xb*(one-tr))
786  esi = psat * (tr**xai) * exp(xbi*(one-tr))
787  w = (tdry - tmix) / (ttp - tmix)
788  es = w * psat * (tr**xa) * exp(xb*(one-tr)) &
789  + (one-w) * psat * (tr**xai) * exp(xbi*(one-tr))
790  ENDIF
791 
792  pw = onep3*prsl(k)
793  esmax = es
794  IF(lmint < k)THEN
795  esmax=0.1_fp*pw
796  esmax=min(esmax,estmax)
797  END IF
798  es2=min(es,esmax)
799  qsat(k) = eps * es2 / (pw - omeps * es2)
800 
801  END DO
802 
803  RETURN
804 
805  END SUBROUTINE genqsat
806 
807  END SUBROUTINE ufo_aod_simobs
808 
809 ! ------------------------------------------------------------------------------
810 
811 
812 END MODULE ufo_aod_mod
real(fp), parameter ttp
Definition: ufo_aod_mod.F90:28
subroutine, public ufo_geovals_get_var(self, varname, geoval, status)
character(len=maxvarlen), public var_mixr
real(fp), parameter, public zero
integer, parameter, public naerosols_gocart_esrl
character(len=maxvarlen), dimension(naerosols_gocart_esrl), public var_aerosols
character(len=maxvarlen), public var_prsi
real(fp), parameter omeps
Definition: ufo_aod_mod.F90:41
real(fp) function gocart_aerosol_size(itype, eh)
integer, parameter max_string
real(fp), parameter xai
Definition: ufo_aod_mod.F90:41
integer function, public obsspace_get_nobs(c_dom)
Return the number of observations.
subroutine genqsat(qsat, tsen, prsl, nsig, ice)
real(fp), parameter eps
Definition: ufo_aod_mod.F90:41
type(aerosolcoeff_type), target, save, public aeroc
Fortran module to handle aod observations.
Definition: ufo_aod_mod.F90:8
real(fp), parameter xb
Definition: ufo_aod_mod.F90:41
Fortran derived type for aod trajectory.
Definition: ufo_aod_mod.F90:57
real(fp), parameter, public one
subroutine load_aerosol_data()
subroutine load_atm_data()
real(fp), parameter tmix
Definition: ufo_aod_mod.F90:41
character(len=maxvarlen), public var_prs
real(fp), parameter xa
Definition: ufo_aod_mod.F90:41
subroutine crtm_version(version)
Definition: CRTM_Module.F90:79
real, parameter, public small_value
Definition: ufo_aod_misc.F90:9
logical flip_vertical
Definition: ufo_aod_mod.F90:53
real(fp), parameter xbi
Definition: ufo_aod_mod.F90:41
#define max(a, b)
Definition: mosaic_util.h:33
logical, parameter ice4qsat
Definition: ufo_aod_mod.F90:26
real(fp), parameter psat
Definition: ufo_aod_mod.F90:28
real(fp), parameter grav
Definition: ufo_aod_mod.F90:28
Fortran module handling observation locations.
#define min(a, b)
Definition: mosaic_util.h:32
character(len=maxvarlen), public var_t
Fortran interface to ObsSpace.
Definition: obsspace_mod.F90:9
subroutine ufo_aod_simobs(self, geovals, hofx, obss)
Definition: ufo_aod_mod.F90:67
integer function, public obsspace_get_nlocs(c_dom)
Return the number of observational locations.