3 !------------------------------------------------------------------------------!
4 ! Recover observation height, when missing, based on pressure.
6 ! Y.-R. GUO, September 2000
7 !------------------------------------------------------------------------------!
18 !------------------------------------------------------------------------------
19 SUBROUTINE recover_height_from_pressure(max_number_of_obs , &
20 obs , number_of_obs, print_hp_recover)
22 ! This routine recovers the missing heights based on the pressure
23 ! under the hydrostatic assumption, or the model reference state.
24 ! for the multi-level OBS data (SOUND, AIREP, etc.).
29 INTEGER, INTENT ( IN ) :: max_number_of_obs
30 TYPE (report), DIMENSION (max_number_of_obs):: obs
31 INTEGER , INTENT ( IN ) :: number_of_obs
32 LOGICAL , INTENT ( IN ) :: print_hp_recover
34 TYPE (measurement), POINTER :: current
37 INTEGER :: i, j, nlevel, k, &
39 CHARACTER (LEN = 80) :: filename
40 CHARACTER (LEN = 80) :: proc_name = &
41 "recover_height_from_pressure"
42 LOGICAL :: connected, correct, failed
46 TYPE (field) , dimension(9000) :: hh
47 REAL , dimension(9000) :: pp, tt, qq
49 INCLUDE 'platform_interface.inc'
51 !------------------------------------------------------------------------------!
53 '------------------------------------------------------------------------------'
54 WRITE (UNIT = 0, FMT = '(A,/)') 'HEIGHT RECOVERED FROM P, T, Q,..:'
57 ! Open diagnostic file
59 IF (print_hp_recover) THEN
61 filename = 'obs_recover_height.diag'
64 INQUIRE (UNIT = iunit, OPENED = connected )
66 IF (connected) CLOSE (iunit)
68 OPEN (UNIT = iunit , FILE = filename , FORM = 'FORMATTED' , &
69 ACTION = 'WRITE' , STATUS = 'REPLACE', IOSTAT = io_error )
71 IF (io_error .NE. 0) THEN
72 CALL error_handler (proc_name, &
73 "Unable to open output diagnostic file. " , filename, .TRUE.)
75 WRITE (UNIT = 0, FMT = '(A,A,/)') &
76 "Diagnostics in file ", TRIM (filename)
81 IF (print_hp_recover) &
82 WRITE (UNIT = IUNIT, FMT = '(/A/)') &
83 'HEIGHT RECOVERED FROM PRESSURE FOR MULTI-LEVEL OBS DATA:'
96 DO i = 1, number_of_obs
98 IF ((obs (i) % info % discard) .OR. .NOT. ASSOCIATED &
99 (obs (i) % surface)) THEN
106 ! 2. SINGLE LEVEL OBS
107 ! ====================
110 IF ((ASSOCIATED (obs (i) % surface)) .AND. &
111 (.NOT.ASSOCIATED (obs (i) % surface % next))) THEN
113 ! IF height is missing, pressure should be present
116 obs (i) % surface % meas % height % data, missing_r, 1.)) THEN
118 obs (i) % surface % meas % height % data = ref_height &
119 (obs (i) % surface % meas % pressure % data)
120 obs (i) % surface % meas % height % qc = Reference_atmosphere
122 obs (i) % surface % meas % height % data = NINT &
123 (obs (i) % surface % meas % height % data + .5)
124 obs (i) % surface % meas % height % data = MAX &
125 (obs (i) % surface % meas % height % data, 0.)
128 IF (print_hp_recover) THEN
130 WRITE (UNIT = iunit,FMT = '(/,A,A5,1X,A23,2F9.3)') &
131 "Recover 1 level station id = ", &
132 TRIM (obs (i) % location % id ) , &
133 TRIM (obs (i) % location % name), &
134 obs (i) % location % latitude, &
135 obs (i) % location % longitude
136 WRITE (UNIT = iunit, FMT = '(2(A,I5),A)') &
137 "Use reference state to infer height (", &
138 INT (obs (i) % surface % meas % height % data), &
139 "m) from pressure (",&
140 INT (obs (i) % surface % meas % pressure % data/100.),"hPa)."
145 ! Recover station elevation for single level obs
148 ! obs (i) % info % elevation, missing_r, 1.)) THEN
149 ! obs (i) % info % elevation = &
150 ! obs (i) % surface % meas % height % data
159 ! Y.-R. Guo (10/25/2005):.......
160 call reorder(obs(i), i, 'pressure', failed)
162 obs(i) % info % discard = .true.
166 ! ..........................................
167 ! 3.1 Get the OBS profile and count the number of levels
168 ! --------------------------------------------------
172 current => obs(i)%surface
175 DO WHILE (ASSOCIATED (current))
179 hh (nlevel) = current%meas%height
180 pp (nlevel) = current%meas%pressure%data
181 tt (nlevel) = current%meas%temperature%data
182 qq (nlevel) = current%meas%qv%data
184 IF (eps_equal(current%meas%height%data, missing_r, 1.)) THEN
188 current => current%next
192 ! 3.2 If all levels have height, go to next station
193 ! ---------------------------------------------
195 IF (.not.correct) CYCLE loop_all
198 ! 3.2 Otherwise recover missing height for upper-level
199 ! ------------------------------------------------
202 IF (nlevel <= 1) THEN
204 IF (print_hp_recover) THEN
205 WRITE (UNIT = iunit , FMT = '(A,A5,1X,A23,2F9.3)') &
206 "No level found for sound id= " , &
207 TRIM (obs (i) % location % id ) , &
208 TRIM (obs (i) % location % name), &
209 obs (i) % location % latitude, &
210 obs (i) % location % longitude
213 STOP 'in recover_height.F90'
215 ELSE IF (nlevel > 1) THEN levels
217 CALL recover_h_from_ptq (pp, tt, qq, hh, nlevel,k_start,k_top)
219 IF (k_start >= 1 .or. k_top <= nlevel) THEN
221 IF (print_hp_recover) &
222 WRITE (UNIT = iunit, FMT = '(/,A,A5,1X,A23,2F9.3)') &
223 "Recover upperair station id = ", &
224 TRIM (obs (i) % location % id ) , &
225 TRIM (obs (i) % location % name), &
226 obs (i) % location % latitude, &
227 obs (i) % location % longitude
237 current => obs(i)%surface
240 DO WHILE (ASSOCIATED (current))
244 ! IF (eps_equal(current%meas%height%data, missing_r, 1.)) THEN
246 IF (print_hp_recover) THEN
247 WRITE (UNIT = iunit, FMT = '(2(A,I5),A)') &
248 "Height missing set to ",INT (hh (k) % data), &
249 "m, pressure = ",INT (pp(k)/100.),"hpa."
252 current%meas%height % data = CEILING (hh(k)%data)
253 current%meas%height % qc = hh(k)%qc
257 current => current%next
262 call reorder(obs(i), i, 'pressure', failed)
264 obs(i) % info % discard = .true.
268 ! 3.4 Go to next station
273 IF (print_hp_recover) CLOSE (IUNIT)
275 END SUBROUTINE recover_height_from_pressure
277 !-----------------------------------------------------------------------
279 SUBROUTINE recover_h_from_ptq(P,T,Q,HGT,KXS,K_START,K_TOP)
280 !-----------------------------------------------------------------------
281 ! To recover the missing heights for the MULTI-LEVEL (KXS>1) OBS data
283 ! (1) To compute the heights based on pressure(P), and available
284 ! temperature(T) and specific humidity(Q) under the hydrostatic
287 ! Using the available observed heights to calibrate the computed
288 ! heights, then these calibrated and computed heights are used
289 ! where the observed heights are missing.
291 ! (2) When the hydrostatic assumption can not be applied at the bottom
292 ! (K_START > 1) or top (K_TOP < KXS) part of the atmosphere, the
293 ! model reference state is used to derive the missing heights based
294 ! on the observed pressure with the calibration from the available
299 ! In case (1), the derived heights have very high accuracy since only
300 ! a high accurate "hydrostatic assumption" used here.
302 ! In case (2), the model reference state parameters are used. These
303 ! parameters are consistent with the model BKG, and independent of
304 ! the model domain settings. Of course, the model reference state
305 ! atmosphere is not a real atmosphere, but it's consistent with the model.
306 ! With the observed heights calibrated, these derived heights
307 ! also included some information from OBS (pressure and height).
309 ! This subroutine can not be applied to the SIGLE-LEVEL(KXS=1) data.
310 ! For those OBS, the missing heights can only be derived from the
311 ! observed pressure and the model BKG and reference state (subroutine
317 !-------------------------------------------------------------------------
321 INTEGER, INTENT(in) :: KXS
322 REAL , DIMENSION(KXS), INTENT(in) :: T, Q, P
323 TYPE (field), DIMENSION(KXS), INTENT(inout) :: HGT
324 INTEGER, INTENT(out) :: k_start,k_top
326 INTEGER :: k, kk, kwk, L, K0, K1, K2
327 REAL :: height0, height1, diff_hp, &
328 TM1, TM2, ALNP, DDH, DDP, DHH, &
329 dh1, dh2, dp1, dp2, aa, bb, cc
330 INTEGER,dimension(9000) :: KP
331 REAL ,DIMENSION(9000) :: TWK, QWK, PWK, HWK, DHGT
334 TYPE (field), DIMENSION(KXS) :: HGT0, HGT1
336 include 'constants.inc'
337 ! -------------------------------------------------------------------
341 ! .. get data at the first levels where both pressure and height
345 ! Find the first level with height, pressure and temperature
352 IF (.NOT. eps_equal(P (k) , missing_r, 1.) .AND. &
353 .NOT. eps_equal(HGT(k)%data, missing_r, 1.) .AND. &
354 .NOT. eps_equal(T (k) , missing_r, 1.)) THEN
362 ! Obs without temperature and/or height are processed here
364 IF (K_start == 0) THEN
368 IF (.NOT. eps_equal(P (k) , missing_r, 1.) .AND. &
369 eps_equal(HGT(k)%data, missing_r, 1.)) THEN
371 HGT(k)%data = ref_height (P (k) )
372 HGT(k)%qc = reference_atmosphere
377 ! To avoid the duplicated heights between the computed and
380 1999 Vert_ok = .True.
383 if ((P(k) < P(K-1)) .and. (HGT(k)%data > HGT(k-1)%data)) then
387 if (HGT(k)%qc <= 0) then
388 ! HGT at level k-1 is computed:
393 HGT(k-1)%data = (HGT(k)%data*BB + HGT(k-2)%data * CC) / AA
394 ! Y.-R. Guo (10/25/2005), Y.-R. Guo (01/16/2006):
395 if (HGT(k-1)%qc>0) HGT(k-1)%qc = - HGT(k-1)%qc
396 ! print '(" Computed k=",i3," pp,hh,qc:",2f11.2,i8)', k-1,p(k-1),HGT(k-1)%data, HGT(k-1)%qc
399 if ( k <= kxs-1 ) then
403 HGT(k-1)%data = (HGT(k+1)%data*BB + HGT(k)%data * CC) / AA
405 ! Y.-R. Guo (1/31/2008): must be processed separately when k >= kxs
406 AA = HGT(k)%data - ref_height (P (k) )
407 HGT(k-1)%data = HGT(k-1)%data + AA
409 ! Y.-R. Guo (10/25/2005), Y.-R. Guo (01/16/2006):
410 if (HGT(k-1)%qc>0) HGT(k-1)%qc = - HGT(k-1)%qc
413 ! HGT at level k is computed
414 if ( k <= kxs-1 ) then
418 HGT(k)%data = (HGT(k+1)%data*BB + HGT(k-1)%data * CC) / AA
420 ! Y.-R. Guo (1/31/2008): must be processed separately when k >= kxs
421 AA = HGT(k-1)%data - ref_height (P (k-1) )
422 HGT(k)%data = HGT(k)%data + AA
424 ! Y.-R. Guo (10/25/2005), Y.-R. Guo (01/16/2006):
425 if (HGT(k-1)%qc>0) HGT(k-1)%qc = - HGT(k-1)%qc
429 if (.Not. Vert_ok) goto 1999
434 ! Y.-R. Guo (10/25/2005):
436 HGT(k)%qc = abs(HGT(k)%qc)
437 ! print '(i3," p,h,qc:",2f12.2,i8)', k, p(k), HGT(k)%data, HGT(k)%qc
444 ! .. if k_start > 1, using the model reference state to get
445 ! the height at any level k below the level k_start,
446 ! keep the height difference between level k_start and level k
447 ! same as between the observed height and the model reference height
450 IF (k_start > 1) THEN
452 ! Model reference height
454 height1 = Ref_height (p(k_start))
456 DO k = k_start-1, 1, -1
460 IF (eps_equal (hgt(k)%data, missing_r, 1.)) THEN
462 IF (p(k)-p(k_start) > 20000.) THEN
464 ! too far below (200mb) the level where the OBS height available
466 HGT(k)%data = Ref_height(P(k))
467 HGT(k)%qc = reference_atmosphere
471 HGT(k)%data = HGT(k_start)%data - height1 &
473 HGT(k)%qc = reference_OBS_scaled
483 ! Use the hydrostatic equation to correct the heigt
490 IF (.NOT.eps_equal(T(k), missing_r, 1.)) THEN
499 HWK(1) = HGT(k_start)%data * G
501 ! ... INTEGRATE HYDROSTATIC EQN
506 ALNP = ALOG (PWK(K-1) /PWK(K)) * gasr
508 IF (.NOT.eps_equal(QWK(k), missing_r, 1.)) THEN
509 TM2 = TWK(K )*(1.+0.608*QWK(K ))
514 IF (.NOT.eps_equal(QWK(k-1), missing_r, 1.)) THEN
515 TM1 = TWK(K-1)*(1.+0.608*QWK(K-1))
519 HWK(K) = HWK(K-1) + .5*(TM1+TM2) * ALNP
523 ! .. CALIBRATION OF THE HWK BASED ON THE AVAILABLE HGT:
531 IF (eps_equal(HGT(K)%data, missing_r, 1.)) then
535 IF (P(K).EQ.PWK(KK)) THEN
538 DHGT(K0) = HWK(KK)/G - HGT(K)%data
546 ! .. levels between k_start(K0=1) and K0-1
552 DDH = DHGT(L+1) - DHGT(L)
553 DDP = ALOG(PWK(K2)/PWK(K1))
554 DHH = DHGT(L) + ALOG(PWK(KK)/PWK(K1))*DDH/DDP
555 HWK(KK) = HWK(KK)/G - DHH
559 ! .. Above the level KP(K0):
562 HWK(K) = HWK(K)/G - DHGT(K0)
564 ! WRITE(0,'(I3,2X,4E15.5)') &
565 ! (L,PWK(L),TWK(L),QWK(L),HWK(L),L=1,KWK)
568 ! .. FILL BACK THE HEIGHTS AT THE LEVELS WHERE TEMPERATURE AVAILABLE:
570 height1 = Ref_height(Pwk(kwk))
572 above_k_start: DO K = k_start,KXS
574 if (abs(P(K) - PWK(KWK)) < 0.01) k_top = k
576 ! if (eps_equal(HGT(k)%data, missing_r, 1.)) then
578 IF (P(K) >= PWK(KWK)) then
581 IF (P(K).EQ.PWK(KK)) THEN
582 HGT(K)%data = HWK(KK)
583 ELSE IF (KK.LT.KWK .AND. &
584 P(K).LT.PWK(KK) .AND. P(K).GT.PWK(KK+1)) THEN
586 ! .. Get the interpolated heights at the levels temperature unavailable:
588 ALNP = ALOG (P(K)/PWK(KK)) / ALOG(PWK(KK+1)/PWK(KK))
589 HGT(K)%data = HWK(KK) + ALNP*(HWK(KK+1)-HWK(KK))
592 HGT(k)%qc = Hydrostatic_recover
594 if ((PWK(KWK)-P(K)) > 10000.) then
596 ! too far above (100mb) the level where the OBS height available
598 HGT(k)%data = Ref_height(P(k))
599 HGT(k)%qc = reference_atmosphere
601 HGT(k)%data = Hwk(kwk) - height1 &
603 HGT(k)%qc = reference_OBS_scaled
612 ! Non-hydrastatic adjustment:
614 ! In case of only P and H observed without T, TD, the hydrostatic
615 ! height may be different from the observed H. We must keep this
616 ! observed H, and adjust the calculated heights at the adjacent
617 ! levels to avoid inconsistency between P and H when having
618 ! the dense observed levels.
620 ! Yong-Run Guo 12/06/2001
621 ! ------------------------------------------------------------
622 ! .. Find the starting level with the observed height:
623 ! Fixed the bug on 07/08/2004
626 if (HGT0(k) % qc == 0) then
631 ! ------------------------------------------------------------
633 ! .. Keep the calculated height:
637 ! .. Find the starting level (k1+1) without the observed height:
638 if (HGT0(k) % qc /= 0 .and. k1 == 0) then
640 else if (HGT0(k) % qc == 0 .and. &
641 abs(HGT0(k)%data - HGT(k)%data) <= 0.10*HGT(k)%data ) then
645 ! .. Find the ending level (k2-1) without the observed height:
646 if (HGT0(k) % qc == 0 .and. k1 > 0 .and. k > k1+1) then
649 if (abs(HGT0(k2)%data - HGT(k2)%data) > 0.10*HGT(k2)%data) then
651 ! ....When the difference between the observed height and retrieved height
652 ! greater than 10% of Hydro. Retrv. height, ignore the observed height,
653 ! and no adjustment done:
661 ! .. Adjust the calculated hydristatic heights from level k1+1 to k2-1:
663 dh1 = HGT0(k1)%data - HGT(k1)%data
664 dh2 = HGT0(k2)%data - HGT(k2)%data
667 HGT1(kk)%data = HGT(kk)%data + dh1*(1-dp1/dp2) + dh2*dp1/dp2
668 HGT1(kk)%qc = HGT(kk)%qc
669 HGT1(kk)%error= HGT(kk)%error
678 ! .. Fill back to HGT with HGT1:
681 END subroutine recover_h_from_ptq
682 !------------------------------------------------------------------------------!
684 SUBROUTINE reorder(obs, i, order_component, failed)
685 !------------------------------------------------------------------------------!
689 INTEGER, INTENT (in) :: i
690 CHARACTER*(*), INTENT (in) :: order_component
691 TYPE (report), INTENT (inout) :: obs
694 INCLUDE 'missing.inc'
696 TYPE (measurement), pointer :: current, new, tmp, pre
698 integer :: num, ii, num_loop, nlevels
699 logical :: need_check
704 current => obs % surface
705 count_levels: do while (associated(current))
707 current => current%next
711 current => obs%surface
718 missing_check: do while (associated(current))
720 if(eps_equal(comp_field(current,order_component), &
721 missing_r, 1.0)) then
722 ! remove the missing data link:
725 current => current%next
728 if (num /= nlevels) then
729 write(0,'(/I5,A,A,A/3X,A,A,A,A,A,2I5,A,f10.3,A,f10.3)') I, &
730 ' There are ',order_component,&
731 ' at several levels missing. Reordering can not be done.', &
732 ' FM=',obs%info%platform(4:5),' ID=',obs%location%id(1:5), &
733 ' nlevels, num:', nlevels, num, &
734 ' lat=', obs%location%latitude, ' long=', obs%location%longitude
739 ! Re-set the number of levels to OBS
741 obs % info % levels = nlevels
743 if (nlevels <= 1) return
750 put2order: do while(need_check)
752 num_loop = num_loop + 1
754 head_check: do while(need_check)
756 current => obs%surface
760 if(comp_field(current,order_component) < &
761 comp_field(current%next,order_component)) then
762 !--------Cut the first on off and put it in pointer tmp:
764 current => current%next
771 !--------if first pressure is not good, through tmp away
773 if(eps_equal(comp_field(current,order_component), &
774 missing_r, 1.0)) then
776 ! Don't allow happened
777 STOP 'in reorder_missing data'
781 !--------Now we need to put pointer tmp to a place.
783 current => obs%surface
785 new => obs%surface%next
787 nullify(current%next)
789 allocate(current%next)
798 if(num < 3) exit put2order
802 ! current => obs%surface
806 ! do while (associated(current))
808 ! write(0,'(A,I3,A,I3,3f12.2)') 'num_loop=',num_loop, &
810 ! current%meas%pressure%data, current%meas%height%data, &
811 ! current%meas%temperature%data
812 ! current => current%next
815 !-----Put others in order
818 current => obs%surface%next
819 new => obs%surface%next%next
821 do while (associated(new))
822 if(comp_field(current,order_component) < &
823 comp_field(current%next,order_component)) then
828 nullify(current%next)
842 current => current%next
847 ! current => obs%surface
851 ! do while (associated(current))
853 ! write(0,'(A,I3,A,I3,3f12.2)') 'num_loop=',num_loop, &
855 ! current%meas%pressure%data, current%meas%height%data, &
856 ! current%meas%temperature%data
857 ! current => current%next
863 ! current => obs%surface
866 ! do while (associated(current))
868 ! write(0,'(A,I3,3f12.2)') 'I,P,H,T:', ii, &
869 ! current%meas%pressure%data, current%meas%height%data, &
870 ! current%meas%temperature%data
871 ! current => current%next
874 END subroutine reorder
875 !------------------------------------------------------------------------------!
877 FUNCTION comp_field(current, order_component) result(xxx)
878 !------------------------------------------------------------------------------!
880 type (measurement), pointer :: current
881 character*(*), intent(in) :: order_component
884 SELECT CASE (order_component)
888 xxx = current%meas%pressure%data
892 xxx = current%meas%height%data
896 WRITE(0,'(A,A,A)') 'order_component=',order_component, &
897 ' is not defined correctly'
902 END function comp_field
903 !------------------------------------------------------------------------------!
905 END MODULE module_recoverh