SURFEX v8.1
General documentation of Surfex
sso.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 sso (U, UG, USS, OSSO, OSSO_ANIS)
7 ! #########################
8 !
9 !!*SSO computes the SSO anisotropy, direction and slope
10 !!
11 !!
12 !! METHOD
13 !! ------
14 !! See Lott and Miller, 1997, QJRMS 101-127
15 !!
16 !! AUTHOR
17 !! ------
18 !!
19 !! V.Masson Meteo-France
20 !!
21 !! MODIFICATION
22 !! ------------
23 !!
24 !! Original 23/05/97
25 !!
26 !----------------------------------------------------------------------------
27 !
28 !* 0. DECLARATION
29 ! -----------
30 !
31 USE modd_surfex_mpi, ONLY : nrank
32 !
34 USE modd_sso_n, ONLY : sso_t
35 USE modd_surf_atm_n, ONLY : surf_atm_t
36 !
37 USE modd_surfex_mpi, ONLY : nrank, npio
38 !
39 USE modi_get_mesh_dim
40 USE modi_get_adjacent_meshes
41 !
44 !
45 USE modd_csts, ONLY : xpi
46 USE modd_pgdwork, ONLY : nsso, xssqo, lssqo
47 USE modd_pgd_grid, ONLY : nl, cgrid
48 !
49 !
50 USE yomhook ,ONLY : lhook, dr_hook
51 USE parkind1 ,ONLY : jprb
52 !
53 IMPLICIT NONE
54 !
55 !* 0.1 Declaration of dummy arguments
56 ! ------------------------------
57 !
58 !
59 TYPE(surf_atm_t), INTENT(INOUT) :: U
60 TYPE(surf_atm_grid_t), INTENT(INOUT) :: UG
61 TYPE(sso_t), INTENT(INOUT) :: USS
62 !
63 LOGICAL, DIMENSION(:), INTENT(OUT) :: OSSO ! .T. : the SSO coefficients
64 ! ! are computed at grid point
65 ! ! .F. : not enough sub-grid
66 ! ! information avalaible to
67 ! ! compute the coefficients
68 LOGICAL, DIMENSION(:), INTENT(OUT) :: OSSO_ANIS ! .T. : the SSO anisotropy
69 ! ! are computed at grid point
70 ! ! .F. : not enough sub-grid
71 ! ! information avalaible to
72 ! ! compute the coefficients
73 !
74 !* 0.2 Declaration of indexes
75 ! ----------------------
76 !
77 INTEGER :: JS1, JS2
78 INTEGER :: JL ! loop index on grid meshs
79 INTEGER :: IL ! grid mesh index of second subgrid point used
80 INTEGER :: JISS, JJSS ! loop indexes for subsquares arrays
81 INTEGER :: JNEXT ! loop index on subgrid meshes
82 INTEGER :: JPREV ! loop index on subgrid meshes
83 INTEGER :: INEXT ! index to add to JISS or JJSS to obtain the following
84 ! ! point containing a data in a segment
85 INTEGER :: IPREV ! index to remove from JISS or JJSS to obtain the
86 ! ! previous point containing a data in a segment
87 !
88 INTEGER :: IMAXI ! index of the next subsquare with data along I axis,
89  ! or last subsquare inside grid mesh along I axis
90 INTEGER :: IMAXJ ! index of the next subsquare with data along J axis,
91  ! or last subsquare inside grid mesh along J axis
92 INTEGER, DIMENSION(:), ALLOCATABLE :: ILEFT, IRIGHT, ITOP, IBOTTOM
93 INTEGER :: ICOUNT
94 !
95 !* 0.3 Declaration of working arrays inside a MESONH grid (JI,JJ)
96 ! -----------------------------
97 !
98 INTEGER, DIMENSION(:), ALLOCATABLE :: ISSO, ISSOT
99 INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: ISSQOT, ISSQO
100 REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZSSQO
101 LOGICAL, DIMENSION(:,:,:), ALLOCATABLE :: GSSQO
102 LOGICAL, DIMENSION(:), ALLOCATABLE :: GSSO, GSSO_ANIS
103 !
104 REAL, DIMENSION(NSSO,NSSO) :: ZDZSDX ! topographic gradient along x
105 REAL, DIMENSION(NSSO,NSSO) :: ZDZSDY ! topographic gradient along y
106 LOGICAL, DIMENSION(NSSO,NSSO) :: GDZSDX ! occurence of gradient along x
107 LOGICAL, DIMENSION(NSSO,NSSO) :: GDZSDY ! occurence of gradient along y
108 REAL :: ZDXEFF ! width of a subsquare along I axis
109 REAL :: ZDYEFF ! width of a subsquare along J axis
110 LOGICAL :: GBOUND ! .T.: first left (for dzs/dx) or first bottom (for dzs/dy)
111  ! sub-square gradients is being computed
112 !
113 !* 0.4 Declaration of other local variables
114 ! ------------------------------------
115 !
116 REAL, DIMENSION(:), ALLOCATABLE :: ZDX, ZDY, ZSEA, ZMESH_SIZE
117 REAL, DIMENSION(:), ALLOCATABLE :: ZHXX0, ZHXY0, ZHYY0
118 REAL, DIMENSION(NL) :: ZHXX ! topographic gradient correlation tensor: x,x
119 REAL, DIMENSION(NL) :: ZHXY ! topographic gradient correlation tensor: x,y
120 REAL, DIMENSION(NL) :: ZHYY ! topographic gradient correlation tensor: y,y
121 REAL, DIMENSION(NL) :: ZK, ZL, ZM ! diagonalised terms of the tensor
122 REAL(KIND=JPRB) :: ZHOOK_HANDLE
123 !
124 !----------------------------------------------------------------------------
125 !
126 !* 1. Initializations
127 ! ---------------
128 !
129 IF (lhook) CALL dr_hook('SSO',0,zhook_handle)
130 !
131 !* 1.1 Occurence of computation of the coefficients
132 ! --------------------------------------------
133 !
134 osso(:)=.false.
135 osso_anis(:)=.false.
136 !
137 zhyy(:) = 0.
138 zhxx(:) = 0.
139 zhxy(:) = 0.
140 !
141 !* 1.2 Grid dimension (meters)
142 ! -----------------------
143 !
144 IF (nrank==npio) THEN
145  ALLOCATE(zsea(u%NDIM_FULL))
146  ALLOCATE(zmesh_size(u%NDIM_FULL))
147  ALLOCATE(zssqo(u%NDIM_FULL,nsso,nsso))
148  ALLOCATE(issqot(u%NDIM_FULL,nsso,nsso))
149 ELSE
150  ALLOCATE(zsea(0))
151  ALLOCATE(zssqo(0,0,0))
152  ALLOCATE(issqot(0,0,0))
153 ENDIF
154 !
155  CALL gather_and_write_mpi(u%XSEA,zsea)
156  CALL gather_and_write_mpi(ug%G%XMESH_SIZE,zmesh_size)
157  CALL gather_and_write_mpi(xssqo,zssqo)
158 !
159 ALLOCATE(issqo(SIZE(xssqo,1),nsso,nsso))
160 IF (SIZE(issqo)/=0) THEN
161  issqo(:,:,:) = 0
162  WHERE (lssqo(:,:,:)) issqo(:,:,:) = 1
163 ENDIF
164  CALL gather_and_write_mpi(issqo,issqot)
165 DEALLOCATE(issqo)
166 !
167 IF (nrank==npio) THEN
168  !
169  ALLOCATE(zdx(u%NDIM_FULL),zdy(u%NDIM_FULL))
170  CALL get_mesh_dim(cgrid,ug%NGRID_FULL_PAR,u%NDIM_FULL,ug%XGRID_FULL_PAR,zdx,zdy,zmesh_size)
171  DEALLOCATE(zmesh_size)
172 
173  !
174  !
175  !* 1.3 Left, top, right and bottom adjacent gris meshes
176  ! ------------------------------------------------
177  !
178  ALLOCATE(ileft(u%NDIM_FULL),iright(u%NDIM_FULL),itop(u%NDIM_FULL),ibottom(u%NDIM_FULL))
179  CALL get_adjacent_meshes(cgrid,ug%NGRID_FULL_PAR,u%NDIM_FULL,ug%XGRID_FULL_PAR,&
180  ileft,iright,itop,ibottom)
181  !
182  ALLOCATE(gsso(u%NDIM_FULL),gsso_anis(u%NDIM_FULL))
183  ALLOCATE(zhxx0(u%NDIM_FULL),zhxy0(u%NDIM_FULL),zhyy0(u%NDIM_FULL))
184  gsso(:) = .false.
185  gsso_anis(:) = .false.
186  zhyy0(:) = 0.
187  zhxx0(:) = 0.
188  zhxy0(:) = 0.
189  !
190  !
191  !* 2. Loop on MESONH grid points
192  ! --------------------------
193  !
194  !
195  !done on the whole grid (needed because of use of near points)
196  DO jl=1,u%NDIM_FULL
197  !
198  !
199  !* 2.1 No land in grid mesh
200  ! --------------------
201  !
202  IF (zsea(jl)==1.) cycle
203  !
204  zdxeff=zdx(jl)/float(nsso)
205  zdyeff=zdy(jl)/float(nsso)
206  !
207  !* 2.3 Not enough data for computation
208  ! -------------------------------
209  !
210  ! 1st step: removes points where orography data is not present at all.
211  !
212  IF ( count( issqot(jl,:,:)==1) == 0 ) cycle
213  !
214  !----------------------------------------------------------------------------
215  !
216  !* 3. Computations of the gradients along x
217  ! -------------------------------------
218  !
219  gdzsdx(:,:)=.false.
220  zdzsdx(:,:)= 0.
221  !
222  !* 3.1 loop on jss index (there is no specific computation along j)
223  ! -----------------
224  !
225  DO jjss=1,nsso
226  !
227  !* left point mark initialization
228  !
229  gbound=.true.
230  !
231  !* 3.2 loop on iss index
232  ! -----------------
233  !
234  DO jiss=1,nsso
235  !
236  !
237  !* 3.3 search for two consecutive grid points
238  ! --------------------------------------
239  !
240  !* 3.3.1 first one
241  !
242  IF ( issqot(jl,jiss,jjss)==0 ) cycle
243  !
244  !* 3.3.2 second one (up to one grid mesh further)
245  !
246  DO jnext=1,nsso
247  IF (jiss+jnext>nsso) THEN
248  il = iright(jl)
249  inext = jiss+jnext-nsso
250  ELSE
251  il = jl
252  inext = jiss+jnext
253  END IF
254  ! no right point
255  IF (il==0) EXIT
256  ! subgrid data found
257  IF (issqot(il,inext,jjss)==1) EXIT
258  END DO
259  !
260  !* 3.3.3 none found: end of loop along jss
261  ! ---------------------
262  !
263  IF (jnext>=nsso+1) EXIT
264  !
265  !* 3.3.4 second point outside of the domain: end of loop along iss
266  ! ---------------------
267  !
268  IF (il==0) EXIT
269  !
270  !* 3.4 dzs/dx term
271  ! -----------
272  !
273  imaxi = min(jiss+jnext-1,nsso)
274  !
275  zdzsdx(jiss:imaxi,jjss) = ( zssqo(il,inext,jjss) - zssqo(jl,jiss,jjss)) &
276  / float(jnext) / zdxeff
277  !
278  gdzsdx(jiss:imaxi,jjss) = .true.
279  !
280  !
281  !* 3.5 left data point not on the left of the grid mesh (one more computation)
282  ! ------------------------------------------------
283  !
284  IF (gbound .AND. jiss/=1) THEN
285  DO jprev=1,nsso
286  IF (jiss-jprev<1) THEN
287  il = ileft(jl)
288  iprev = jiss-jprev+nsso
289  ELSE
290  il = jl
291  iprev = jiss-jprev
292  END IF
293  ! no left point
294  IF (il==0) EXIT
295  ! subgrid data found
296  IF (issqot(il,iprev,jjss)==1) EXIT
297  END DO
298 
299  IF (.NOT. (jprev>=nsso+1 .OR. il==0)) THEN
300  zdzsdx(1:jiss,jjss) = ( zssqo(jl,jiss,jjss) - zssqo(il,iprev,jjss)) &
301  / float(jprev) / zdxeff
302  !
303  gdzsdx(1:jiss,jjss) = .true.
304  END IF
305  END IF
306  !
307  !
308  gbound=.false.
309  !
310  !
311  !* 3.6 end of loop on iss index
312  ! ------------------------
313  !
314  END DO
315  !
316  !* 3.7 end of loop on jss index
317  ! ------------------------
318  !
319  END DO
320  !
321  !----------------------------------------------------------------------------
322  !
323  !* 4. Computations of the gradients along y
324  ! -------------------------------------
325  !
326  gdzsdy(:,:)=.false.
327  zdzsdy(:,:)= 0.
328  !
329  !* 4.1 loop on iss index (there is no specific computation along i)
330  ! -----------------
331  !
332  DO jiss=1,nsso
333 !
334 !* bottom point mark initialization
335 !
336  gbound=.true.
337 !
338 !* 4.2 loop on jss index
339 ! -----------------
340 !
341  DO jjss=1,nsso
342 !
343 !
344 !* 4.3 search for two consecutive grid points
345 ! --------------------------------------
346 !
347 !* 4.3.1 first one
348 !
349  IF (issqot(jl,jiss,jjss)==0 ) cycle
350 !
351 !* 4.3.2 second one (up to one grid mesh further)
352 !
353  DO jnext=1,nsso
354  IF (jjss+jnext>nsso) THEN
355  il = itop(jl)
356  inext = jjss+jnext-nsso
357  ELSE
358  il = jl
359  inext = jjss+jnext
360  END IF
361  ! no top point
362  IF (il==0) EXIT
363  ! subgrid data found
364  IF (issqot(il,jiss,inext)==1) EXIT
365  END DO
366 !
367 !* 4.3.3 none found: end of loop along iss
368 ! ---------------------
369 !
370  IF (jnext>=nsso+1) EXIT
371 !
372 !* 3.3.4 second point outside of the domain: end of loop along iss
373 ! ---------------------
374 !
375  IF (il==0) EXIT
376 !
377 !* 4.4 dzs/dy term
378 ! -----------
379 !
380  imaxj = min(jjss+jnext-1,nsso)
381 !
382  zdzsdy(jiss,jjss:imaxj) = ( zssqo(il,jiss,inext) - zssqo(jl,jiss,jjss)) &
383  / float(jnext) / zdyeff
384  !
385  gdzsdy(jiss,jjss:imaxj) = .true.
386 !
387 !
388 !* 4.5 bottom data point not on the bottom of the grid mesh (one more computation)
389 ! ----------------------------------------------------
390 !
391  IF (gbound .AND. jjss/=1) THEN
392  DO jprev=1,nsso
393  IF (jjss-jprev<1) THEN
394  il = ibottom(jl)
395  iprev = jjss-jprev+nsso
396  ELSE
397  il = jl
398  iprev = jjss-jprev
399  END IF
400  ! no left point
401  IF (il==0) EXIT
402  ! subgrid data found
403  IF (issqot(il,jiss,iprev)==1) EXIT
404  END DO
405 
406  IF (.NOT. (jprev>=nsso+1 .OR. il==0)) THEN
407  zdzsdy(jiss,1:jjss) = ( zssqo(jl,jiss,jjss) - zssqo(il,jiss,iprev)) &
408  / float(jprev) / zdyeff
409 !
410  gdzsdy(jiss,1:jjss) = .true.
411  END IF
412  END IF
413 !
414 !
415  gbound=.false.
416 !
417  !
418  !
419  !* 4.6 end of loop on jss index
420  ! ------------------------
421  !
422  END DO
423  !
424  !* 4.7 end of loop on iss index
425  ! ------------------------
426  !
427  END DO
428  !----------------------------------------------------------------------------
429  !
430  !* 5. Computations of tensor terms
431  ! ----------------------------
432  !
433  !
434  !* 5.1 test to know if term Hxy is computable
435  ! --------------------------------------
436  !
437  icount = count(gdzsdx(:,:).AND.gdzsdy(:,:))
438  !* 2 values are necessary in the grid point to compute anisotropy
439  !
440  IF ( icount==0 ) cycle
441  !
442  !
443  !* 5.2 SSO quantities are computable
444  ! -----------------------------
445  !
446  gsso(jl)=.true.
447  gsso_anis(jl)=icount>1
448  !
449  !
450  !* 5.3 term Hxx
451  ! --------
452  !
453  zhxx0(jl) = sum(zdzsdx(:,:)*zdzsdx(:,:),mask=gdzsdx(:,:).AND.gdzsdy(:,:))/icount
454  !
455  !* 5.4 term Hyy
456  ! --------
457  !
458  zhyy0(jl) = sum(zdzsdy(:,:)*zdzsdy(:,:),mask=gdzsdx(:,:).AND.gdzsdy(:,:))/icount
459  !
460  !* 5.5 term Hxy
461  ! --------
462  !
463  zhxy0(jl) = sum(zdzsdx(:,:)*zdzsdy(:,:),mask=gdzsdx(:,:).AND.gdzsdy(:,:))/icount
464  !
465  !-------------------------------------------------------------------------------
466  !
467  !* 6. Next MESONH grid point
468  ! ----------------------
469  !
470  END DO
471  !
472 ELSE
473  !
474  ALLOCATE(zhxx0(0),zhyy0(0),zhxy0(0))
475  !
476 ENDIF
477 !
478 DEALLOCATE(zssqo,issqot)
479 DEALLOCATE(zsea)
480 !
481 !each contrib sent to each task
482  CALL read_and_send_mpi(zhxx0,zhxx)
483  CALL read_and_send_mpi(zhyy0,zhyy)
484  CALL read_and_send_mpi(zhxy0,zhxy)
485 DEALLOCATE(zhxx0,zhyy0,zhxy0)
486 !
487 IF (nrank==npio) THEN
488  ALLOCATE(issot(u%NDIM_FULL))
489  issot(:) = 0
490  WHERE (gsso(:)) issot(:) = 1
491  DEALLOCATE(gsso)
492 ELSE
493  ALLOCATE(issot(0))
494 ENDIF
495 ALLOCATE(isso(nl))
496  CALL read_and_send_mpi(issot,isso)
497 WHERE(isso(:)==1) osso(:) = .true.
498 !
499 IF (nrank==npio) THEN
500  issot(:) = 0
501  WHERE (gsso_anis(:)) issot(:) = 1
502  DEALLOCATE(gsso_anis)
503 ENDIF
504  CALL read_and_send_mpi(issot,isso)
505 WHERE(isso(:)==1) osso_anis(:) = .true.
506 DEALLOCATE(isso)
507 !
508 DEALLOCATE(issot)
509 !
510 !----------------------------------------------------------------------------
511 !
512 !* 7. Diagonalization of the tensor
513 ! -----------------------------
514 !
515 zk=0.
516 zl=0.
517 zm=0.
518 !
519 WHERE (osso(:))
520  zk(:)=0.5*(zhxx(:)+zhyy(:))
521  zl(:)=0.5*(zhxx(:)-zhyy(:))
522  zm(:)= zhxy(:)
523 END WHERE
524 !
525 !-------------------------------------------------------------------------------
526 !
527 !* 8. S.S.O. characteristics
528 ! ----------------------
529 !
530 !* 8.1 S.S.O. direction of main axis
531 ! -----------------------------
532 !
533 WHERE (osso(:) .AND. zl(:)>1.e-30 )
534  uss%XSSO_DIR(:) = 0.5* atan(zm/zl) * (180./xpi)
535 END WHERE
536 !
537 WHERE (osso(:) .AND. zl(:)<-1.e-30 )
538  uss%XSSO_DIR(:) = 0.5* atan(zm/zl) * (180./xpi) + 90.
539 END WHERE
540 !
541 WHERE (osso(:) .AND. abs(zl(:))<=1.e-30 )
542  uss%XSSO_DIR(:) = 45.
543 END WHERE
544 !
545 WHERE (osso(:) .AND. uss%XSSO_DIR(:)>90. )
546  uss%XSSO_DIR(:) = uss%XSSO_DIR(:) - 180.
547 END WHERE
548 !
549 !* 8.2 S.S.O. slope
550 ! ------------
551 !
552 WHERE (osso(:))
553  uss%XSSO_SLOPE(:) = sqrt( zk+sqrt(zl*zl+zm*zm) )
554 END WHERE
555 !
556 !* 8.3 S.S.O. anisotropy
557 ! -----------------
558 !
559 WHERE (osso_anis(:) .AND. (zk+sqrt(zl*zl+zm*zm)) >0. )
560  uss%XSSO_ANIS(:)=sqrt( max(zk-sqrt(zl*zl+zm*zm),0.) / (zk+sqrt(zl*zl+zm*zm)))
561 END WHERE
562 !
563 WHERE (osso_anis(:) .AND. (zk+sqrt(zl*zl+zm*zm))==0. )
564  uss%XSSO_ANIS(:)=1.
565 END WHERE
566 IF (lhook) CALL dr_hook('SSO',1,zhook_handle)
567 !
568 !-------------------------------------------------------------------------------
569 !
570 END SUBROUTINE sso
real, save xpi
Definition: modd_csts.F90:43
logical, dimension(:,:,:), allocatable lssqo
integer, parameter jprb
Definition: parkind1.F90:32
subroutine sso(U, UG, USS, OSSO, OSSO_ANIS)
Definition: sso.F90:7
subroutine get_adjacent_meshes(HGRID, KGRID_PAR, KL, PGRID_PAR, KLEFT,
real, dimension(:,:,:), allocatable xssqo
intent(out) overrides sub arrays one Sort by the least significant key first sum(iindex(1:n))
logical lhook
Definition: yomhook.F90:15
character(len=10) cgrid
static int mask
Definition: ifssig.c:38
subroutine get_mesh_dim(HGRID, KGRID_PAR, KL, PGRID_PAR, PDX, PDY, PMESH
Definition: get_mesh_dim.F90:7
static int count
Definition: memory_hook.c:21