FV3 Bundle
ODPS_CoordinateMapping.f90
Go to the documentation of this file.
1 !
2 ! ODPS_CoordinateMapping
3 !
4 ! Module containing routines to perform data mapping from user pressure space to
5 ! internal pressure space for the ODPS algorithm.
6 !
7 !
8 ! CREATION HISTORY:
9 ! Written by: Yong Han & Yong Chen, JCSDA, NOAA/NESDIS 10-NOV-2009
10 
11 
13 
14  ! -----------------
15  ! Environment setup
16  ! -----------------
17  ! Module use
18  USE type_kinds, ONLY: fp
22  USE odps_define, ONLY: odps_type
23  USE pafv_define, ONLY: pafv_type, &
26  USE crtm_parameters, ONLY: zero, one, two, &
27  earth_radius, &
29 
30  ! Disable implicit typing
31  IMPLICIT NONE
32 
33  ! ------------
34  ! Visibilities
35  ! ------------
36  ! Everything private by default
37  PRIVATE
38  ! variables and routines from USE modules
39  PUBLIC :: map_input
40  PUBLIC :: map_input_tl
41  PUBLIC :: map_input_ad
42  PUBLIC :: interpolate_profile
45  PUBLIC :: compute_interp_index
46 
47  ! Parameters used in the geopotential height calculation routines
48  ! a factor used in the virtual temperature Tv calculation
49  REAL(fp), PARAMETER :: c = (one/eps - one) / 1000.0_fp
50  ! a factor used in the scale height calculation ( H = CC*Tv)
51  REAL(fp), PARAMETER :: cc = 0.001_fp*r_dryair/g0
52  ! for using in SUBROUTINE LayerAvg
53  REAL(fp), PARAMETER :: smalldiff = 1.0e-20_fp
54 
55  ! -----------------
56  ! Module parameters
57  ! -----------------
58  ! RCS Id for the module
59  CHARACTER(*), PRIVATE, PARAMETER :: module_rcs_id = &
60  '$Id: ODPS_CoordinateMapping.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
61 
62 CONTAINS
63 
64 
65 !################################################################################
66 !################################################################################
67 !## ##
68 !## ## PUBLIC MODULE ROUTINES ## ##
69 !## ##
70 !################################################################################
71 !################################################################################
72 
73 !------------------------------------------------------------------------------
74 !
75 ! NAME:
76 ! Map_Input
77 !
78 ! PURPOSE:
79 ! Subroutine for data mapping from user pressure space to
80 ! internal pressure space for the ODPS algorithm.
81 !
82 ! CALLING SEQUENCE:
83 ! CALL Map_Input( Atm, & ! Input
84 ! TC, & ! Input
85 ! GeoInfo, & ! Input
86 ! Temperature, & ! Output
87 ! Absorber, & ! Output
88 ! User_Level_LnPressure, & ! Output
89 ! Ref_Level_LnPressure, & ! Output
90 ! Secant_Zenith, & ! Output
91 ! PAFV ) ! In/Output
92 !
93 ! INPUT ARGUMENTS:
94 !
95 ! Atm : CRTM Atmosphere structure containing the atmospheric
96 ! state data.
97 ! UNITS: N/A
98 ! TYPE: CRTM_Atmosphere_type
99 ! DIMENSION: Scalar
100 ! ATTRIBUTES: INTENT(IN)
101 !
102 ! TC: ODPS structure holding tau coefficients
103 ! UNITS: N/A
104 ! TYPE: ODPS_type
105 ! DIMENSION: Scalar
106 ! ATTRIBUTES: INTENT(IN)
107 !
108 ! GeoInfo : CRTM_GeometryInfo structure containing the
109 ! view geometry information.
110 ! UNITS: N/A
111 ! TYPE: CRTM_GeometryInfo_type
112 ! DIMENSION: Scalar
113 ! ATTRIBUTES: INTENT(IN)
114 !
115 ! OUTPUT ARGUMENTS:
116 !
117 ! Temperature : Temperatures on internal pressure grids
118 ! UNITS: K
119 ! TYPE: REAL(fp)
120 ! DIMENSION: Rank 1 array
121 ! ATTRIBUTES: INTENT(IN)
122 !
123 ! Absorber : Layer absorber amount on internal pressure grids
124 ! UNITS: depend on absorber types
125 ! TYPE: REAL(fp)
126 ! DIMENSION: Rank 2 array (n_layers x n_abosrbers)
127 ! ATTRIBUTES: INTENT(IN)
128 !
129 ! User_Level_LnPressure: User level pressure coordinate in Log scale
130 ! UNITS: N/A (Pressure in hPa)
131 ! TYPE: REAL(fp)
132 ! DIMENSION: Rank 1 array (0:n_userLayers)
133 ! ATTRIBUTES: INTENT(IN)
134 !
135 ! Ref_Level_LnPressure: internal level pressure coordinate in Log scale
136 ! UNITS: N/A (Pressure in hPa)
137 ! TYPE: REAL(fp)
138 ! DIMENSION: Rank 1 array (0:n_refLayers)
139 ! ATTRIBUTES: INTENT(IN)
140 ! Secant_Zenith : Secant zenith angle array on internal pressure grids
141 ! UNITS: N/A
142 ! TYPE: REAL(fp)
143 ! DIMENSION: Rank 1 array (n_refLayers)
144 ! ATTRIBUTES: INTENT(IN)
145 !
146 ! IN/OUTPUT ARGUMENTS:
147 ! PAFV: Structure containing FW variables for TL and AD uses
148 ! UNITS: N/A
149 ! TYPE: PAFV_type
150 ! DIMENSION: Scalar
151 ! ATTRIBUTES: INTENT(IN OUT)
152 !------------------------------------------------------------------------------
153  SUBROUTINE map_input(Atm, & ! Input
154  TC, & ! Input
155  GeoInfo, & ! Input
156  Temperature, & ! Output
157  Absorber, & ! Output
158  User_Level_LnPressure, & ! Output
159  Ref_Level_LnPressure, & ! Output
160  Secant_Zenith, & ! Output
161  H2O_idx, & ! Output
162  PAFV) ! In/Output
163  TYPE(crtm_atmosphere_type) , INTENT(IN) :: atm
164  TYPE(odps_type) , INTENT(IN) :: tc
165  TYPE(crtm_geometryinfo_type) , INTENT(IN) :: geoinfo
166  REAL(fp) , INTENT(OUT) :: temperature(:)
167  REAL(fp) , INTENT(OUT) :: absorber(:,:)
168  REAL(fp) , INTENT(OUT) :: user_level_lnpressure(0:)
169  REAL(fp) , INTENT(OUT) :: ref_level_lnpressure(0:)
170  REAL(fp) , INTENT(OUT) :: secant_zenith(:)
171  INTEGER , INTENT(OUT) :: h2o_idx
172  TYPE(pafv_type) , INTENT(INOUT) :: pafv
173 
174  ! Local variables
175  REAL(fp) :: tolerance
176  REAL(fp) :: sineang
177  REAL(fp) :: odps_sfc_fraction, z_offset, s
178  REAL(fp) :: z(0:tc%n_layers) ! Heights of pressure levels
179  REAL(fp) :: acc_weighting(atm%n_layers, tc%n_layers)
180  INTEGER :: interp_index(2, tc%n_layers)
181  REAL(fp) :: ref_lnpressure(tc%n_layers)
182  REAL(fp) :: user_lnpressure(atm%n_layers)
183  REAL(fp) :: surface_altitude, sensor_zenith_radian
184  ! absorber index mapping from ODPS to user
185  INTEGER :: idx_map(tc%n_absorbers)
186  INTEGER :: j, jj, k, n_odps_layers, n_user_layers, odps_sfc_idx
187 
188  ! Define numerical precision tolerance.
189  tolerance = epsilon(one)
190 
191  n_odps_layers = tc%n_Layers
192  n_user_layers = atm%n_layers
193  ! Set pressure profiles for interpolations
194  ref_lnpressure = log(tc%Ref_Pressure)
195  user_lnpressure = log(atm%Pressure(1:n_user_layers))
196  ref_level_lnpressure = log(tc%Ref_Level_Pressure)
197  IF(atm%Level_Pressure(0) <= zero)THEN
198  ! In this bad case, the top pressure level is set to the half of the next-to-top pressure level
199  user_level_lnpressure(0) = log(atm%Level_Pressure(1)/two)
200  ELSE
201  user_level_lnpressure(0) = log(atm%Level_Pressure(0))
202  END IF
203  user_level_lnpressure(1:n_user_layers) = log(atm%Level_Pressure(1:n_user_layers))
204 
205  ! Find the index at which the ODPS layer contains the user surface pressure level. Then
206  ! compute the fraction of the portion between the lower boundary of the ODPS layer and
207  ! the user surface pressure level
208  odps_sfc_idx = n_odps_layers
209  odps_sfc_fraction = zero
210  IF(tc%Ref_Level_Pressure(n_odps_layers) > atm%Level_Pressure(n_user_layers))THEN
211  DO k = n_odps_layers, 0, -1
212  IF(tc%Ref_Level_Pressure(k) < atm%Level_Pressure(n_user_layers))THEN
213  odps_sfc_idx = k+1
214  odps_sfc_fraction = (ref_level_lnpressure(odps_sfc_idx) - &
215  user_level_lnpressure(n_user_layers)) /&
216  (ref_level_lnpressure(odps_sfc_idx) - &
217  ref_level_lnpressure(k))
218  EXIT
219  END IF
220  END DO
221  END IF
222 
223  ! Extract the needed GeometryInfo information
224  CALL crtm_geometryinfo_getvalue( geoinfo, &
225  surface_altitude = surface_altitude, &
226  trans_zenith_radian = sensor_zenith_radian )
227 
228 
229  !-----------------------------------------------------------
230  ! Interpolate temperautre profile on internal pressure grids
231  !-----------------------------------------------------------
232  CALL layeravg( ref_lnpressure , &
233  user_lnpressure , &
234  acc_weighting , &
235  interp_index)
236 
237  DO k = 1, n_odps_layers
238  temperature(k) = sum(acc_weighting(interp_index(1,k):interp_index(2,k), k) &
239  * atm%Temperature(interp_index(1,k):interp_index(2,k)) )
240  END DO
241 
242  !-----------------------------------------------------------
243  ! Interpolate absorber profiles on internal pressure grids
244  !-----------------------------------------------------------
245  DO j = 1,tc%n_Absorbers
246  idx_map(j) = -1
247  DO jj=1, atm%n_Absorbers
248  IF( atm%Absorber_ID(jj) == tc%Absorber_ID(j) ) THEN
249  idx_map(j) = jj
250  EXIT
251  END IF
252  END DO
253 
254  ! save index for water vapor absorption
255  h2o_idx = 1 ! default
256  IF(tc%Absorber_ID(j) == h2o_id)THEN
257  h2o_idx = j
258  END IF
259  IF(idx_map(j) > 0)THEN
260 
261  DO k = 1, n_odps_layers
262  absorber(k,j) = sum(acc_weighting(interp_index(1,k):interp_index(2,k), k) &
263  * atm%Absorber(interp_index(1,k):interp_index(2,k), idx_map(j)) )
264  END DO
265 
266  DO k=1, n_odps_layers
267 
268  IF (absorber(k,j) <= tolerance ) absorber(k,j) = tolerance
269  IF (absorber(k,j) < tc%Min_Absorber(k,j) ) absorber(k,j) = tc%Min_Absorber(k,j)
270  IF (absorber(k,j) > tc%Max_Absorber(k,j) ) absorber(k,j) = tc%Max_Absorber(k,j)
271 
272  END DO
273  ELSE ! when the profile is missing, use the referece profile
274  absorber(:, j) = tc%Ref_Absorber(:, j)
275  END IF
276 
277  END DO
278 
279  !-----------------------------------------------
280  ! Compute height dependent secant zenith angles
281  !-----------------------------------------------
282  ! Compute geopotential height, which starts from ODPS surface pressure level
283  CALL geopotential_height( tc%Ref_Level_Pressure, &
284  tc%Ref_Temperature, &
285  tc%Ref_Absorber(:, h2o_idx), &
286  zero, &
287  z)
288  ! Adjust ODPS surface height for the user surface height. The adjustment includes two parts:
289  ! (1) the delta Z from the ODPS surface pressure to the user surface pressure
290  ! (2) the user-given surface height
291  IF(tc%Ref_Level_Pressure(n_odps_layers) >= atm%Level_Pressure(n_user_layers))THEN
292  z_offset = -(z(odps_sfc_idx) + odps_sfc_fraction*(z(odps_sfc_idx-1)-z(odps_sfc_idx))) &
293  + surface_altitude
294  ELSE
295  ! For the case in which the user surface pressure is larger than the ODPS surface pressure,
296  ! the ODPS surface is adjusted for a surface pressure 1013 mb, regardless the user supplied
297  ! surface height.
298  z_offset = cc*tc%Ref_Temperature(n_odps_layers) & ! scale height
299  *log(1013.0_fp / tc%Ref_Level_Pressure(n_odps_layers))
300  END IF
301  z = z + z_offset
302 
303  s = (earth_radius + surface_altitude)*sin(sensor_zenith_radian)
304 
305  DO k = 1, n_odps_layers
306  sineang = s /(earth_radius + z(k))
307  secant_zenith(k) = one / sqrt(one - sineang*sineang)
308  END DO
309 
310  IF ( pafv_associated(pafv) ) THEN
311  pafv%Temperature = temperature
312  pafv%Absorber = absorber
313  pafv%interp_index = interp_index
314  pafv%Acc_Weighting= acc_weighting
315  pafv%idx_map = idx_map
316  pafv%H2O_idx = h2o_idx
317  pafv%Ref_LnPressure = ref_lnpressure
318  pafv%User_LnPressure = user_lnpressure
319  END IF
320 
321  END SUBROUTINE map_input
322 
323 !------------------------------------------------------------------------------
324 !
325 ! NAME:
326 ! Map_Input_TL
327 !
328 ! PURPOSE:
329 ! TL Subroutine for data mapping from user pressure space to
330 ! internal pressure space for the ODPS algorithm.
331 !
332 ! CALLING SEQUENCE:
333 ! CALL Map_Input_TL( TC, & ! Input
334 ! Atm_TL, & ! Input
335 ! Temperature_TL, & ! Output
336 ! Absorber_TL, & ! Output
337 ! PAFV ) ! In/Output
338 !
339 ! INPUT ARGUMENTS:
340 ! TC: ODPS structure holding tau coefficients
341 ! UNITS: N/A
342 ! TYPE: ODPS_type
343 ! DIMENSION: Scalar
344 ! ATTRIBUTES: INTENT(IN)
345 !
346 ! Atm_TL : TL CRTM Atmosphere structure containing the atmospheric
347 ! state data.
348 ! UNITS: N/A
349 ! TYPE: CRTM_Atmosphere_type
350 ! DIMENSION: Scalar
351 ! ATTRIBUTES: INTENT(IN)
352 !
353 ! PAFV: Structure containing FW variables for TL and AD uses
354 ! UNITS: N/A
355 ! TYPE: PAFV_type
356 ! DIMENSION: Scalar
357 ! ATTRIBUTES: INTENT(IN)
358 ! OUTPUT ARGUMENTS:
359 !
360 ! Temperature_TL : TL Temperatures on internal pressure grids
361 ! UNITS: K
362 ! TYPE: REAL(fp)
363 ! DIMENSION: Rank 1 array
364 ! ATTRIBUTES: INTENT(OUT)
365 !
366 ! Absorber_TL : TL Layer absorber amount on internal pressure grids
367 ! UNITS: depend on absorber types
368 ! TYPE: REAL(fp)
369 ! DIMENSION: Rank 2 array (n_layers x n_abosrbers)
370 ! ATTRIBUTES: INTENT(OUT)
371 !
372 !
373 !------------------------------------------------------------------------------
374  SUBROUTINE map_input_tl(TC, & ! Input
375  Atm_TL, & ! Input
376  Temperature_TL, & ! Output
377  Absorber_TL, & ! Output
378  PAFV) ! Input
379  TYPE(odps_type) , INTENT(IN) :: tc
380  TYPE(crtm_atmosphere_type) , INTENT(IN) :: atm_tl
381  REAL(fp) , INTENT(OUT) :: temperature_tl(:)
382  REAL(fp) , INTENT(OUT) :: absorber_tl(:,:)
383  TYPE(pafv_type) , INTENT(IN) :: pafv
384 
385  ! Local variables
386  REAL(fp) :: tolerance
387  ! absorber index mapping from ODPS to user
388  INTEGER :: idx_map(tc%n_absorbers), h2o_idx
389  INTEGER :: j, k, n_odps_layers
390 
391  ! Define numerical precision tolerance.
392  tolerance = epsilon(one)
393 
394  n_odps_layers = tc%n_Layers
395 
396  !-----------------------------------------------------------
397  ! Interpolate temperautre profile on internal pressure grids
398  !-----------------------------------------------------------
399  DO k = 1, n_odps_layers
400  temperature_tl(k) = &
401  sum(pafv%Acc_Weighting(pafv%interp_index(1,k):pafv%interp_index(2,k), k) &
402  * atm_tl%Temperature(pafv%interp_index(1,k):pafv%interp_index(2,k)) )
403  END DO
404 
405  !-----------------------------------------------------------
406  ! Interpolate absorber profiles on internal pressure grids
407  !-----------------------------------------------------------
408  h2o_idx = pafv%H2O_idx
409  idx_map = pafv%Idx_map
410 
411  DO j = 1,tc%n_Absorbers
412  IF(idx_map(j) > 0)THEN
413 
414  DO k = 1, n_odps_layers
415  absorber_tl(k,j) = &
416  sum(pafv%Acc_Weighting(pafv%interp_index(1,k):pafv%interp_index(2,k), k) &
417  * atm_tl%Absorber(pafv%interp_index(1,k):pafv%interp_index(2,k), idx_map(j)) )
418  END DO
419 
420  DO k=1, n_odps_layers
421  IF(pafv%Absorber(k,j) <= tolerance ) absorber_tl(k,j) = zero
422 
423  END DO
424  ELSE ! when the profile is missing, use the referece profile
425  absorber_tl(:, j) = zero
426  END IF
427 
428  END DO
429 
430  END SUBROUTINE map_input_tl
431 
432 !------------------------------------------------------------------------------
433 !
434 ! NAME:
435 ! Map_Input_AD
436 !
437 ! PURPOSE:
438 ! AD Subroutine for data mapping from user pressure space to
439 ! internal pressure space for the ODPS algorithm.
440 !
441 ! CALLING SEQUENCE:
442 ! CALL Map_Input_AD( TC, & ! Input
443 ! Temperature_AD, & ! Input
444 ! Absorber_AD, & ! Input
445 ! Atm_AD, & ! In/Output
446 ! PAFV ) ! Input
447 !
448 ! INPUT ARGUMENTS:
449 ! TC: ODPS structure holding tau coefficients
450 ! UNITS: N/A
451 ! TYPE: ODPS_type
452 ! DIMENSION: Scalar
453 ! ATTRIBUTES: INTENT(IN)
454 !
455 ! Temperature_AD : AD Temperatures on internal pressure grids
456 ! UNITS: K
457 ! TYPE: REAL(fp)
458 ! DIMENSION: Rank 1 array
459 ! ATTRIBUTES: INTENT(IN)
460 !
461 ! Absorber_AD : AD Layer absorber amount on internal pressure grids
462 ! UNITS: depend on absorber types
463 ! TYPE: REAL(fp)
464 ! DIMENSION: Rank 2 array (n_layers x n_abosrbers)
465 ! ATTRIBUTES: INTENT(IN)
466 !
467 ! PAFV: Structure containing FW variables for TL and AD uses
468 ! UNITS: N/A
469 ! TYPE: PAFV_type
470 ! DIMENSION: Scalar
471 ! ATTRIBUTES: INTENT(IN)
472 ! OUTPUT ARGUMENTS:
473 !
474 ! Atm_AD : AD CRTM Atmosphere structure containing the atmospheric
475 ! state data.
476 ! UNITS: N/A
477 ! TYPE: CRTM_Atmosphere_type
478 ! DIMENSION: Scalar
479 ! ATTRIBUTES: INTENT(INOUT)
480 !
481 !------------------------------------------------------------------------------
482  SUBROUTINE map_input_ad(TC, & ! Input
483  Temperature_AD, & ! Input
484  Absorber_AD, & ! Input
485  Atm_AD, & ! Output
486  PAFV) ! Input
488  TYPE(odps_type) , INTENT(IN) :: tc
489  REAL(fp) , INTENT(INOUT) :: temperature_ad(:)
490  REAL(fp) , INTENT(INOUT) :: absorber_ad(:,:)
491  TYPE(crtm_atmosphere_type) , INTENT(INOUT) :: atm_ad
492  TYPE(pafv_type) , INTENT(IN) :: pafv
493 
494  ! Local variables
495  REAL(fp) :: tolerance
496  ! absorber index mapping from ODPS to user
497  INTEGER :: idx_map(tc%n_absorbers), h2o_idx
498  INTEGER :: j, k, n_odps_layers
499 
500  ! Define numerical precision tolerance.
501  tolerance = epsilon(one)
502 
503  !-----------------------------------------------------------
504  ! Initialization of forward model part
505  !-----------------------------------------------------------
506 
507  n_odps_layers = tc%n_Layers
508 
509  h2o_idx = pafv%H2O_idx
510  idx_map = pafv%Idx_map
511 
512  !-----------------------------------------------------------
513  ! Interpolate absorber profiles on internal pressure grids
514  !-----------------------------------------------------------
515  DO j = tc%n_Absorbers, 1, -1
516  IF(idx_map(j) > 0)THEN
517 
518  DO k=1, n_odps_layers
519  IF(pafv%Absorber(k,j) <= tolerance ) absorber_ad(k,j) = zero
520  END DO
521 
522  DO k = n_odps_layers, 1, -1
523  atm_ad%Absorber(pafv%interp_index(1,k):pafv%interp_index(2,k), idx_map(j)) = &
524  atm_ad%Absorber(pafv%interp_index(1,k):pafv%interp_index(2,k), idx_map(j)) &
525  + pafv%Acc_Weighting(pafv%interp_index(1,k):pafv%interp_index(2,k), k) &
526  * absorber_ad(k,j)
527  END DO
528 
529  ELSE ! when the profile is missing, use the referece profile
530  absorber_ad(:, j) = zero
531  END IF
532  END DO
533 
534  !-----------------------------------------------------------
535  ! Interpolate temperautre profile on internal pressure grids
536  !-----------------------------------------------------------
537 
538  DO k = n_odps_layers, 1, -1
539  atm_ad%Temperature(pafv%interp_index(1,k):pafv%interp_index(2,k)) = &
540  atm_ad%Temperature(pafv%interp_index(1,k):pafv%interp_index(2,k)) &
541  + pafv%Acc_Weighting(pafv%interp_index(1,k):pafv%interp_index(2,k), k) &
542  * temperature_ad(k)
543 
544  END DO
545 
546  temperature_ad = zero
547  absorber_ad = zero
548 
549  END SUBROUTINE map_input_ad
550 
551 !--------------------------------------------------------------------------------
552 !S+
553 ! NAME:
554 ! Geopotential_Height
555 !
556 ! PURPOSE:
557 ! Routine to calculate geopotential height using the hypsometric
558 ! equation.
559 !
560 ! CALLING SEQUENCE:
561 ! CALL Geopotential_Height( Level_Pressure, & ! Input
562 ! Temperature, & ! Input
563 ! Water_Vapor, & ! Input
564 ! Surface_Height, & ! input
565 ! Level_Height)
566 !
567 ! INPUT ARGUMENTS:
568 ! Level_Pressure: Level Pressures, which are the boundaries of of the
569 ! atmospheric layers for the Temperature and Water_vapor arrays
570 ! UNITS: hectoPascals, hPa
571 ! TYPE: REAL(fp)
572 ! DIMENSION: Rank-1 (0:n_layers)
573 ! ATTRIBUTES: INTENT(IN)
574 !
575 ! Temperature: Layer Temperature.
576 ! UNITS: Kelvin, K
577 ! TYPE: REAL(fp)
578 ! DIMENSION: Rank-1 (n_layers)
579 ! ATTRIBUTES: INTENT(IN)
580 !
581 ! Surface_Height: Height of Level_Pressure(n_layer)
582 ! input arrays.
583 ! UNITS: km.
584 ! TYPE: REAL(fp)
585 ! DIMENSION: Scalar
586 ! ATTRIBUTES: INTENT(IN)
587 !
588 !
589 ! Water_Vapor: Layer water vapor mixing radio
590 ! UNITS: g/kg
591 ! TYPE: REAL(fp)
592 ! DIMENSION: Same as Temperature
593 ! ATTRIBUTES: INTENT(IN)
594 !
595 ! OUTPUT ARGUMENTS:
596 ! Level_Height: Geopotential Heights of the input Pressure levels.
597 ! UNITS: metres, m
598 ! TYPE: REAL(fp)
599 ! DIMENSION: Same as input Pressure
600 ! ATTRIBUTES: INTENT(OUT)
601 !
602 !
603 !
604 ! CREATION HISTORY:
605 ! Written by: Yong Han, NOAA/NESDIS 5-Feb-2008
606 !S-
607 !--------------------------------------------------------------------------------
608 
609  SUBROUTINE geopotential_height( Level_Pressure, & ! Input
610  Temperature, & ! Input
611  Water_Vapor, & ! Input
612  Surface_Height, & ! input
613  Level_Height) ! Output
615  ! Arguments
616  REAL(fp), INTENT(IN) :: Level_Pressure(0:)
617  REAL(fp), INTENT(IN) :: Temperature(:)
618  REAL(fp), INTENT(IN) :: Water_Vapor(:)
619  REAL(fp), INTENT(IN) :: Surface_Height
620  REAL(fp), INTENT(OUT) :: Level_Height(0:)
621 
622  ! Function result
623  REAL(fp) :: Tv, H
624  INTEGER :: k, n_Layers
625 
626  n_layers = SIZE(temperature)
627  level_height(n_layers) = surface_height
628  DO k = n_layers, 1, -1
629  ! virtual temperature computed using an approximation of the exact formula:
630  ! Tv = T*(1+w/epsilon)/(1+w), where w is the water vapor mixing ratio
631  tv = temperature(k)*(one + c*water_vapor(k))
632  h = cc*tv
633  level_height(k-1) = level_height(k) + h*log(level_pressure(k)/level_pressure(k-1))
634  END DO
635 
636  END SUBROUTINE geopotential_height
637 
638 
639 !---------------------------------------------------------------------------------------------
640 ! NAME: Interpolate_Profile
641 !
642 ! PURPOSE:
643 ! Given x and u that are ascending arrays, it interpolates y with the abscissa x
644 ! on the abscissa u using the following algorithm:
645 ! y_int(i) = y(1) if u(i) < x(1)
646 ! y_int(i) = y(nx) if u(i) > x(nx)
647 ! y_int(i) = y(ix1) + (y(ix2)-y(ix1))*(u(i) - x(ix1))/(x(ix2)-x(ix1))
648 ! if x(ix1) <= u(i) <= x(ix2)
649 !
650 ! IThe index array interp_index contains the following content
651 !
652 ! interp_index(1, i) = 1 and interp_index(2, i) = 1, if u(i) < x(1)
653 ! interp_index(1, i) = nx and interp_index(2, i) = nx, if u(i) > x(nx),
654 ! where nx = SIZE(x)
655 ! x(interp_index(1, i)) <= u(i) <= x(interp_index(2, i)) if x(1) <= u(i) <= x(nx)
656 !
657 ! CALLING SEQUENCE:
658 ! CALL Interpolate_Profile(interp_index, y, x, u, y_int)
659 !
660 ! INPUT ARGUMENTS:
661 ! y: The data array to be interpolated.
662 ! UNITS: N/A
663 ! TYPE: fp
664 ! DIMENSION: rank-1
665 ! ATTRIBUTES: INTENT(IN)
666 !
667 ! x: The abscissa values for y and they must be monotonically
668 ! ascending.
669 ! UNITS: N/A
670 ! TYPE: fp
671 ! DIMENSION: rank-1
672 ! ATTRIBUTES: INTENT(IN)
673 !
674 ! u: The abscissa values for the results
675 ! and they must be monotonically ascending
676 ! UNITS: N/A
677 ! TYPE: fp
678 ! DIMENSION: rank-1
679 ! ATTRIBUTES: INTENT(IN)
680 !
681 ! interp_index: The index array of dimension (nu x 2), where nu = SIZE(u)
682 ! UNITS: N/A
683 ! TYPE: Integer
684 ! DIMENSION: rank-2
685 ! ATTRIBUTES: INTENT(IN)
686 !
687 ! OUTPUT ARGUMENTS:
688 ! y_int: The array contains the results
689 ! UNITS: N/A
690 ! TYPE: Integer
691 ! DIMENSION: rank-1
692 ! ATTRIBUTES: INTENT(OUT)
693 !
694 ! RESTRICTIONS:
695 ! To be efficient, this routine does not check that x and u are both
696 ! monotonically ascending and the index bounds.
697 !
698 ! CREATION HISTORY:
699 ! Written by: Yong Han, 10-Dec-2008
700 !-----------------------------------------------------------------------------------
701 
702  !----------------------------------------------------------------------------
703  ! Interpolation routine with interperlation index array already calculated.
704  !----------------------------------------------------------------------------
705  SUBROUTINE interpolate_profile(interp_index, y, x, u, y_int)
706  ! Arguments
707  INTEGER, DIMENSION(:,:), INTENT(IN) :: interp_index
708  REAL(fp), DIMENSION(:), INTENT(IN) :: y
709  REAL(fp), DIMENSION(:), INTENT(IN) :: x
710  REAL(fp), DIMENSION(:), INTENT(IN) :: u
711  REAL(fp), DIMENSION(:), INTENT(OUT) :: y_int
712  ! Local variables
713  INTEGER :: i, n, k1, k2
714 
715  n = SIZE(interp_index, dim=2)
716  DO i = 1, n
717  k1 = interp_index(1, i)
718  k2 = interp_index(2, i)
719  IF( k1 == k2)THEN
720  y_int(i) = y(k1)
721  ELSE
722  CALL interp_linear(y(k1), x(k1), y(k2), x(k2), u(i), y_int(i))
723  END IF
724  END DO
725 
726  END SUBROUTINE interpolate_profile
727 
728 
729 !---------------------------------------------------------------------------------------------
730 ! NAME: Interpolate_Profile_TL
731 !
732 ! PURPOSE:
733 ! The Tangent_Linear routine of Interpolate_Profile
734 ! CALLING SEQUENCE:
735 ! CALL Interpolate_Profile_F1_TL(interp_index, y, x, u, y_TL, y_int_TL)
736 ! OR CALL Interpolate_Profile_F2_TL(interp_index, y, x, u, y_TL, u_TL, y_int_TL)
737 ! OR CALL Interpolate_Profile_F3_TL(interp_index, y, x, u, y_TL, x_TL, y_int_TL)
738 !
739 ! INPUT ARGUMENTS:
740 ! y: The data array to be interpolated.
741 ! UNITS: N/A
742 ! TYPE: fp
743 ! DIMENSION: rank-1
744 ! ATTRIBUTES: INTENT(IN)
745 !
746 ! x: The abscissa values for y and they must be monotonically
747 ! ascending.
748 ! UNITS: N/A
749 ! TYPE: fp
750 ! DIMENSION: rank-1
751 ! ATTRIBUTES: INTENT(IN)
752 !
753 ! u: The abscissa values for the results
754 ! and they must be monotonically ascending
755 ! UNITS: N/A
756 ! TYPE: fp
757 ! DIMENSION: rank-1
758 ! ATTRIBUTES: INTENT(IN)
759 !
760 ! y_TL: The Tangent-linear data array of y
761 ! UNITS: N/A
762 ! TYPE: fp
763 ! DIMENSION: rank-1
764 ! ATTRIBUTES: INTENT(IN)
765 !
766 ! u_TL: The Tangent-linear data array of u
767 ! UNITS: N/A
768 ! TYPE: fp
769 ! DIMENSION: rank-1
770 ! ATTRIBUTES: INTENT(IN)
771 !
772 ! x_TL: The Tangent-linear data array of x
773 ! UNITS: N/A
774 ! TYPE: fp
775 ! DIMENSION: rank-1
776 ! ATTRIBUTES: INTENT(IN)
777 !
778 ! interp_index: The index array of dimension (nu x 2), where nu = SIZE(u)
779 ! UNITS: N/A
780 ! TYPE: Integer
781 ! DIMENSION: rank-2
782 ! ATTRIBUTES: INTENT(IN)
783 !
784 ! OUTPUT ARGUMENTS:
785 ! y_int_TL: The Tangent-linear array of y_int
786 ! UNITS: N/A
787 ! TYPE: Integer
788 ! DIMENSION: rank-1
789 ! ATTRIBUTES: INTENT(OUT)
790 !
791 ! RESTRICTIONS:
792 ! To be efficient, this routine does not check that x and u are both
793 ! monotonically ascending and the index bounds.
794 !
795 ! CREATION HISTORY:
796 ! Written by: Yong Han, 10-Dec-2008
797 !-----------------------------------------------------------------------------------
798 
799  SUBROUTINE interpolate_profile_f1_tl(interp_index, x, u, y_TL, y_int_TL)
800  ! Arguments
801  INTEGER, DIMENSION(:,:), INTENT(IN) :: interp_index
802  REAL(fp), DIMENSION(:), INTENT(IN) :: x
803  REAL(fp), DIMENSION(:), INTENT(IN) :: u
804  REAL(fp), DIMENSION(:), INTENT(IN) :: y_tl
805  REAL(fp), DIMENSION(:), INTENT(OUT) :: y_int_tl
806  ! Local variables
807  INTEGER :: i, n, k1, k2
808 
809  n = SIZE(interp_index, dim=2)
810  DO i = 1, n
811  k1 = interp_index(1, i)
812  k2 = interp_index(2, i)
813  IF( k1 == k2)THEN
814  y_int_tl(i) = y_tl(k1)
815  ELSE
816  CALL interp_linear_f1_tl(x(k1), x(k2), u(i), y_tl(k1), y_tl(k2), y_int_tl(i))
817  END IF
818  END DO
819 
820  END SUBROUTINE interpolate_profile_f1_tl
821 
822 
823 !---------------------------------------------------------------------------------------------
824 ! NAME: Interpolate_Profile_AD
825 !
826 ! PURPOSE:
827 ! The Adjoint routine of Interpolate_Profile
828 !
829 ! CALLING SEQUENCE:
830 ! CALL Interpolate_Profile_F1_AD(interp_index, y, x, u, y_int_AD, y_AD)
831 ! OR CALL Interpolate_Profile_F2_AD(interp_index, y, x, u, y_int_AD, y_AD, u_AD)
832 ! OR CALL Interpolate_Profile_F3_AD(interp_index, y, x, u, y_int_AD, y_AD, x_AD)
833 !
834 ! INPUT ARGUMENTS:
835 ! y: The data array to be interpolated.
836 ! UNITS: N/A
837 ! TYPE: fp
838 ! DIMENSION: rank-1
839 ! ATTRIBUTES: INTENT(IN)
840 !
841 ! x: The abscissa values for y and they must be monotonically
842 ! ascending.
843 ! UNITS: N/A
844 ! TYPE: fp
845 ! DIMENSION: rank-1
846 ! ATTRIBUTES: INTENT(IN)
847 !
848 ! u: The abscissa values for the results
849 ! and they must be monotonically ascending
850 ! UNITS: N/A
851 ! TYPE: fp
852 ! DIMENSION: rank-1
853 ! ATTRIBUTES: INTENT(IN)
854 !
855 ! y_int_AD: The Adjoint array of y_int
856 ! UNITS: N/A
857 ! TYPE: Integer
858 ! DIMENSION: rank-1
859 ! ATTRIBUTES: INTENT(IN)
860 !
861 ! interp_index: The index array of dimension (nu x 2), where nu = SIZE(u)
862 ! UNITS: N/A
863 ! TYPE: Integer
864 ! DIMENSION: rank-2
865 ! ATTRIBUTES: INTENT(IN)
866 !
867 ! OUTPUT ARGUMENTS:
868 ! y_AD: The Adjoint data array of y
869 ! UNITS: N/A
870 ! TYPE: fp
871 ! DIMENSION: rank-1
872 ! ATTRIBUTES: INTENT(IN)
873 !
874 ! u_AD: The Adjoint data array of u
875 ! UNITS: N/A
876 ! TYPE: fp
877 ! DIMENSION: rank-1
878 ! ATTRIBUTES: INTENT(IN)
879 !
880 ! x_AD: The Adjoint data array of x
881 ! UNITS: N/A
882 ! TYPE: fp
883 ! DIMENSION: rank-1
884 ! ATTRIBUTES: INTENT(IN)
885 !
886 ! RESTRICTIONS:
887 ! To be efficient, this routine does not check that x and u are both
888 ! monotonically ascending and the index bounds.
889 !
890 ! CREATION HISTORY:
891 ! Written by: Yong Han, 10-Dec-2008
892 !-----------------------------------------------------------------------------------
893 
894  SUBROUTINE interpolate_profile_f1_ad(interp_index, x, u, y_int_AD, y_AD)
895  ! Arguments
896  INTEGER, DIMENSION(:,:), INTENT(IN) :: interp_index
897  REAL(fp), DIMENSION(:), INTENT(IN) :: x
898  REAL(fp), DIMENSION(:), INTENT(IN) :: u
899  REAL(fp), DIMENSION(:), INTENT(IN OUT) :: y_int_ad
900  REAL(fp), DIMENSION(:), INTENT(IN OUT) :: y_ad
901  ! Local variables
902  INTEGER :: i, n, k1, k2
903 
904  n = SIZE(interp_index, dim=2)
905  DO i = n, 1, -1
906  k1 = interp_index(1, i)
907  k2 = interp_index(2, i)
908  IF( k1 == k2)THEN
909  y_ad(k1) = y_ad(k1) + y_int_ad(i)
910  y_int_ad(i) = zero
911  ELSE
912  CALL interp_linear_f1_ad(x(k1), x(k2), u(i), y_int_ad(i), y_ad(k1), y_ad(k2))
913  END IF
914  END DO
915 
916  END SUBROUTINE interpolate_profile_f1_ad
917 
918 
919 !---------------------------------------------------------------------------------------------
920 ! NAME: Compute_Interp_Index
921 !
922 ! PURPOSE:
923 ! Given x and u that are ascending arrays, it computes an index array, interp_index,
924 ! such that
925 !
926 ! interp_index(i, 1) = 1 and interp_index(i, 2) = 1, if u(i) < x(1)
927 ! interp_index(i, 1) = nx and interp_index(i, 2) = nx, if u(i) > x(nx),
928 ! where nx = SIZE(x)
929 ! x(interp_index(i, 1)) <= u(i) <= x(interp_index(i, 2)) if x(1) <= u(i) <= x(nx)
930 !
931 ! CALLING SEQUENCE:
932 ! CALL Compute_Interp_Index(x, u, interp_index)
933 !
934 ! INPUT ARGUMENTS:
935 ! x: The abscissa values for the data to be interpolated and
936 ! they must be monotonically ascending.
937 ! UNITS: N/A
938 ! TYPE: fp
939 ! DIMENSION: rank-1
940 ! ATTRIBUTES: INTENT(IN)
941 !
942 ! u: The abscissa values on which the data are interpolated
943 ! they must be monotonically ascending
944 ! the elements of array x.
945 ! UNITS: N/A
946 ! TYPE: fp
947 ! DIMENSION: rank-1
948 ! ATTRIBUTES: INTENT(IN)
949 !
950 ! OUTPUT ARGUMENTS:
951 ! interp_index: The index array of dimension (nu x 2), where nu = SIZE(u)
952 ! UNITS: N/A
953 ! TYPE: Integer
954 ! DIMENSION: rank-2
955 ! ATTRIBUTES: INTENT(OUT)
956 !
957 ! RESTRICTIONS:
958 ! To be efficient, this routine does not check that x and u are both
959 ! monotonically ascending and the index bounds.
960 !
961 ! CREATION HISTORY:
962 ! Written by: Yong Han, 07-May-2004
963 !-----------------------------------------------------------------------------------
964 
965  SUBROUTINE compute_interp_index(x, u, interp_index)
966  ! Arguments
967  REAL(fp), DIMENSION(:), INTENT(IN) :: x
968  REAL(fp), DIMENSION(:), INTENT(IN) :: u
969  INTEGER, DIMENSION(:,:), INTENT(OUT) :: interp_index
970  ! Local variables
971  INTEGER :: nx, nu, ix, iu, j, k1, k2
972 
973  nx = SIZE(x)
974  nu = SIZE(u)
975 
976  ! Set the indexes to 1 for the elements in u that are smaller than x(1)
977  k1 = nu + 1
978  lessthan_loop: DO iu = 1, nu
979  IF(u(iu) < x(1))THEN
980  interp_index(1, iu) = 1
981  interp_index(2, iu) = 1
982  ELSE
983  k1 = iu
984  EXIT lessthan_loop
985  END IF
986  END DO lessthan_loop
987 
988  ! Set the indexes to nx for the elements in u that are larger than x(nx)
989  k2 = 0
990  greaterthan_loop: DO iu = nu, k1, -1
991  IF(u(iu) > x(nx))THEN
992  interp_index(1, iu) = nx
993  interp_index(2, iu) = nx
994  ELSE
995  k2 = iu
996  EXIT greaterthan_loop
997  END IF
998  END DO greaterthan_loop
999 
1000  ! Set the indexes for the elements in u that are in the range
1001  ! between x1(1) and x(nx)
1002  j = 1
1003  outer_loop: DO iu = k1, k2
1004  inner_loop: DO ix = j, nx-1
1005  IF(u(iu) >= x(ix) .AND. u(iu) <= x(ix+1))THEN
1006  interp_index(1, iu) = ix
1007  interp_index(2, iu) = ix+1
1008  j = ix
1009  EXIT inner_loop
1010  ENDIF
1011  END DO inner_loop
1012  END DO outer_loop
1013 
1014  END SUBROUTINE compute_interp_index
1015 
1016 
1017  !---------------------------------------------
1018  ! Function for two points linear interpolation
1019  !---------------------------------------------
1020  SUBROUTINE interp_linear(y1, x1, y2, x2, x, y)
1021  REAL(fp), INTENT(IN) :: y1, x1, y2, x2, x
1022  REAL(fp), INTENT(OUT) :: y
1023  y = y1 + (y2-y1)*(x - x1)/(x2 - x1)
1024  END SUBROUTINE interp_linear
1025 
1026 
1027  SUBROUTINE interp_linear_f1_tl(x1, x2, x, y1_TL, y2_TL, y_TL)
1028  REAL(fp), INTENT(IN) :: x1, x2, x, y1_TL, y2_TL
1029  REAL(fp), INTENT(OUT) :: y_TL
1030  y_tl = y1_tl + (y2_tl-y1_tl)*(x - x1)/(x2 - x1)
1031  END SUBROUTINE interp_linear_f1_tl
1032 
1033 
1034  SUBROUTINE interp_linear_f1_ad(x1, x2, x, y_AD, y1_AD, y2_AD)
1035  REAL(fp), INTENT(IN) :: x1, x2, x
1036  REAL(fp), INTENT(IN OUT) :: y_AD
1037  REAL(fp), INTENT(IN OUT) :: y1_AD, y2_AD
1038  ! Local variables
1039  REAL(fp) :: fac
1040  fac = (x - x1)/(x2 - x1)
1041  y1_ad = y1_ad + (one - fac)*y_ad
1042  y2_ad = y2_ad + fac*y_ad
1043  y_ad = zero
1044  END SUBROUTINE interp_linear_f1_ad
1045 
1046 
1047 !--------------------------------------------------------------------------------
1048 !
1049 ! NAME:
1050 ! LayerAvg
1051 !
1052 ! PURPOSE:
1053 ! Given px1 (output domain) and px2 (input domain) that are ascending arrays,
1054 ! it computes the accumulated weighting factors for interpolation from input
1055 ! to output domainsan, and the index array, interp_index, such that output
1056 ! variable
1057 ! to(jo) = sum(pz(interp_index(1,jo):interp_index(2,jo),jo) &
1058 ! *(ti(interp_index(1,jo):interp_index(2,jo))))
1059 
1060 !
1061 ! CALLING SEQUENCE:
1062 ! CALL LayerAvg(PX1,PX2,PZ,Interp_index)
1063 !
1064 ! INPUT ARGUMENTS:
1065 ! PX1: The abscissa values for the target data (output domain) and
1066 ! they must be monotonically ascending (e.g. lnP; in increasing values).
1067 ! UNITS: N/A
1068 ! TYPE: fp
1069 ! DIMENSION: rank-1 (KN1)
1070 ! ATTRIBUTES: INTENT(IN)
1071 ! PX2: The abscissa values for the source data (input domain) and
1072 ! they must be monotonically ascending (e.g. lnP; in increasing values).
1073 ! UNITS: N/A
1074 ! TYPE: fp
1075 ! DIMENSION: rank-1 (KN2)
1076 ! ATTRIBUTES: INTENT(IN)
1077 !
1078 ! OUTPUT ARGUMENTS:
1079 ! PZ: Resultant accumulated weighting factors for
1080 ! interpolation from input to output domains.
1081 ! UNITS: N/A
1082 ! TYPE: fp
1083 ! DIMENSION: rank-2 (KN2,KN1)
1084 ! ATTRIBUTES: INTENT(OUT)
1085 ! interp_index: The index array of dimension (2 x KN1) for
1086 ! Start index for relevant PZ row array segment and
1087 ! End index for relevant PZ row array segment, where KN1 = SIZE(PX1)
1088 ! UNITS: N/A
1089 ! TYPE: Integer
1090 ! DIMENSION: rank-2
1091 ! ATTRIBUTES: INTENT(IN)
1092 !
1093 ! Comments:
1094 !
1095 ! 1) PX1(i)<PX1(i+1) & PX2(i)<PX2(i+1)
1096 !
1097 ! RESTRICTIONS:
1098 ! To be efficient, this routine does not check that x and u are both
1099 ! monotonically ascending and the index bounds.
1100 !
1101 ! - Journal reference:
1102 ! Rochon, Y.J., L. Garand, D.S. Turner, and S. Polavarapu.
1103 ! Jacobian mapping between vertical coordinate systems in data assimilation,
1104 ! Q. J. of the Royal Met. Soc., 133, 1547-1558 (2007) DOI: 10.1002/qj.117
1105 !
1106 ! CREATION HISTORY:
1107 ! Written by: Yong Chen, 08-May-2009
1108 !-----------------------------------------------------------------------------------
1109 !--------------------------------------------------------------------------------
1110  SUBROUTINE layeravg( PX1,PX2,PZ,interp_index)
1111  REAL(fp), DIMENSION(:), INTENT(IN) :: PX1(:)
1112  REAL(fp), DIMENSION(:), INTENT(IN) :: PX2(:)
1113  REAL(fp), DIMENSION(:,:), INTENT(OUT) :: PZ(:, :)
1114  INTEGER, DIMENSION(:,:), INTENT(OUT) :: interp_index
1115 
1116  ! Local variables
1117  INTEGER :: KN1,KN2, ibot,itop,ii,istart,iend, J,IC,ISKIP,KI
1118  REAL(fp) :: z1,z2,z3,zw1,zw2,zsum
1119  REAL(fp) :: y1,y2,d,w10,w20,dz,dx,dy,dzd,dxd
1120 
1121  kn1 = SIZE(px1)
1122  kn2 = SIZE(px2)
1123 
1124  istart=1
1125  iend=kn1
1126  DO ki=1,kn1
1127  z2=px1(ki)
1128 !
1129  if (ki == 1) then
1130  z1=2.0*z2-px1(ki+1)
1131  else
1132  z1=px1(ki-1)
1133  endif
1134 !
1135  if (ki == kn1) then
1136  z3=2.0*z2-z1
1137  else
1138  z3=px1(ki+1)
1139  endif
1140  if (z3 > px2(kn2)) z3=px2(kn2)
1141 !
1142  iskip=0
1143  if (z2 >= px2(kn2)) then
1144  z3=px2(kn2)
1145  z2=px2(kn2)
1146  iskip=1
1147  endif
1148 
1149 ! --- Determine forward interpolator
1150 !
1151  pz(1:kn2,ki)=zero
1152  ic=0
1153  do j=istart,kn2-1
1154  if (px2(j) > z3) go to 1000
1155 !
1156  if (px2(j) <= z2 .and. px2(j+1) > z1) then
1157  itop=0
1158  ibot=0
1159  if (z1 < z3) then
1160  y1=z1
1161  if (px2(j) > z1) then
1162  y1=px2(j)
1163  itop=1
1164  endif
1165  y2=z2
1166  if (px2(j+1) < z2) then
1167  y2=px2(j+1)
1168  ibot=1
1169  endif
1170  else
1171  y1=z2
1172  if (px2(j) > z2) then
1173  y1=px2(j)
1174  itop=1
1175  endif
1176  y2=z1
1177  if (px2(j+1) < z1) then
1178  y2=px2(j+1)
1179  ibot=1
1180  endif
1181  endif
1182 !
1183 ! --- Set weights for forward interpolator
1184 !
1185  dy=y2-y1
1186  dz=z1-z2
1187  if (abs(dz) < smalldiff) then
1188  write(6,*) 'SUBLAYER: ERROR: dz is <=0. dz = ',dz
1189  write(6,*) 'z1,z2,z3 = ',z1,z2,z3
1190  write(6,*) 'px2(j),px2(j+1) = ',px2(j),px2(j+1)
1191  return
1192  else
1193  dzd=one/dz
1194  endif
1195  zw1=(z1-y1)*dzd*dy
1196  zw2=(z1-y2)*dzd*dy
1197  w10=zw1
1198  w20=zw2
1199  dx=(px2(j+1)-px2(j))
1200  if (abs(dx) < smalldiff) then
1201  write(6,*) 'SUBLAYER: ERROR: dx is <=0. dx = ',dx
1202  write(6,*) 'z1,z2,z3 = ',z1,z2,z3
1203  write(6,*) 'px2(j),px2(j+1) = ',px2(j),px2(j+1)
1204  return
1205  else
1206  dxd=one/dx
1207  endif
1208 !
1209  d=(px2(j+1)-z2)*dxd
1210  if (z1 < z3 .and. ibot == 0) then
1211  zw1=zw1+zw2*d
1212  zw2=zw2*(one-d)
1213  else if (z1 > z3 .and. itop == 0) then
1214  zw2=zw2+zw1*(one-d)
1215  zw1=zw1*d
1216  end if
1217  pz(j,ki)=pz(j,ki)+zw1
1218  pz(j+1,ki)=pz(j+1,ki)+zw2
1219  ic=1
1220  endif
1221 !
1222  if (px2(j) < z3 .and. px2(j+1) >= z2 .and. iskip == 0) then
1223  itop=0
1224  ibot=0
1225  if (z3 < z1) then
1226  y1=z3
1227  if (px2(j) > z3) then
1228  y1=px2(j)
1229  itop=1
1230  endif
1231  y2=z2
1232  if (px2(j+1) < z2) then
1233  y2=px2(j+1)
1234  ibot=1
1235  endif
1236  else
1237  y1=z2
1238  if (px2(j) > z2) then
1239  y1=px2(j)
1240  itop=1
1241  endif
1242  y2=z3
1243  if (px2(j+1) < z3) then
1244  y2=px2(j+1)
1245  ibot=1
1246  endif
1247  endif
1248 !
1249 ! --- Set weights for forward interpolator
1250 !
1251  dy=y2-y1
1252  dz=z3-z2
1253  if (abs(dz) < smalldiff) then
1254  write(6,*) 'SUBLAYER: ERROR: dz is <=0. dz = ',dz
1255  write(6,*) 'z3,z2,z1 = ',z3,z2,z1
1256  write(6,*) 'px2(j),px2(j+1) = ',px2(j),px2(j+1)
1257  return
1258  else
1259  dzd=one/dz
1260  endif
1261  zw1=(z3-y1)*dzd*dy
1262  zw2=(z3-y2)*dzd*dy
1263  w10=zw1
1264  w20=zw2
1265  dx=(px2(j+1)-px2(j))
1266  if (abs(dx) < smalldiff) then
1267  write(6,*) 'SUBLAYER: ERROR: dx is <=0. dx = ',dx
1268  write(6,*) 'z3,z2,z1 = ',z3,z2,z1
1269  write(6,*) 'px2(j),px2(j+1) = ',px2(j),px2(j+1)
1270  return
1271  else
1272  dxd=one/dx
1273  endif
1274 !
1275  d=(px2(j+1)-z2)*dxd
1276  if (z3 < z1 .and. ibot == 0) then
1277  zw1=zw1+zw2*d
1278  zw2=zw2*(one-d)
1279  else if (z3 > z1 .and. itop == 0) then
1280  zw2=zw2+zw1*(one-d)
1281  zw1=zw1*d
1282  end if
1283  pz(j,ki)=pz(j,ki)+zw1
1284  pz(j+1,ki)=pz(j+1,ki)+zw2
1285  ic=1
1286  endif
1287  enddo
1288  j=kn2
1289  1000 continue
1290  if (ic == 0) pz(j,ki)=one
1291 !
1292 ! Normalize sum to unity (instead of calculating and dividing by
1293 ! weighting denominator)
1294 !
1295  do ii=istart,kn2
1296  if(pz(ii,ki) /= zero)then
1297  interp_index(1, ki)=ii
1298  exit
1299  endif
1300  enddo
1301  istart=interp_index(1, ki)
1302 
1303  interp_index(2,ki)=kn2
1304 
1305  do ii=interp_index(1, ki)+1,kn2
1306  if(pz(ii,ki) == zero)then
1307  interp_index(2,ki)=ii-1
1308  exit
1309  endif
1310  enddo
1311  iend=interp_index(2,ki)
1312 
1313  zsum=sum(pz(interp_index(1, ki):interp_index(2,ki),ki))
1314  pz(interp_index(1,ki):interp_index(2,ki),ki)= &
1315  pz(interp_index(1,ki):interp_index(2, ki),ki)/zsum
1316  ENDDO
1317 
1318 
1319  END SUBROUTINE layeravg
1320 
1321 END MODULE odps_coordinatemapping
subroutine geopotential_height(Level_Pressure, Temperature, Water_Vapor, Surface_Height, Level_Height)
real(fp), parameter, public zero
integer, parameter, public fp
Definition: Type_Kinds.f90:124
character(*), parameter, private module_rcs_id
real(fp), parameter, public r_dryair
integer, parameter, public h2o_id
subroutine layeravg(PX1, PX2, PZ, interp_index)
real(fp), parameter, public earth_radius
subroutine, public map_input_tl(TC, Atm_TL, Temperature_TL, Absorber_TL, PAFV)
subroutine interp_linear_f1_tl(x1, x2, x, y1_TL, y2_TL, y_TL)
real(fp), parameter, public one
subroutine, public interpolate_profile_f1_tl(interp_index, x, u, y_TL, y_int_TL)
subroutine, public map_input_ad(TC, Temperature_AD, Absorber_AD, Atm_AD, PAFV)
elemental logical function, public pafv_associated(self)
real(fp), parameter, public two
subroutine, public compute_interp_index(x, u, interp_index)
subroutine interp_linear(y1, x1, y2, x2, x, y)
subroutine, public map_input(Atm, TC, GeoInfo, Temperature, Absorber, User_Level_LnPressure, Ref_Level_LnPressure, Secant_Zenith, H2O_idx, PAFV)
real(fp), parameter, public degrees_to_radians
subroutine, public interpolate_profile(interp_index, y, x, u, y_int)
subroutine, public interpolate_profile_f1_ad(interp_index, x, u, y_int_AD, y_AD)
subroutine interp_linear_f1_ad(x1, x2, x, y_AD, y1_AD, y2_AD)
elemental subroutine, public crtm_geometryinfo_getvalue(gInfo, Geometry, iFOV, Longitude, Latitude, Surface_Altitude, Sensor_Scan_Angle, Sensor_Zenith_Angle, Sensor_Azimuth_Angle, Source_Zenith_Angle, Source_Azimuth_Angle, Flux_Zenith_Angle, Year, Month, Day, Distance_Ratio, Sensor_Scan_Radian, Sensor_Zenith_Radian, Sensor_Azimuth_Radian, Secant_Sensor_Zenith, Cosine_Sensor_Zenith, Source_Zenith_Radian, Source_Azimuth_Radian, Secant_Source_Zenith, Flux_Zenith_Radian, Secant_Flux_Zenith, Trans_Zenith_Radian, Secant_Trans_Zenith, AU_ratio2)