SURFEX v8.1
General documentation of Surfex
horibl_surf_value.F90
Go to the documentation of this file.
1 !SFX_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
2 !SFX_LIC This is part of the SURFEX software governed by the CeCILL-C licence
3 !SFX_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
4 !SFX_LIC for details. version 1.
5 ! #########
6  SUBROUTINE horibl_surf_value(KILEN,KOLEN,PAROUT,OINTERP,PARIN,KLSMIN,&
7  POLO,POLA,PLA,PLOP,&
8  KMASKIN,KLSMOUT )
9 ! ###########################################################################
10 !
11 !!**** *HORIBL_SURF_VALUE* - horitontal bilinear interpolation
12 !!
13 !! PURPOSE
14 !! -------
15 !!
16 !! Interpolates a field, supports masks.
17 !!
18 !! METHOD
19 !! ------
20 !!
21 !! This routine performs a bilinear interpolation based on the 12 surrounding
22 !! points. It begins with an interpolation along the latitudes (with third order
23 !! polynoms interpolation with 4 points and linear interpolation for 2 points)
24 !! and then a second along the longitude (third order polynoms interpolation).
25 !! Two interpolations are performed : first along the parallels then between the
26 !! four resulting points.
27 !!
28 !! The disposition of the points is the following :
29 !!
30 !!
31 !! N 1 2
32 !!
33 !! ^ 3 4 5 6
34 !! | x
35 !! | 7 8 9 10
36 !! |
37 !! 11 12
38 !! S
39 !! W ---------------> E
40 !!
41 !! Note : the name 'south', 'north', may not be exact if the last data point is
42 !! to the south of first (delta latitude < 0). This does not affect computations.
43 !!
44 !! The formula used to compute the weight is :
45 !! (Lon - Lon.i) . (Lon - Lon.i) . (Lon - Lon.i)
46 !! Wi = ---------------------------------------------------
47 !! (Lon.i - Lon.j) . (Lon.i - Lon.k) . (Lon.i - Lon.l)
48 !! Where j,k,l are the other points of the line.
49 !!
50 !! When masks are used, points with different types than the output points are
51 !! not taken in account (in the formula, the corresponding coefficient is set
52 !! to 1). If no points of the same nature are available, the interpolation is
53 !! performed anyway with the 12 points. It is the task of the calling program
54 !! to react to this situation.
55 !!
56 !! When the inputs parameters define a circular map (or global), the inputs data
57 !! are extended. The value of the parameter ODVECT is used to know if the datas
58 !! are vectorial or scalar (this affects the sign of extended values).
59 !!
60 !! EXTERNAL
61 !! --------
62 !!
63 !! subroutine FMLOOK_ll : to retrieve the logical unit number of the listing file
64 !!
65 !! IMPLICIT ARGUMENTS
66 !! ------------------
67 !!
68 !! REFERENCE
69 !! ---------
70 !!
71 !! This routine is based on the one used by the software FULL-POS from Meteo France.
72 !! More informations may be found in 'Book 1'
73 !!
74 !! AUTHOR
75 !! ------
76 !!
77 !! J.Pettre & V.Bousquet
78 !!
79 !! MODIFICATIONS
80 !! -------------
81 !!
82 !! Original 07/01/1999
83 !! 21/04/1999 (V. Masson) set correct prefixes and bug in
84 !! a logical definition
85 !! 21/04/1999 (V. Masson) bug in north and south poles
86 !! extension for input map land-sea mask
87 !! 27/05/1999 (V. Masson) bug in 'grib south pole'
88 !! extrapolation (number of point per parallel)
89 !! 27/05/1999 (V. Masson) bug in 'grib pole' extrapolation
90 !! extra latitudes are now computed symetrically
91 !! to the poles.
92 !! 17/03/2010 (P. LeMoigne) bug in weights computations
93 !! 16/06/2010 (G. Tanguy) bug in 'grib north pole"
94 !! extrapolation (tabular PARIN not totaly filled)
95 !!
96 !------------------------------------------------------------------------------
97 !
98 !
99 !* 0. DECLARATIONS
100 ! ---------------
101 !
102 !
103 USE modd_surf_par, ONLY : xundef
104 !
105 USE yomhook ,ONLY : lhook, dr_hook
106 USE parkind1 ,ONLY : jprb
107 !
108 USE modi_abor1_sfx
109 !
110 IMPLICIT NONE
111 !
112 !* 0.1. Declaration of arguments
113 !
114 INTEGER, INTENT(IN) :: KILEN
115 INTEGER, INTENT(IN) :: KOLEN ! size of output array
116 REAL, DIMENSION(:), INTENT(OUT) :: PAROUT ! output array
117 LOGICAL, DIMENSION(:), INTENT(IN) :: OINTERP ! .true. where physical value is needed
118 REAL, DIMENSION(:,:), INTENT(IN) :: PARIN
119 INTEGER, DIMENSION(:,:), INTENT(IN) :: KLSMIN
120 REAL, DIMENSION(:), INTENT(IN) :: POLO, POLA
121 REAL, DIMENSION(:,:), INTENT(IN) :: PLA
122 REAL, DIMENSION(:,:), INTENT(IN) :: PLOP
123 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: KMASKIN ! input land/sea mask
124 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: KLSMOUT ! output land/sea mask
125 !
126 !* 0.2. Declaration of local variables
127 !
128 ! Weights of the latitudes and of the points
129 REAL, DIMENSION(4) :: ZWV
130 REAL, DIMENSION(12) :: ZWP
131  ! Land/sea mask coefficient for each point : 0 -> point not taken in account,
132  ! 1 -> point taken in account
133 REAL, DIMENSION(12) :: ZLSMP
134 REAL, DIMENSION(4) :: ZLSMV
135 REAL :: ZLSMTOT
136  ! Variables implied in the extension procedure
137 LOGICAL :: LDLSM ! Specify if land/sea mask is present or not
138  ! Loop counters
139 INTEGER :: JL, JI ! Dummy counter
140 !
141 !------------------------------------------------------------------------------
142 REAL, DIMENSION(3) :: ZP
143 REAL :: ZMAX, ZT ! Max of 12 surrounding values
144 REAL :: ZMIN ! Min of 12 surrounding values
145 INTEGER :: JL2 ! Dummy counter
146 REAL(KIND=JPRB) :: ZHOOK_HANDLE, ZHOOK_HANDLE_OMP
147 !------------------------------------------------------------------------------
148 !
149 !* 1. DETERMINATION of the latitude of the poles (depending of the latitude
150 ! ------------- of the first data point)
151 !
152 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_1',0,zhook_handle)
153 !
154 ldlsm = .false.
155 IF (PRESENT(kmaskin) .AND. PRESENT(klsmout)) ldlsm = .true.
156 !
157 !------------------------------------------------------------------------------
158 !
159 !* 3. LOOP OVER ALL THE POINTS OF THE OUTPUT GRID
160 ! -------------------------------------------
161 !
162 parout(:) = xundef
163 !
164 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_1',1,zhook_handle)
165 !$OMP PARALLEL PRIVATE(ZHOOK_HANDLE_OMP)
166 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_2',0,zhook_handle_omp)
167 !$OMP DO SCHEDULE(DYNAMIC,1) PRIVATE(JL,ZLSMP,ZLSMV,ZLSMTOT,ZP,ZT,&
168 !$OMP ZWV,ZWP,JI,ZMIN,ZMAX,JL2)
169 DO jl = 1, kolen
170 !
171  IF (.NOT. ointerp(jl)) cycle
172 !
173 !* 3.2 Land / Sea mask
174 !
175  zlsmp(:) = 1.
176  zlsmv(:) = 1.
177  !
178  IF (ldlsm) THEN
179  !
180  DO ji = 1,12
181  IF (klsmin(jl,ji).NE.klsmout(jl)) zlsmp(ji) = 0.
182  ENDDO
183  !
184  zlsmv(1) = zlsmp(1) + zlsmp(2)
185  zlsmv(2) = zlsmp(3) + zlsmp(4) + zlsmp(5) + zlsmp(6)
186  zlsmv(3) = zlsmp(7) + zlsmp(8) + zlsmp(9) + zlsmp(10)
187  zlsmv(4) = zlsmp(11) + zlsmp(12)
188  !
189  zlsmv(:) = min(zlsmv(:),1.)
190  zlsmtot = min(sum(zlsmv),1.)
191  !
192  IF (zlsmv(1) < 1.e-3) zlsmp(1:2) = 1.
193  IF (zlsmv(2) < 1.e-3) zlsmp(3:6) = 1.
194  IF (zlsmv(3) < 1.e-3) zlsmp(7:10) = 1.
195  IF (zlsmv(4) < 1.e-3) zlsmp(11:12) = 1.
196  IF (zlsmtot < 1.e-3) zlsmv(:) = 1.
197  !
198  ENDIF
199 !
200 !* 3.3 Weight of points
201 !
202  zp(1) = pla(jl,1) - pla(jl,2)
203  zp(2) = pla(jl,1) - pla(jl,3)
204  zp(3) = pla(jl,2) - pla(jl,3)
205  !
206  zt = pola(jl) - pla(jl,1)
207  zwv(1) = zlsmv(1) * (1.+zlsmv(2)*zt/zp(1)) * (1.+zlsmv(3)*zt/zp(2)) * (1.+zlsmv(4)*zt/(pla(jl,1)-pla(jl,4)))
208  zt = pola(jl) - pla(jl,2)
209  zwv(2) = zlsmv(2) * (1.-zlsmv(1)*zt/zp(1)) * (1.+zlsmv(3)*zt/zp(3)) * (1.+zlsmv(4)*zt/(pla(jl,2)-pla(jl,4)))
210  zt = pola(jl) - pla(jl,3)
211  zwv(3) = zlsmv(3) * (1.-zlsmv(1)*zt/zp(2)) * (1.-zlsmv(2)*zt/zp(3)) * (1.+zlsmv(4)*zt/(pla(jl,3)-pla(jl,4)))
212  zwv(4) = 1. - zwv(1) - zwv(2) - zwv(3)
213 !
214  ! 3.3.1 northern
215  zwp(1) = zlsmp(1) * (1.+zlsmp(2) *(polo(jl) -plop(jl,1))/(plop(jl,1) -plop(jl,2)))
216  zwp(2) = 1. - zwp(1)
217  ! 3.3.4. southern
218  zwp(11) = zlsmp(11)* (1.+zlsmp(12)*(polo(jl)-plop(jl,11))/(plop(jl,11)-plop(jl,12)))
219  zwp(12) = 1. - zwp(11)
220 
221  ! 3.3.2. north
222  zp(1) = plop(jl,3) - plop(jl,4)
223  zp(2) = plop(jl,3) - plop(jl,5)
224  zp(3) = plop(jl,4) - plop(jl,5)
225  !
226  zt = polo(jl) - plop(jl,3)
227  zwp(3) = zlsmp(3) * (1.+zlsmp(4)*zt/zp(1)) * (1.+zlsmp(5)*zt/zp(2)) * (1.+zlsmp(6)*zt/(plop(jl,3)-plop(jl,6)))
228  zt = polo(jl) - plop(jl,4)
229  zwp(4) = zlsmp(4) * (1.-zlsmp(3)*zt/zp(1)) * (1.+zlsmp(5)*zt/zp(3)) * (1.+zlsmp(6)*zt/(plop(jl,4)-plop(jl,6)))
230  zt = polo(jl) - plop(jl,5)
231  zwp(5) = zlsmp(5) * (1.-zlsmp(3)*zt/zp(2)) * (1.-zlsmp(4)*zt/zp(3)) * (1.+zlsmp(6)*zt/(plop(jl,5)-plop(jl,6)))
232  zwp(6) = 1. - zwp(3) - zwp(4) - zwp(5)
233 !
234  ! 3.3.3. south
235  zp(1) = plop(jl,7) - plop(jl,8)
236  zp(2) = plop(jl,7) - plop(jl,9)
237  zp(3) = plop(jl,8) - plop(jl,9)
238  !
239  zt = polo(jl) - plop(jl,7)
240  zwp(7) = zlsmp(7) * (1.+zlsmp(8)*zt/zp(1)) * (1.+zlsmp(9)*zt/zp(2)) * (1.+zlsmp(10)*zt/(plop(jl,7)-plop(jl,10)))
241  zt = polo(jl) - plop(jl,8)
242  zwp(8) = zlsmp(8) * (1.-zlsmp(7)*zt/zp(1)) * (1.+zlsmp(9)*zt/zp(3)) * (1.+zlsmp(10)*zt/(plop(jl,8)-plop(jl,10)))
243  zt = polo(jl) - plop(jl,9)
244  zwp(9) = zlsmp(9) * (1.-zlsmp(7)*zt/zp(2)) * (1.-zlsmp(8)*zt/zp(3)) * (1.+zlsmp(10)*zt/(plop(jl,9)-plop(jl,10)))
245  zwp(10) = 1. - zwp(7) - zwp(8) - zwp(9)
246 !
247 ! In order to exclude undef values from computation of PAROUT,
248 ! weights w2, w6, w10, w12 and wss which can be numerically very low
249 ! because they are residual, are set to 0
250 !
251  IF (abs(zwp(2)) < 1.e-10) zwp(2) =0.
252  IF (abs(zwp(6)) < 1.e-10) zwp(6) =0.
253  IF (abs(zwp(10))< 1.e-10) zwp(10)=0.
254  IF (abs(zwp(12))< 1.e-10) zwp(12)=0.
255  IF (abs(zwv(4)) < 1.e-10) zwv(4) =0.
256 !
257  ! 3.3.5. longitude weight x latitude weight
258  zwp(1:2) = zwp(1:2) * zwv(1)
259  zwp(3:6) = zwp(3:6) * zwv(2)
260  zwp(7:10) = zwp(7:10) * zwv(3)
261  zwp(11:12) = zwp(11:12) * zwv(4)
262  WHERE (zwp(:)<1.e-4) zwp(:) = 0.
263  zwp(:) = zwp(:) / sum(zwp)
264 !
265  parout(jl) = 0.
266  DO ji = 1,12
267  parout(jl) = parout(jl) + zwp(ji) * parin(jl,ji)
268  ENDDO
269 !
270 ! For surface fields, the interpoalted value is bounded
271 ! by the min max values of the initial field
272 
273  IF (PRESENT(kmaskin)) THEN
274 
275  zmin=xundef
276  zmax=xundef
277 
278  DO jl2=1,12
279  IF (parin(jl,jl2)==xundef) cycle
280 
281  IF ((zmax==xundef)) THEN
282  zmax=parin(jl,jl2)
283  zmin=parin(jl,jl2)
284  ELSE
285  zmax=max(zmax,parin(jl,jl2))
286  zmin=min(zmin,parin(jl,jl2))
287  ENDIF
288 
289  END DO
290 
291  parout(jl) = max(min(parout(jl),zmax),zmin)
292 
293  ENDIF
294 
295 END DO
296 !$OMP END DO
297 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_2',1,zhook_handle_omp)
298 !$OMP END PARALLEL
299 !
300 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_3',0,zhook_handle)
301 WHERE(abs(parout-xundef)<1.e-6) parout=xundef
302 IF (lhook) CALL dr_hook('HORIBL_SURF_VALUE_3',1,zhook_handle)
303 !
304 !------------------------------------------------------------------------------
305 !
306 !
307 END SUBROUTINE horibl_surf_value
real, parameter xundef
integer, parameter jprb
Definition: parkind1.F90:32
intent(out) overrides sub arrays one Sort by the least significant key first sum(iindex(1:n))
logical lhook
Definition: yomhook.F90:15
subroutine horibl_surf_value(KILEN, KOLEN, PAROUT, OINTERP, PARIN, KLSMIN, POLO, POLA, PLA, PLOP, KMASKIN, KLSMOUT)