SURFEX v8.1
General documentation of Surfex
fapula.F90
Go to the documentation of this file.
1 ! Oct-2012 P. Marguinaud 64b LFI
2 ! Jan-2011 P. Marguinaud Thread-safe FA
3 SUBROUTINE fapula_fort &
4 & (fa, krep, krang, pspec, kpulap)
5 USE fa_mod, ONLY : fa_com, jpniil
6 USE parkind1, ONLY : jprb
7 USE yomhook , ONLY : lhook, dr_hook
9 IMPLICIT NONE
10 !****
11 ! Sous-programme INTERNE du logiciel de Fichiers ARPEGE:
12 ! calcul de la PUissance de LAplacien "optimale" pour aplatir
13 ! le spectre hors de la sous-troncature.
14 !
15 !**
16 ! Arguments : KREP (Sortie) ==> Code-reponse du sous-programme;
17 ! KRANG (Entree) ==> Rang de l'unite logique;
18 ! ( Tableau ) PSPEC (Entree) ==> Champ en coef. spectraux en entree;
19 ! KPULAP (Sortie) ==> Puissance de laplacien calculee.
20 !*
21 !
22 ! Creation
23 ! --------
24 ! Avril 1999, D. Paradis, SCEM/TTI/DEV:
25 ! Ce ss-programme est derive de la routine CALCOP du logiciel GRIBEX
26 ! du CEPMMT. Il retourne la puissance de laplacien (exprimee en un
27 ! nombre entier de milliemes) qui aplatit le mieux le spectre des
28 ! coefficients spectraux (hors sous-troncature).
29 ! Cette puissance de laplacien, P, sera l'exposant du facteur
30 ! .(n*(n+1))**P pour les champs ARPEGE ou n est le nombre d'onde total
31 ! .(n**2+m**2)**P pour les champs ALADIN ou n est le nombre d'onde meridien
32 ! et m est le nombre d'onde zonal
33 ! Ce facteur sera applique aux coefficients spectraux hors sous-troncature
34 ! pour en reduire l'amplitude avant le codage GRIB.
35 !
36 !
37 ! Method.
38 ! -------
39 !
40 ! For ARPEGE case, consider F(n,m) = (n*(n+1))**(-P) * G(n,m),
41 ! where F(n,m) is the original spectral field and n the total wavenumber.
42 ! For ALADIN case (LAM), consider F(n,m) = (n**2+m**2)**(-P) * G(n,m),
43 ! where F(n,m) is the original spectral field, n the meridian
44 ! wavenumber and m the zonal wavenumber.
45 ! The aim is to minimize G in a 1 norm with respect to P. This can only
46 ! partially be achieved.
47 !
48 ! 1) For ARPEGE case, what we do is to compute H(n), where
49 ! H(n) = max(F(n,m)) with respect to m.
50 !
51 ! We then perform a least square fit for the equation
52 ! log(H(n)) = beta0+beta1*log(n*(n+1)).
53 !
54 ! To ensure a better fit for the lower end of the spectrum, we
55 ! apply an (arbitrary) weighting function before fitting
56 ! W(n) = 1.0 / (n-ISTRON+1)
57 !
58 ! 2) For ALADIN case, what we do is to compute H(in), where
59 ! H(in) = max(F(n,m)) where n and m verify: k = n**2 + m**2
60 ! and "in" is the rank of k among all the reached values by k:
61 ! we are only interested in k values which verify
62 ! k = n**2 + m**2, with (n,m) belonging to spectrum without
63 ! the non-compacted sub-truncation area. We call inmax the number
64 ! of these k values. "in" belongs to interval 1,inmax.
65 !
66 ! We then perform a least square fit for the equation
67 ! log(H(in)) = beta0+beta1*log(k).
68 !
69 ! To ensure a better fit for the lower end of the spectrum, we
70 ! apply an (arbitrary) weighting function before fitting
71 ! W(in) = 1.0 / in
72 !
73 ! Reference.
74 ! ----------
75 !
76 ! Seber, G.A.F. (1979). Linear Regression Analyses.
77 ! John Wiley and Sons
78 !
79 ! ECMWF Research Department documentation of the IFS
80 !
81 !
82 ! Modifications
83 ! -------------
84 !
85 !
86 !
87 ! Subroutine arguments
88 !
89 TYPE(fa_com) :: FA
90 INTEGER (KIND=JPLIKB) KREP, KRANG, KPULAP
91 !
92 REAL (KIND=JPDBLR) PSPEC(*)
93 !
94 ! Local arguments
95 !
96 INTEGER (KIND=JPLIKB) IRANGC, ITRONC, IMTRONC, INMAX, INMIN
97 INTEGER (KIND=JPLIKB) IKMAX, IDEB, IFIN, JN, JM, JK, IK, IN, IM
98 INTEGER (KIND=JPLIKB) IMLIM, JIND, IOFF, INUMER
99 INTEGER (KIND=JPLIKB) INIMES, ISTRON
100 INTEGER (KIND=JPLIKB), DIMENSION(:), ALLOCATABLE :: ITAB1
101 INTEGER (KIND=JPLIKB), DIMENSION(:), ALLOCATABLE :: ITAB2
102 !
103 REAL (KIND=JPDBLR) ZEPS, ZZ, ZXMW, ZYMW, ZWSUM, ZX, ZY
104 REAL (KIND=JPDBLR) ZP, ZBETA1, ZSUM1, ZSUM2
105 REAL (KIND=JPDBLR), DIMENSION(:), ALLOCATABLE :: ZW, ZNORM
106 !
107 LOGICAL LLMLAM
108 !
109 CHARACTER(LEN=FA%JPLMES) CLMESS
110 CHARACTER(LEN=FA%JPLSPX) CLNSPR
111 LOGICAL LLFATA
112 
113 !**
114 ! 1. - CONTROLES DES PARAMETRES D'APPEL, INITIALISATIONS.
115 !-----------------------------------------------------------------------
116 !
117 REAL(KIND=JPRB) :: ZHOOK_HANDLE
118 IF (lhook) CALL dr_hook('FAPULA_MT',0,zhook_handle)
119 IF (krang.LE.0.OR.krang.GT.fa%JPNXFA) THEN
120  krep=-66
121  GOTO 1001
122 ENDIF
123 !
124 istron=fa%FICHIER(krang)%NSTROF
125 irangc=fa%FICHIER(krang)%NUCADR
126 itronc=fa%CADRE(irangc)%MTRONC
127 llmlam=fa%CADRE(irangc)%LIMLAM
128 !
129 IF (llmlam) imtronc=fa%CADRE(irangc)%NOZPAR(2)
130 IF (itronc.LE.istron) THEN
131  krep=-88
132  GOTO 1001
133 ELSEIF (llmlam.AND.imtronc.LE.istron) THEN
134  krep=-88
135  GOTO 1001
136 ELSEIF (llmlam.AND.(imtronc.GT.3*itronc.OR. &
137 & itronc.GT.3*imtronc)) THEN
138 ! Il s'agit d'un garde-fou, modifiable (ne pas oublier FARCIS et FACSIM)
139  krep=-114
140  GOTO 1001
141 ELSE
142  krep=0
143 ENDIF
144 !
145 zeps = 1.0e-15_jpdblr
146 !
147 IF (llmlam) THEN
148  ikmax = itronc*itronc + imtronc*imtronc
149 !
150 ! Pour le cas ALADIN, il faut creer les tableaux ITAB1 et ITAB2 :
151 ! ITAB1(JK) = 0 sauf pour JK tel qu'il existe (n,m) appartenant au spectre
152 ! hors de la sous-troncature non-compactee verifiant JK = n**2 + m**2:
153 ! on a alors ITAB1(JK) = 1
154 ! ITAB2 regroupe toutes les valeurs de JK precedentes.
155 !
156 ! ITAB1 est necessaire a la creation de ITAB2 et ITAB2 permet de boucler
157 ! directement sur les valeurs de JK utiles, et de dimensionner au plus
158 ! juste les tableaux ZW et ZNORM.
159 !
160  ALLOCATE ( itab1(ikmax) )
161  itab1 = 0
162 !DP#ifdef SCALAR
163  ALLOCATE ( itab2((itronc-1)*(imtronc-1)) )
164 !DP#else
165 !DP ALLOCATE ( ITAB2(0:(ITRONC-1)*(IMTRONC-1)) )
166 !DP ITAB2 = 0
167 !DP#endif
168  DO jm = 1,imtronc
169  imlim=istron-jm
170  ideb=max(fa%CADRE(irangc)%NOMPAR(2*jm+3)+4*(1+imlim), &
171 & fa%CADRE(irangc)%NOMPAR(2*jm+3)+4)
172  ifin=fa%CADRE(irangc)%NOMPAR(2*jm+4)
173  DO jind=ideb,ifin
174  ioff=jind-fa%CADRE(irangc)%NOMPAR(2*jm+3)
175  jn=ioff/4
176  jk=(jn**2 + jm**2)
177 ! On conserve les valeurs de JK atteintes
178  itab1(jk) = 1
179  ENDDO
180  ENDDO
181 ! On construit le tableau ITAB2 des valeurs de JK atteintes
182  ik = 0
183  DO jk = 1,ikmax
184 !DP#ifdef SCALAR
185  IF (itab1(jk).GT.0) THEN
186  ik = ik+1
187  itab2(ik) = jk
188  itab1(jk) = ik
189  ENDIF
190 !DP#else
191 !DP IK = IK + ITAB1(JK)
192 !DP ITAB2(IK) = ITAB2(IK) + JK*ITAB1(JK)
193 !DP ITAB1(JK) = IK
194 !DP#endif
195  ENDDO
196  inmin = 1
197  inmax = ik
198 !
199 ! CAS ARPEGE
200 !
201 ELSE
202  inmin = istron + 1
203  inmax = itronc
204 ENDIF
205 !
206 !**
207 ! 2. - CALCUL DES NORMES ET DES POIDS
208 !-----------------------------------------------------------------------
209 !
210 ALLOCATE ( zw(0:inmax), znorm(0:inmax) )
211 znorm = 0.0_jpdblr
212 !
213 IF (llmlam) THEN
214 !
215 ! CAS ALADIN
216 !
217  DO jm = 1,imtronc
218  imlim=istron-jm
219  ideb=max(fa%CADRE(irangc)%NOMPAR(2*jm+3)+4*(1+imlim), &
220 & fa%CADRE(irangc)%NOMPAR(2*jm+3)+4)
221  ifin=fa%CADRE(irangc)%NOMPAR(2*jm+4)
222  DO jind=ideb,ifin
223  ioff=jind-fa%CADRE(irangc)%NOMPAR(2*jm+3)
224  jn=ioff/4
225  jk=(jn**2 + jm**2)
226  znorm(itab1(jk)) = max(znorm(itab1(jk)), abs(pspec(jind)))
227  ENDDO
228  ENDDO
229  DEALLOCATE ( itab1 )
230 !
231 ! CAS ARPEGE
232 !
233 ELSE
234 !
235  DO jn=0,inmax
236  DO jm=-jn,jn
237  im=abs(jm)
238  IF (jm < 0) THEN
239  jind=fa%CADRE(irangc)%NDIM0GG(im)+(jn-im)*2 +1
240  ELSE
241  jind=fa%CADRE(irangc)%NDIM0GG(im)+(jn-im)*2
242  ENDIF
243  znorm(jn) = max(znorm(jn), abs(pspec(jind)))
244  ENDDO
245  ENDDO
246 !
247 ENDIF
248 !
249 zz = REAL(inmax-inmin+1,jpdblr)
250 DO in = inmin, inmax
251  zw(in) = zz / REAL(in-inmin+1,jpdblr)
252 !
253 ! Ensure the norms have a value which is not too small in case of
254 ! problems with math functions (e.g. LOG).
255 !
256  IF(znorm(in).LT.zeps) THEN
257  znorm(in) = zeps
258  zw(in) = 100._jpdblr*zeps
259  ENDIF
260 ENDDO
261 !*
262 ! 3. - AJUSTEMENT PAR LES MOINDRES CARRES POUR DETERMINER LA PENTE
263 ! (ZBETA1).
264 !-----------------------------------------------------------------------
265 !
266 !
267 !
268 zxmw = 0.0_jpdblr
269 zymw = 0.0_jpdblr
270 zwsum = 0.0_jpdblr
271 !
272 ! Sum the weighted X and Ys.
273 DO jn = inmin, inmax
274  IF (llmlam) THEN
275  zx = log(REAL(ITAB2(JN),JPDBLR))
276  ELSE
277  zx = log(REAL(JN*(JN+1),JPDBLR))
278  ENDIF
279  zy = log(znorm(jn))
280  zxmw = zxmw+zx*zw(jn)
281  zymw = zymw+zy*zw(jn)
282  zwsum = zwsum+zw(jn)
283 ENDDO
284 !
285 ! Form mean weighted X and Y.
286 zxmw = zxmw / zwsum
287 zymw = zymw / zwsum
288 zsum1 = 0.0_jpdblr
289 zsum2 = 0.0_jpdblr
290 !
291 ! Perform a least square fit for the equation
292 DO jn = inmin, inmax
293  IF (llmlam) THEN
294  zx = log(REAL(ITAB2(JN),JPDBLR))
295  ELSE
296  zx = log(REAL(JN*(JN+1),JPDBLR))
297  ENDIF
298  zy = log(znorm(jn))
299  zsum1 = zsum1+zw(jn)*(zy-zymw)*(zx-zxmw)
300  zsum2 = zsum2+zw(jn)*(zx-zxmw)**2
301 ENDDO
302 !
303 !
304 DEALLOCATE ( zw, znorm )
305 IF (llmlam) DEALLOCATE ( itab2 )
306 !
307 ! On peut en tirer la pente recherchee:
308 zbeta1 = zsum1 / zsum2
309 !
310 ! Et finalement, la puissance de laplacien, arrondie en un
311 ! nombre entier de milliemes.
312 zp = -zbeta1
313 zp = max(-9.999_jpdblr, min(9.999_jpdblr, zp))
314 kpulap = nint( zp * 1000.0_jpdblr, kind=jplikb )
315 !**
316 ! 10. - PHASE TERMINALE : MESSAGERIE EVENTUELLE,
317 ! VIA LE SOUS-PROGRAMME "FAIPAR" .
318 !-----------------------------------------------------------------------
319 !
320 1001 CONTINUE
321 llfata=llmoer(krep,krang)
322 !
323 IF (fa%LFAMOP.OR.llfata) THEN
324  inimes=2
325  clnspr='FAPULA'
326  inumer=jpniil
327  WRITE (unit=clmess,fmt='(''KREP='',I4,'', KRANG='',I4, &
328 & '', ISTRON='',I4,'', KPULAP='',I6)') &
329 & krep,krang,istron,kpulap
330  CALL faipar_fort &
331 & (fa, inumer,inimes,krep,.false.,clmess, &
332 & clnspr,clnspr,.false.)
333 ENDIF
334 !
335 IF (lhook) CALL dr_hook('FAPULA_MT',1,zhook_handle)
336 
337 CONTAINS
338 
339 #include "facom2.llmoer.h"
340 
341 END SUBROUTINE
342 
343 !INTF KREP OUT
344 !INTF KRANG IN
345 !INTF PSPEC IN DIMS=*
346 !INTF KPULAP OUT
347 
integer, parameter jplikb
Definition: fa_mod.F90:1
integer, parameter jprb
Definition: parkind1.F90:32
integer, parameter jpdblr
logical lhook
Definition: yomhook.F90:15
subroutine fapula_fort(FA, KREP, KRANG, PSPEC, KPULAP)
Definition: fapula.F90:5
subroutine faipar_fort(FA, KNUMER, KNIMES, KCODE, LDFATA, CDMESS, CDNSPR, CDACTI, LDRLFI)
Definition: faipar.F90:6
integer(kind=jplikb), parameter jpniil
Definition: fa_mod.F90:31