12 use fckit_configuration_module,
only: fckit_configuration
15 use missing_values_mod
31 character(len=MAXVARLEN),
public,
allocatable :: varin(:)
32 integer,
allocatable :: channels(:)
56 type(fckit_configuration),
intent(in) :: f_confOper
57 integer(c_int),
intent(in) :: channels(:)
61 character(len=max_string) :: err_msg
62 type(fckit_configuration) :: f_confOpts
63 logical :: request_cldfrac
65 call f_confoper%get_or_die(
"obs options",f_confopts)
69 write(err_msg,*)
'ufo_radiancecrtm_setup error: H2O must be included in CRTM Absorbers'
70 call abor1_ftn(err_msg)
73 write(err_msg,*)
'ufo_radiancecrtm_setup error: O3 must be included in CRTM Absorbers'
74 call abor1_ftn(err_msg)
80 nvars_in =
size(
varin_default) + self%conf%n_Absorbers + 2 * self%conf%n_Clouds
82 self%conf%n_Clouds > 0 .and. &
83 self%conf%Cloud_Fraction < 0.0
84 if ( request_cldfrac )
then
85 nvars_in = nvars_in + 1
88 if (trim(self%conf%salinity_option) ==
"on")
then
89 nvars_in = nvars_in + 1
92 allocate(self%varin(nvars_in))
96 do jspec = 1, self%conf%n_Absorbers
97 self%varin(ind) = self%conf%Absorbers(jspec)
100 do jspec = 1, self%conf%n_Clouds
101 self%varin(ind) = self%conf%Clouds(jspec,1)
103 self%varin(ind) = self%conf%Clouds(jspec,2)
106 if ( request_cldfrac )
then
110 if (trim(self%conf%salinity_option) ==
"on")
then
116 allocate(self%channels(
size(channels)))
117 self%channels(:) = channels(:)
135 use fckit_mpi_module,
only: fckit_mpi_comm
141 integer,
intent(in) :: nvars, nlocs
142 real(c_double),
intent(inout) :: hofx(nvars, nlocs)
144 type(c_ptr),
value,
intent(in) :: obss
147 character(*),
parameter :: PROGRAM_NAME =
'ufo_radiancecrtm_simobs'
148 character(255) :: message, version
149 character(max_string) :: err_msg
150 integer :: err_stat, alloc_stat
153 integer :: jvar, jprofile, jlevel, jchannel, ichannel, jspec
154 real(c_double) :: missing
155 type(fckit_mpi_comm) :: f_comm
156 real(kind_real) :: total_od, secant_term, wfunc_max
157 real(kind_real),
allocatable :: TmpVar(:)
158 real(kind_real),
allocatable :: Tao(:)
159 real(kind_real),
allocatable :: Wfunc(:)
161 integer :: n_Profiles, n_Layers, n_Channels
162 logical,
allocatable :: Skip_Profiles(:)
165 type(crtm_channelinfo_type) :: chinfo(self%conf%n_Sensors)
166 type(crtm_geometry_type),
allocatable :: geo(:)
169 type(crtm_atmosphere_type),
allocatable :: atm(:)
170 type(crtm_surface_type),
allocatable :: sfc(:)
171 type(crtm_rtsolution_type),
allocatable :: rts(:,:)
174 type(crtm_atmosphere_type),
allocatable :: atm_K(:,:)
175 type(crtm_surface_type),
allocatable :: sfc_K(:,:)
176 type(crtm_rtsolution_type),
allocatable :: rts_K(:,:)
177 type(crtm_options_type),
allocatable :: Options(:)
180 character(len=MAXVARLEN) :: varstr
181 character(len=MAXVARLEN),
dimension(hofxdiags%nvar) :: &
182 ystr_diags, xstr_diags
183 character(10),
parameter :: jacobianstr =
"_jacobian_"
184 integer :: str_pos(4), ch_diags(hofxdiags%nvar)
185 logical :: jacobian_needed
187 call obsspace_get_comm(obss, f_comm)
191 n_profiles = geovals%nlocs
212 err_stat = crtm_init( self%conf%SENSOR_ID, chinfo, &
213 file_path=trim(self%conf%COEFFICIENT_PATH), &
214 irwatercoeff_file=trim(self%conf%IRwaterCoeff_File), &
215 irlandcoeff_file=trim(self%conf%IRlandCoeff_File), &
216 irsnowcoeff_file=trim(self%conf%IRsnowCoeff_File), &
217 iricecoeff_file=trim(self%conf%IRiceCoeff_File), &
218 viswatercoeff_file=trim(self%conf%VISwaterCoeff_File), &
219 vislandcoeff_file=trim(self%conf%VISlandCoeff_File), &
220 vissnowcoeff_file=trim(self%conf%VISsnowCoeff_File), &
221 visicecoeff_file=trim(self%conf%VISiceCoeff_File), &
222 mwwatercoeff_file=trim(self%conf%MWwaterCoeff_File), &
224 message =
'Error initializing CRTM'
229 sensor_loop:
do n = 1, self%conf%n_Sensors
234 err_stat = crtm_channelinfo_subset(chinfo(n), self%channels, reset=.false.)
235 message =
'Error subsetting channels!'
240 n_channels = crtm_channelinfo_n_channels(chinfo(n))
244 allocate( geo( n_profiles ), &
247 rts( n_channels, n_profiles ), &
248 options( n_profiles ), &
250 message =
'Error allocating structure arrays'
253 if (n_layers > 0)
call crtm_rtsolution_create (rts, n_layers)
257 call crtm_atmosphere_create( atm, n_layers, self%conf%n_Absorbers, self%conf%n_Clouds, self%conf%n_Aerosols )
258 if ( any(.NOT. crtm_atmosphere_associated(atm)) )
THEN
259 message =
'Error allocating CRTM Forward Atmosphere structure'
260 CALL display_message( program_name, message, failure )
267 call crtm_surface_create(sfc, n_channels)
268 IF ( any(.NOT. crtm_surface_associated(sfc)) )
THEN
269 message =
'Error allocating CRTM Surface structure'
270 CALL display_message( program_name, message, failure )
274 CALL crtm_rtsolution_create(rts, n_layers )
278 call load_atm_data(n_profiles,n_layers,geovals,atm,self%conf)
279 call load_sfc_data(n_profiles,n_channels,self%channels,geovals,sfc,chinfo,obss,self%conf)
284 if (self%conf%inspect > 0)
then
285 call crtm_atmosphere_inspect(atm(self%conf%inspect))
286 call crtm_surface_inspect(sfc(self%conf%inspect))
287 call crtm_geometry_inspect(geo(self%conf%inspect))
288 call crtm_channelinfo_inspect(chinfo(n))
296 jacobian_needed = .false.
298 do jvar = 1, hofxdiags%nvar
299 varstr = hofxdiags%variables(jvar)
300 str_pos(4) = len_trim(varstr)
301 if (str_pos(4) < 1) cycle
302 str_pos(3) = index(varstr,
"_",back=.true.)
303 read(varstr(str_pos(3)+1:str_pos(4)),*, err=999) ch_diags(jvar)
304 999 str_pos(1) = index(varstr,jacobianstr) - 1
305 if (str_pos(1) == 0)
then
306 write(err_msg,*)
'ufo_radiancecrtm_simobs: _jacobian_ must be // &
307 & preceded by dependent variable in config: ', &
308 & hofxdiags%variables(jvar)
309 call abor1_ftn(err_msg)
310 else if (str_pos(1) > 0)
then
312 ystr_diags(jvar) = varstr(1:str_pos(1))
313 str_pos(2) = str_pos(1) + len(jacobianstr) + 1
314 jacobian_needed = .true.
315 str_pos(4) = str_pos(3) - str_pos(2)
316 xstr_diags(jvar)(1:str_pos(4)) = varstr(str_pos(2):str_pos(3)-1)
317 xstr_diags(jvar)(str_pos(4)+1:) =
""
320 xstr_diags(jvar) =
""
321 ystr_diags(jvar)(1:str_pos(3)-1) = varstr(1:str_pos(3)-1)
322 ystr_diags(jvar)(str_pos(3):) =
""
323 if (ch_diags(jvar) < 0) ystr_diags(jvar) = varstr
327 allocate(skip_profiles(n_profiles))
329 profile_loop:
do jprofile = 1, n_profiles
330 options(jprofile)%Skip_Profile = skip_profiles(jprofile)
332 do jlevel = atm(jprofile)%n_layers, 1, -1
333 if ( atm(jprofile)%level_pressure(jlevel) <= atm(jprofile)%level_pressure(jlevel-1) )
then
334 options(jprofile)%Skip_Profile = .true.
340 if (jacobian_needed)
then
343 allocate( atm_k( n_channels, n_profiles ), &
344 sfc_k( n_channels, n_profiles ), &
345 rts_k( n_channels, n_profiles ), &
347 message =
'Error allocating K structure arrays'
352 call crtm_atmosphere_create( atm_k, n_layers, self%conf%n_Absorbers, self%conf%n_Clouds, self%conf%n_Aerosols )
353 if ( any(.NOT. crtm_atmosphere_associated(atm_k)) )
THEN
354 message =
'Error allocating CRTM K-matrix Atmosphere structure (setTraj)'
355 CALL display_message( program_name, message, failure )
361 call crtm_surface_create( sfc_k, n_channels)
362 IF ( any(.NOT. crtm_surface_associated(sfc_k)) )
THEN
363 message =
'Error allocating CRTM K-matrix Surface structure (setTraj)'
364 CALL display_message( program_name, message, failure )
370 call crtm_atmosphere_zero( atm_k )
371 call crtm_surface_zero( sfc_k )
375 rts_k%Radiance = zero
376 rts_k%Brightness_Temperature = one
381 err_stat = crtm_k_matrix( atm , &
390 message =
'Error calling CRTM (setTraj) K-Matrix Model for '//trim(self%conf%SENSOR_ID(n))
395 err_stat = crtm_forward( atm , &
401 message =
'Error calling CRTM Forward Model for '//trim(self%conf%SENSOR_ID(n))
411 missing = missing_value(missing)
416 if (.not.skip_profiles(m))
then
417 do l = 1,
size(self%channels)
418 hofx(l,m) = rts(l,m)%Brightness_Temperature
425 do jvar = 1, hofxdiags%nvar
426 if (len(trim(hofxdiags%variables(jvar))) < 1) cycle
428 if (ch_diags(jvar) > 0)
then
429 if (
size(pack(self%channels,self%channels==ch_diags(jvar))) /= 1)
then
430 write(err_msg,*)
'ufo_radiancecrtm_simobs: mismatch between// &
431 & h(x) channels(', self%channels,
') and// &
432 & ch_diags(jvar) = ', ch_diags(jvar)
433 call abor1_ftn(err_msg)
438 do ichannel = 1,
size(self%channels)
439 if (ch_diags(jvar) == self%channels(ichannel))
then
445 if (
allocated(hofxdiags%geovals(jvar)%vals)) &
446 deallocate(hofxdiags%geovals(jvar)%vals)
451 if (trim(xstr_diags(jvar)) ==
"")
then
453 select case(ystr_diags(jvar))
456 hofxdiags%geovals(jvar)%nval = n_layers
457 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
458 hofxdiags%geovals(jvar)%vals = missing
459 do jprofile = 1, n_profiles
460 if (.not.skip_profiles(jprofile))
then
461 do jlevel = 1, hofxdiags%geovals(jvar)%nval
462 hofxdiags%geovals(jvar)%vals(jlevel,jprofile) = &
463 rts(jchannel,jprofile) % layer_optical_depth(jlevel)
470 hofxdiags%geovals(jvar)%nval = 1
471 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
472 hofxdiags%geovals(jvar)%vals = missing
473 do jprofile = 1, n_profiles
474 if (.not.skip_profiles(jprofile))
then
475 hofxdiags%geovals(jvar)%vals(1,jprofile) = &
476 rts(jchannel,jprofile) % Radiance
482 hofxdiags%geovals(jvar)%nval = 1
483 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
484 hofxdiags%geovals(jvar)%vals = missing
485 do jprofile = 1, n_profiles
486 if (.not.skip_profiles(jprofile))
then
490 hofxdiags%geovals(jvar)%vals(1,jprofile) = &
491 rts(jchannel,jprofile) % Tb_Clear
497 hofxdiags%geovals(jvar)%nval = 1
498 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
499 hofxdiags%geovals(jvar)%vals = missing
500 do jprofile = 1, n_profiles
501 if (.not.skip_profiles(jprofile))
then
502 hofxdiags%geovals(jvar)%vals(1,jprofile) = &
503 rts(jchannel,jprofile) % Brightness_Temperature
509 hofxdiags%geovals(jvar)%nval = n_layers
510 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
511 hofxdiags%geovals(jvar)%vals = missing
512 allocate(tmpvar(n_profiles))
513 call obsspace_get_db(obss,
"MetaData",
"sensor_zenith_angle", tmpvar)
514 do jprofile = 1, n_profiles
515 if (.not.skip_profiles(jprofile))
then
516 secant_term = one/cos(tmpvar(jprofile)*
deg2rad)
518 do jlevel = 1, n_layers
519 total_od = total_od + rts(jchannel,jprofile) % layer_optical_depth(jlevel)
520 hofxdiags%geovals(jvar)%vals(jlevel,jprofile) = &
521 exp(-min(limit_exp,total_od*secant_term))
529 hofxdiags%geovals(jvar)%nval = n_layers
530 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
531 hofxdiags%geovals(jvar)%vals = missing
532 allocate(tmpvar(n_profiles))
533 allocate(tao(n_layers))
534 call obsspace_get_db(obss,
"MetaData",
"sensor_zenith_angle", tmpvar)
535 do jprofile = 1, n_profiles
536 if (.not.skip_profiles(jprofile))
then
538 secant_term = one/cos(tmpvar(jprofile)*
deg2rad)
540 do jlevel = 1, n_layers
541 total_od = total_od + rts(jchannel,jprofile) % layer_optical_depth(jlevel)
542 tao(jlevel) = exp(-min(limit_exp,total_od*secant_term))
545 do jlevel = n_layers-1, 1, -1
546 hofxdiags%geovals(jvar)%vals(jlevel,jprofile) = &
547 abs( (tao(jlevel+1)-tao(jlevel))/ &
548 (log(atm(jprofile)%pressure(jlevel+1))- &
549 log(atm(jprofile)%pressure(jlevel))) )
551 hofxdiags%geovals(jvar)%vals(n_layers,jprofile) = &
552 hofxdiags%geovals(jvar)%vals(n_layers-1,jprofile)
560 hofxdiags%geovals(jvar)%nval = 1
561 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
562 hofxdiags%geovals(jvar)%vals = missing
563 allocate(tmpvar(n_profiles))
564 allocate(tao(n_layers))
565 allocate(wfunc(n_layers))
566 call obsspace_get_db(obss,
"MetaData",
"sensor_zenith_angle", tmpvar)
567 do jprofile = 1, n_profiles
568 if (.not.skip_profiles(jprofile))
then
570 secant_term = one/cos(tmpvar(jprofile)*
deg2rad)
572 do jlevel = 1, n_layers
573 total_od = total_od + rts(jchannel,jprofile) % layer_optical_depth(jlevel)
574 tao(jlevel) = exp(-min(limit_exp,total_od*secant_term))
577 do jlevel = n_layers-1, 1, -1
579 abs( (tao(jlevel+1)-tao(jlevel))/ &
580 (log(atm(jprofile)%pressure(jlevel+1))- &
581 log(atm(jprofile)%pressure(jlevel))) )
583 wfunc(n_layers) = wfunc(n_layers-1)
586 do jlevel = n_layers-1, 1, -1
587 if (wfunc(jlevel) > wfunc_max)
then
588 wfunc_max = wfunc(jlevel)
589 hofxdiags%geovals(jvar)%vals(1,jprofile) = jlevel
599 write(err_msg,*)
'ufo_radiancecrtm_simobs: //&
600 & ObsDiagnostic is unsupported, ', &
601 & hofxdiags%variables(jvar)
603 hofxdiags%geovals(jvar)%nval = 1
604 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
605 hofxdiags%geovals(jvar)%vals = missing
607 else if (ystr_diags(jvar) ==
var_tb)
then
609 select case (xstr_diags(jvar))
612 hofxdiags%geovals(jvar)%nval = n_layers
613 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
614 hofxdiags%geovals(jvar)%vals = missing
615 do jprofile = 1, n_profiles
616 if (.not.skip_profiles(jprofile))
then
617 do jlevel = 1, hofxdiags%geovals(jvar)%nval
618 hofxdiags%geovals(jvar)%vals(jlevel,jprofile) = &
619 atm_k(jchannel,jprofile) % Temperature(jlevel)
625 hofxdiags%geovals(jvar)%nval = n_layers
626 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
627 hofxdiags%geovals(jvar)%vals = missing
629 do jprofile = 1, n_profiles
630 if (.not.skip_profiles(jprofile))
then
631 do jlevel = 1, hofxdiags%geovals(jvar)%nval
632 hofxdiags%geovals(jvar)%vals(jlevel,jprofile) = &
633 atm_k(jchannel,jprofile) % Absorber(jlevel,jspec)
640 hofxdiags%geovals(jvar)%nval = 1
641 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
642 hofxdiags%geovals(jvar)%vals = missing
643 do jprofile = 1, n_profiles
644 if (.not.skip_profiles(jprofile))
then
645 hofxdiags%geovals(jvar)%vals(1,jprofile) = &
646 sfc_k(jchannel,jprofile) % water_temperature &
647 + sfc_k(jchannel,jprofile) % land_temperature &
648 + sfc_k(jchannel,jprofile) % ice_temperature &
649 + sfc_k(jchannel,jprofile) % snow_temperature
655 hofxdiags%geovals(jvar)%nval = 1
656 allocate(hofxdiags%geovals(jvar)%vals(hofxdiags%geovals(jvar)%nval,n_profiles))
657 hofxdiags%geovals(jvar)%vals = missing
658 do jprofile = 1, n_profiles
659 if (.not.skip_profiles(jprofile))
then
660 hofxdiags%geovals(jvar)%vals(1,jprofile) = &
661 rts_k(jchannel,jprofile) % surface_emissivity
665 write(err_msg,*)
'ufo_radiancecrtm_simobs: //&
666 & ObsDiagnostic is unsupported, ', &
667 & hofxdiags%variables(jvar)
668 call abor1_ftn(err_msg)
671 write(err_msg,*)
'ufo_radiancecrtm_simobs: //&
672 & ObsDiagnostic is unsupported, ', &
673 & hofxdiags%variables(jvar)
674 call abor1_ftn(err_msg)
680 call crtm_geometry_destroy(geo)
681 call crtm_atmosphere_destroy(atm)
682 call crtm_surface_destroy(sfc)
683 call crtm_rtsolution_destroy(rts)
687 deallocate(geo, atm, sfc, rts, options, skip_profiles, stat = alloc_stat)
688 message =
'Error deallocating structure arrays'
691 if (jacobian_needed)
then
694 call crtm_atmosphere_destroy(atm_k)
695 call crtm_surface_destroy(sfc_k)
696 call crtm_rtsolution_destroy(rts_k)
700 deallocate(atm_k, sfc_k, rts_k, stat = alloc_stat)
701 message =
'Error deallocating K structure arrays'
711 err_stat = crtm_destroy( chinfo )
712 message =
'Error destroying CRTM'