<HTML> <BODY BGCOLOR=#ccccdd LINK=#0000aa VLINK=#0000ff ALINK=#ff0000 ><BASE TARGET="bottom_target"><PRE>
<A NAME='MODULE_THIN_OB'><A href='../../html_code/obsproc/module_thin_ob.F90.html#MODULE_THIN_OB' TARGET='top_target'><IMG SRC="../../gif/bar_purple.gif" border=0></A>
MODULE module_thin_ob 1
USE module_type
USE module_func
USE module_mm5
USE module_map
USE map_utils
USE module_namelist
CONTAINS
<A NAME='THIN_OB'><A href='../../html_code/obsproc/module_thin_ob.F90.html#THIN_OB' TARGET='top_target'><IMG SRC="../../gif/bar_red.gif" border=0></A>
SUBROUTINE THIN_OB (max_number_of_obs, obs, number_of_obs, mix, mjx, & 4,14
missing_r, Ob_name, Ob_fm, Delta_P)
! --------------------------------------------------------------------------
! Purpose: To thin the sateliite (SATOB, SSMI Retrieval and Tb) data.
! Method : To select only ONE data nearest to the center of the (I,J,K)
! grid-box if there are more than one OBS within that gridbox.
!
! The vertical P_thickness is defined by Delta_P.
! Currently for SATOB the maximum of 100 level in vertical
! and maximum of 20 data points within a grid box are allowed.
! For the single level SSMI the maximum of 400 data points
! within a gridbox is allowed.
!
! Yong-Run Guo 05/01/2001
! --------------------------------------------------------------------------
!
implicit none
INTEGER, INTENT (in) :: max_number_of_obs
TYPE (report), DIMENSION (max_number_of_obs), INTENT (inout) :: obs
INTEGER, INTENT (in) :: number_of_obs
CHARACTER (LEN = *), INTENT (in) :: Ob_name
INTEGER, INTENT (in) :: Ob_fm
REAL, INTENT (in) :: missing_r
REAL , OPTIONAL, INTENT (in) :: Delta_P
INTEGER :: n, fm, i, j, k, kk, num_box, &
max_num, mix, mjx, num, nn, total, &
max_box, LV, N_selected, N1_selected
INTEGER, ALLOCATABLE :: Num_ob(:,:,:), Ob_index(:,:,:,:)
REAL :: X, Y, dx, dy, RR, Rmin, R1min
TYPE ( meas_data ) :: new
INTEGER :: nvalids_fm
!------------------------------------------------------------------
!
! 1.0 Allocate the working arrays
!
! The default size: LV, max_box can be changed to meet the needs.
!
! For SATOB
if (Ob_fm == 88) then
LV = 100
max_box = 50
! For SSMI
else if (Ob_fm == 125 .or. Ob_fm == 126 .or. Ob_fm == 281) then
LV = 1
max_box = 400
else
WRITE(0,'(A,I3,A)') ' FM=',Ob_fm,' NOT SATELLITE OBS,', &
' NO THINING APPLIED TO IT.'
return
endif
allocate (Num_ob (mix,mjx,LV))
allocate (Ob_index(mix,mjx,LV,max_box))
WRITE(0,'(/"Thining OBS ==> ",A,1X,"FM=",I3,2X, &
& "mix, mjx, LV, max_box:",4I6)') &
& Ob_name, Ob_fm, mix, mjx, LV, max_box
!
! 2.0 To count the number of OBS within the grid boxes
! ------------------------------------------------
Num_ob = 0
nvalids_fm = 0
! 2.1 Loop over stations
! ------------------
stations: &
DO n = 1, number_of_obs
stations_valid: &
IF (obs (n)%info%discard ) THEN
CYCLE stations
ELSE stations_valid
READ (obs (n) % info % platform (4:6), '(I3)') fm
if (fm /= Ob_fm) CYCLE stations
nvalids_fm = nvalids_fm + 1
SELECT CASE (Ob_fm)
! 2.2 count the number of SATOB within the grid box for thining
!
CASE (88)
new = obs (n) % surface % meas
if (eps_equal (new%pressure%data, missing_r, 1.)) then
CYCLE stations
else
! 2.2.1 Calculate the model horizonatl coordinates: I, J, and the
! vertical index K
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
J = INT(X + .5)
I = INT(Y + .5)
K = INT(new % pressure % data / Delta_p)
! 2.2.2 Grid-box counter
Num_ob (i,j,k) = Num_ob (i,j,k) + 1
! 2.2.3 Keep the OBS indices for each of the grid-box
Ob_index(i,j,k, Num_ob(i,j,k)) = n
endif
! 2.3 count the number of SSMI within the grid box for thining
!
CASE (125, 126)
! 2.3.1 Calculate the model horizonatl coordinates: I, J
!
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
J = INT(X + .5)
I = INT(Y + .5)
K = 1
! 2.3.2 Grid-box counter
Num_ob (i,j,k) = Num_ob (i,j,k) + 1
! 2.3.3 Keep the OBS indices for each of the grid-box
Ob_index(i,j,k, Num_ob(i,j,k)) = n
! 2.4 count the number of QSCAT within the grid box for thining
CASE ( 281)
! 2.4.1 Calculate the model horizonatl coordinates: I, J
!
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
J = INT(X + .5)
I = INT(Y + .5)
K = 1
! 2.4.2 Grid-box counter
Num_ob (i,j,k) = Num_ob (i,j,k) + 1
! 2.4.3 Keep the OBS indices for each of the grid-box
Ob_index(i,j,k, Num_ob(i,j,k)) = n
! Others
CASE DEFAULT;
! Should never come here
END SELECT
ENDIF stations_valid
ENDDO stations
! 2.5 Print the total number of boxes and columns data available
! ----------------------------------------------------------
!
WRITE(0,'("VALID NO.=",I6)') nvalids_fm
! 2.5.1 Print the total number of boxes data available
num_box = 0
DO K = 1,LV
kk = 0
max_num = 0
DO I = 1,MIX
DO J = 1,MJX
IF (Num_ob (i,j,k) > 0) THEN
max_num = max(max_num, Num_ob (i,j,k))
kk = kk + 1
num_box = num_box + 1
ENDIF
ENDDO
ENDDO
if (kk >0) &
WRITE(0,'(A,I5,A,I5,A,I3)') "LEVEL ", K, " NUM=", KK, " Max=", max_num
ENDDO
write(0,'(10X,"Total Number of Boxes ",I6)') num_box
! 2.5.2 Print the total number of columes data available
num_box = 0
DO I = 1,MIX
DO J = 1,MJX
kk = 0
DO K = 1,LV
KK = KK + Num_ob (i,j,k)
ENDDO
if (kk > 0) num_box = num_box + 1
enddo
enddo
write(0,'(10X,"Number of columns =", I5)') num_box
! 3.0 Select the ONE data within one grid box
! ---------------------------------------
DO K = 1,LV
DO I = 1,MIX
NEXT_box:DO J = 1,MJX
N_selected = -99
N1_selected = -99
num = Num_ob (i,j,k)
if (num <= 1) cycle NEXT_box
! 3.1 The data nearest to the center of grid box (I,J) is selected
Rmin = 100.0
R1min = 100.0
Select_ob:do nn = 1,num
n = Ob_index(i,j,k,nn)
SELECT CASE (Ob_fm)
! 3.1.1 Select one SATOB within a grid-box
CASE (88)
new = obs (n) % surface % meas
if (new % pressure % qc == 0 .and. &
new % speed % qc == 0 .and. &
new % direction % qc == 0) then
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
X = X + .5
Y = Y + .5
dx = X - float(J)
dy = Y - float(I)
RR = dx*dx + dy*dy
if (RR < Rmin) then
N_selected = n
Rmin = RR
endif
endif
! 3.1.2 Select one good SSMI Retrieval Speed and one PW within a grid-box
! This may be in same obs(n): N_selected = N1_selected = n
!
CASE (125)
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
X = X + .5
Y = Y + .5
dx = X - float(J)
dy = Y - float(I)
RR = dx*dx + dy*dy
! Speed
IF (ASSOCIATED (obs (n) % surface)) then
new = obs (n) % surface % meas
if (new % speed % qc == 0) then
if (RR < Rmin) then
N_selected = n
Rmin = RR
endif
endif
endif
! PW
if (obs(n)%ground% pw % qc == 0) then
if (RR < R1min) then
N1_selected = n
R1min = RR
endif
endif
! 3.1.3 Select one good SSMI Tb within a grid-box
! Only keep the data when the data for all channels are good
CASE (126)
if (obs (n) % ground % tb19v % qc == 0 .and. &
obs (n) % ground % tb19h % qc == 0 .and. &
obs (n) % ground % tb22v % qc == 0 .and. &
obs (n) % ground % tb37v % qc == 0 .and. &
obs (n) % ground % tb37h % qc == 0 .and. &
obs (n) % ground % tb85v % qc == 0 .and. &
obs (n) % ground % tb85h % qc == 0) then
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
X = X + .5
Y = Y + .5
dx = X - float(J)
dy = Y - float(I)
RR = dx*dx + dy*dy
if (RR < Rmin) then
N_selected = n
Rmin = RR
endif
endif
! 3.1.2 Select one good QUIKSCAT within a grid-box
!
CASE (281)
if (fg_format == 'MM5') then
call LLXY
(obs (n) % location % latitude, &
obs (n) % location % longitude, X, Y)
else if (fg_format == 'WRF') then
call latlon_to_ij
(map_info, obs(n)%location%latitude, &
obs (n)%location%longitude, X, Y)
X = X + .5
Y = Y + .5
endif
X = X + .5
Y = Y + .5
dx = X - float(J)
dy = Y - float(I)
RR = dx*dx + dy*dy
! if the speed is OK, keep this report.
IF (ASSOCIATED (obs (n) % surface)) then
new = obs (n) % surface % meas
if (new % speed % qc == 0) then
if (RR < Rmin) then
N_selected = n
Rmin = RR
endif
endif
endif
! Others
CASE DEFAULT;
! Should never come here
END SELECT
enddo Select_ob
! 3.2 Discard the unselected data
Discard:do nn = 1,num
n = Ob_index(i,j,k,nn)
SELECT CASE (Ob_fm)
! 3.2.1 Thining SATOB data by setting discard = .TRUE.
CASE (88)
if (n /= N_selected) obs(n) % info % discard = .TRUE.
! 3.2.3 Thining SSMI Retrieval data by setting discard = .TRUE.
CASE (125)
if (n /= N_selected .and. &
n /= N1_selected) obs(n) % info % discard = .TRUE.
! 3.2.4 Thining SSMI Tb data by setting discard = .TRUE.
CASE (126)
if (n /= N_selected) obs(n) % info % discard = .TRUE.
! 3.2.5 Thining QUIKSCAT data by setting discard = .TRUE.
CASE (281)
if (n /= N_selected) obs(n) % info % discard = .TRUE.
! Others
CASE DEFAULT;
! Should never come here
END SELECT
enddo Discard
ENDDO NEXT_box
ENDDO
ENDDO
! 4.0 deallocate the working arrays
deallocate (Num_ob)
deallocate (Ob_index)
END SUBROUTINE THIN_OB
END MODULE module_thin_ob