SURFEX v8.1
General documentation of Surfex
horibl_surf_init.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_init(PILA1,PILO1,PILA2,PILO2,KINLA,KINLO,KOLEN,&
7  PXOUT,PYOUT,OINTERP,OGLOBLON,OGLOBN,OGLOBS,&
8  KO,KINLO_OUT,POLA,POLO,PILO1_OUT,&
9  PILO2_OUT,PLA,PILATARRAY )
10 ! ###########################################################################
11 !
12 !!**** *HORIBL_SURF_INIT* - horitontal bilinear interpolation
13 !!
14 !! PURPOSE
15 !! -------
16 !!
17 !! Interpolates a field, supports masks.
18 !!
19 !! METHOD
20 !! ------
21 !!
22 !! This routine performs a bilinear interpolation based on the 12 surrounding
23 !! points. It begins with an interpolation along the latitudes (with third order
24 !! polynoms interpolation with 4 points and linear interpolation for 2 points)
25 !! and then a second along the longitude (third order polynoms interpolation).
26 !! Two interpolations are performed : first along the parallels then between the
27 !! four resulting points.
28 !!
29 !! The disposition of the points is the following :
30 !!
31 !!
32 !! N 1 2
33 !!
34 !! ^ 3 4 5 6
35 !! | x
36 !! | 7 8 9 10
37 !! |
38 !! 11 12
39 !! S
40 !! W ---------------> E
41 !!
42 !! Note : the name 'south', 'north', may not be exact if the last data point is
43 !! to the south of first (delta latitude < 0). This does not affect computations.
44 !!
45 !! The formula used to compute the weight is :
46 !! (Lon - Lon.i) . (Lon - Lon.i) . (Lon - Lon.i)
47 !! Wi = ---------------------------------------------------
48 !! (Lon.i - Lon.j) . (Lon.i - Lon.k) . (Lon.i - Lon.l)
49 !! Where j,k,l are the other points of the line.
50 !!
51 !! When masks are used, points with different types than the output points are
52 !! not taken in account (in the formula, the corresponding coefficient is set
53 !! to 1). If no points of the same nature are available, the interpolation is
54 !! performed anyway with the 12 points. It is the task of the calling program
55 !! to react to this situation.
56 !!
57 !! When the inputs parameters define a circular map (or global), the inputs data
58 !! are extended. The value of the parameter ODVECT is used to know if the datas
59 !! are vectorial or scalar (this affects the sign of extended values).
60 !!
61 !! EXTERNAL
62 !! --------
63 !!
64 !! subroutine FMLOOK_ll : to retrieve the logical unit number of the listing file
65 !!
66 !! IMPLICIT ARGUMENTS
67 !! ------------------
68 !!
69 !! REFERENCE
70 !! ---------
71 !!
72 !! This routine is based on the one used by the software FULL-POS from Meteo France.
73 !! More informations may be found in 'Book 1'
74 !!
75 !! AUTHOR
76 !! ------
77 !!
78 !! J.Pettre & V.Bousquet
79 !!
80 !! MODIFICATKONS
81 !! -------------
82 !!
83 !! Original 07/01/1999
84 !! 21/04/1999 (V. Masson) set correct prefixes and bug in
85 !! a logical definition
86 !! 21/04/1999 (V. Masson) bug in north and south poles
87 !! extension for input map land-sea mask
88 !! 27/05/1999 (V. Masson) bug in 'grib south pole'
89 !! extrapolation (number of point per parallel)
90 !! 27/05/1999 (V. Masson) bug in 'grib pole' extrapolation
91 !! extra latitudes are now computed symetrically
92 !! to the poles.
93 !! 17/03/2010 (P. LeMoigne) bug in weights computations
94 !! 16/06/2010 (G. Tanguy) bug in 'grib north pole"
95 !! extrapolation (tabular ZARIN not totaly filled)
96 !!
97 !------------------------------------------------------------------------------
98 !
99 !
100 !* 0. DECLARATKONS
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 REAL, INTENT(IN) :: PILA1 ! Lat. (y) of first input point KDGSA
115 REAL, INTENT(IN) :: PILO1 ! Lon. (x) of first input point
116 REAL, INTENT(IN) :: PILA2 ! Lat. (y) of last input point KDGEN
117 REAL, INTENT(IN) :: PILO2 ! Lon. (x) of last input point
118 INTEGER, INTENT(IN) :: KINLA ! Number of parallels
119 INTEGER, DIMENSION(:), INTENT(IN) :: KINLO ! Number of point along a parallel
120 INTEGER, INTENT(IN) :: KOLEN ! size of output array
121 REAL, DIMENSION(:), INTENT(IN) :: PXOUT ! X (lon.) of output points
122 REAL, DIMENSION(:), INTENT(IN) :: PYOUT ! Y (lat.) of output points
123 LOGICAL, DIMENSION(:), INTENT(IN) :: OINTERP ! .true. where physical value is needed
124 !
125 LOGICAL, INTENT(OUT) :: OGLOBLON ! True if the map is circular
126 LOGICAL, INTENT(OUT) :: OGLOBN ! True if the map has the north pole
127 LOGICAL, INTENT(OUT) :: OGLOBS ! True if the map has the south pole
128  ! Number of the surrounding latitudes
129 INTEGER, DIMENSION(:,:), INTENT(OUT) :: KO
130 INTEGER, DIMENSION(:), INTENT(OUT) :: KINLO_OUT ! Extended KINLO
131 REAL, INTENT(OUT) :: PILO1_OUT ! Longitude of the first data point
132 REAL, INTENT(OUT) :: PILO2_OUT ! Longitude of the last data point
133 ! Variables used to perform the interpolation
134 REAL, DIMENSION(:), INTENT(OUT) :: POLA ! Latitude of the output point
135 REAL, DIMENSION(:), INTENT(OUT) :: POLO ! Longitude of the output point
136  ! Latitudes and longitudes of the surrounding points
137 REAL, DIMENSION(:,:), INTENT(OUT) :: PLA
138 REAL, DIMENSION(:), INTENT(IN), OPTIONAL :: PILATARRAY! latitudes array
139 !
140 !* 0.2. Declaration of local variables
141 !
142 REAL, DIMENSION(:), ALLOCATABLE :: ZIDLAT ! Deltai latitude
143 REAL :: ZIDLA ! Delta latitude
144 REAL :: ZSOUTHPOLE! south pole latitude (-90 or 90)
145 REAL :: ZNORTHPOLE! north pole latitude ( 90 or -90)
146 !
147 ! Variables implied in the extension procedure
148 !
149 INTEGER :: IOFFSET ! Offset in map
150 INTEGER :: IINLA ! Number of parallel
151  ! Loop counters
152 INTEGER :: JOPOS ! Output position
153 INTEGER :: JL, JL2 ! Dummy counter
154 !
155 REAL(KIND=JPRB) :: ZHOOK_HANDLE
156 !------------------------------------------------------------------------------
157 !
158 !* 1. DETERMINATKON of the latitude of the poles (depending of the latitude
159 ! ------------- of the first data point)
160 !
161 IF (lhook) CALL dr_hook('HORIBL_SURF_INIT',0,zhook_handle)
162 !
163 IF (pila1>0.) THEN
164  zsouthpole= 90.
165  znorthpole=-90.
166 ELSE
167  zsouthpole=-90.
168  znorthpole= 90.
169 END IF
170 !
171 !------------------------------------------------------------------------------
172 !
173 !* 2. EXTEND DATA GRID
174 ! ----------------
175 !
176 !* 2.1 Alias input data
177 !
178 pilo1_out = pilo1
179 pilo2_out = pilo2
180 !
181 !* 2.2 Center input domain in order to have Lo1 < Lo 2
182 !
183 IF (pilo2_out < 0.) pilo2_out = pilo2_out + 360.
184 IF (pilo1_out < 0.) pilo1_out = pilo1_out + 360.
185 IF (pilo2_out < pilo1_out) pilo1_out = pilo1_out - 360.
186 !
187 !* 2.3 Extend one point (needed for reduced grids)
188 !
189 ! Longitude coordinate of points are found by :
190 ! i
191 ! Lon(i) = Lon1 + ------------- . (Lon2 - Lon1)
192 ! Npts(Lat)-1
193 ! Where i goes from 0 to Npts(Lat)-1. The result of this is that the last point of
194 ! each parallel is located at Lon2. This is not the case for reduced grid where the
195 ! position of the last point depends upon the number of points of the parallel. For
196 ! reduced grid, the right formula to use is the following :
197 ! i
198 ! Lon(i) = Lon1 + ----------- . (Lon2' - Lon1)
199 ! Npts(Lat)
200 ! Where Lon2' = Lon1 + 2.PI.
201 !
202 ! Lon2 - Lon1
203 ! This can be generalized with Lon2' = Lon2 + -------------
204 ! Nptsmax - 1
205 !
206 jopos = maxval(kinlo(1:kinla))
207 pilo2_out = pilo1_out + (pilo2_out - pilo1_out) * jopos / (jopos - 1.)
208 !
209 !* 2.4 Test if the input is global or partially global
210 !
211 ! Note that we must have a global map to make extension around the poles
212 oglobn = .false.
213 oglobs = .false.
214 ogloblon = .false.
215 IF (pilo2_out-360.>pilo1_out-1.e-3) ogloblon = .true.
216 zidla = (pila2 - pila1) / (kinla - 1)
217 IF (PRESENT(pilatarray)) THEN
218  ALLOCATE(zidlat(kinla+1))
219  DO jl=2,kinla
220  zidlat(jl) = pilatarray(jl)-pilatarray(jl-1)
221  END DO
222  zidlat(1)=zidlat(2)
223  zidlat(kinla+1) = zidlat(kinla)
224 ENDIF
225 IF ((pila1-zidla>= 90.) .OR. (pila1-zidla<=-90.)) oglobs=ogloblon
226 IF ((pila2+zidla>= 90.) .OR. (pila2+zidla<=-90.)) oglobn=ogloblon
227 ! Aladin case (input PILA2, PILO2 are in meters) no extension
228 IF ( pila2 > 100. ) THEN
229  oglobn = .false.
230  oglobs = .false.
231  ogloblon = .false.
232 END IF
233 !
234 !
235 !* 2.7 Compute the resulting parameters of the map
236 !
237 iinla = kinla
238 IF (oglobs) iinla = iinla + 2
239 IF (oglobn) iinla = iinla + 2
240 !
241 ioffset = 0
242 IF (oglobs) THEN
243  kinlo_out(ioffset+1) = kinlo(2)
244  kinlo_out(ioffset+2) = kinlo(1)
245  ioffset = ioffset + 2
246 END IF
247 kinlo_out(ioffset+1:ioffset+kinla) = kinlo(1:kinla)
248 ioffset = ioffset + kinla
249 IF (oglobn) THEN
250  kinlo_out(ioffset+1) = kinlo(kinla)
251  kinlo_out(ioffset+2) = kinlo(kinla-1)
252  ioffset = ioffset + 2
253 END IF
254 !
255 !------------------------------------------------------------------------------
256 !
257 !* 3. LOOP OVER ALL THE POINTS OF THE OUTPUT GRID
258 ! -------------------------------------------
259 !
260 pola(:) = 0.
261 polo(:) = 0.
262 !
263 DO jl = 1, kolen
264  !
265  IF (.NOT. ointerp(jl)) cycle
266  !
267  pola(jl) = pyout(jl)
268  !
269  polo(jl) = pxout(jl)
270  IF (polo(jl) < pilo1_out) polo(jl) = polo(jl) + 360.
271  IF (polo(jl) > pilo2_out) polo(jl) = polo(jl) - 360.
272  !
273  ! 3.1.1. find positions of latitudes
274  IF (PRESENT(pilatarray)) THEN
275  !
276  DO jl2 = 1,kinla
277  IF((pola(jl)>=pilatarray(jl2)-zidlat(jl2)/2..AND.pola(jl)<pilatarray(jl2)+zidlat(jl2+1)/2.).OR.&
278  (pola(jl)<=pilatarray(jl2)-zidlat(jl2)/2..AND.pola(jl)>pilatarray(jl2)+zidlat(jl2+1)/2.)) THEN
279  ko(jl,3) = jl2
280  EXIT
281  ELSEIF (pola(jl)>maxval(pilatarray(:))) THEN
282  ko(jl,3) = maxloc(pilatarray,1)
283  ELSEIF (pola(jl)<minval(pilatarray(:))) THEN
284  ko(jl,3) = minloc(pilatarray,1)
285  ENDIF
286  ENDDO
287  pla(jl,3) = pilatarray(ko(jl,3))
288  !
289  ELSE
290  !
291  ko(jl,3) = nint( (pola(jl)-pila1)/zidla - 0.5 ) ! because of the zero
292  IF ( ko(jl,3)<-1) CALL abor1_sfx('HORIBLE_SURF_INIT: INPUT DOMAIN SMALLER THAN OUTPUT ONE - LATITUDE')
293  !
294  pla(jl,3) = pila1 + ko(jl,3) * zidla
295  !
296  ko(jl,3) = ko(jl,3) + 1
297  !
298  ENDIF
299  !
300  IF (PRESENT(pilatarray)) THEN
301  !
302  IF (ko(jl,3)==1) THEN
303  pla(jl,4) = pilatarray(1) - zidlat(1)
304  ELSE
305  pla(jl,4) = pilatarray(ko(jl,3)-1)
306  ENDIF
307  IF (ko(jl,3)>=kinla) THEN
308  pla(jl,2) = pilatarray(kinla) + zidlat(kinla)
309  ELSE
310  pla(jl,2) = pilatarray(ko(jl,3)+1)
311  ENDIF
312  IF (ko(jl,3)>=kinla) THEN
313  pla(jl,1) = pilatarray(kinla) + 2.*zidlat(kinla)
314  ELSE
315  pla(jl,1) = pilatarray(ko(jl,3)+2)
316  ENDIF
317  !
318  ELSE
319  !
320  pla(jl,1) = pla(jl,3) + 2*zidla
321  pla(jl,2) = pla(jl,3) + zidla
322  pla(jl,4) = pla(jl,3) - zidla
323  !
324  ENDIF
325  !
326  IF (oglobs) ko(jl,3) = ko(jl,3) + 2
327  !
328  ko(jl,1) = ko(jl,3) + 2
329  ko(jl,2) = ko(jl,3) + 1
330  ko(jl,4) = ko(jl,3) - 1
331  !
332  IF (.NOT.oglobs) THEN
333  ko(jl,1:2) = min(ko(jl,1:2),iinla)
334  ko(jl,3:4) = max(ko(jl,3:4),1)
335  ENDIF
336  !
337  ! extra latitudes are computed symetrically compared to the poles
338  !
339  IF (oglobs) THEN
340  IF (ko(jl,3)==2) THEN
341  pla(jl,4) = 2. * zsouthpole - pla(jl,1)
342  pla(jl,3) = 2. * zsouthpole - pla(jl,2)
343  ELSEIF (ko(jl,3)==3) THEN
344  pla(jl,4) = 2. * zsouthpole - pla(jl,3)
345  END IF
346  ENDIF
347  IF (oglobn) THEN
348  IF (ko(jl,3)==iinla-2) THEN
349  pla(jl,1) = 2. * znorthpole - pla(jl,4)
350  pla(jl,2) = 2. * znorthpole - pla(jl,3)
351  ELSEIF (ko(jl,3)==iinla-3) THEN
352  pla(jl,1) = 2. * znorthpole - pla(jl,2)
353  END IF
354  ENDIF
355  !
356  IF ((ko(jl,4)<1).OR.any((ko(jl,:)>iinla))) THEN
357  CALL abor1_sfx('HORIBLE_SURF_INIT: INPUT DOMAIN SMALLER THAN OUTPUT ONE - LATITUDE')
358  END IF
359  !
360 END DO
361 !
362 IF (lhook) CALL dr_hook('HORIBL_SURF_INIT',1,zhook_handle)
363 !
364 !------------------------------------------------------------------------------
365 !
366 !
367 END SUBROUTINE horibl_surf_init
subroutine abor1_sfx(YTEXT)
Definition: abor1_sfx.F90:7
real, parameter xundef
integer, parameter jprb
Definition: parkind1.F90:32
logical lhook
Definition: yomhook.F90:15
subroutine horibl_surf_init(PILA1, PILO1, PILA2, PILO2, KINLA, KINLO, KOLEN, PXOUT, PYOUT, OINTERP, OGLOBLON, OGLOBN, OGLOBS, KO, KINLO_OUT, POLA, POLO, PILO1_OUT, PILO2_OUT, PLA, PILATARRAY)
static ll_t maxloc
Definition: getcurheap.c:48