source: TOOLS/MOZAIC/src/MOZAIC/math.f90 @ 3918

Last change on this file since 3918 was 3326, checked in by omamce, 7 years ago

O.M. : Utility to generate interpolatio weights for OASIS-MCT

File size: 7.0 KB
Line 
1! -*- Mode: f90 -*-
2MODULE math
3   !
4   !> Some useful mathematical functions
5   !
6   USE declare
7   IMPLICIT NONE
8   !
9   !> 2D vector type, quadruple precision
10   TYPE v2d
11      REAL (kind=rd) :: x !< X-coordinate
12      REAL (kind=rd) :: y !< Y-coordinates
13   END TYPE v2d
14   !
15   !> Multiply 2D vectors
16   INTERFACE OPERATOR ( * ) 
17      MODULE PROCEDURE vect_prod
18   END INTERFACE
19   !
20CONTAINS
21   !
22   ELEMENTAL FUNCTION vect_prod (a, b) 
23      !> Vector product
24      USE declare
25      IMPLICIT NONE
26      !
27      REAL (kind=rl) :: vect_prod
28      TYPE(v2d), INTENT (in) :: a !< First vector to multiply
29      TYPE(v2d), INTENT (in) :: b !< 2nd vector to multiply
30      !
31      vect_prod = a%x * b%y - a%y * b%x
32      !
33      RETURN
34   END FUNCTION vect_prod
35   !
36   FUNCTION poly_surf (xa, ya )
37      !> Surface of a polygone
38      USE declare
39      IMPLICIT NONE
40      !
41      REAL (kind=rl) :: poly_surf
42      REAL (kind=rl), INTENT (in), DIMENSION ( :) :: xa, ya
43      INTEGER (kind=il) :: jn
44      REAL (kind=rd) :: zs
45      !
46      zs = 0.0_rd
47      DO jn = 1, SIZE (xa) - 2
48         zs = zs + v2d ( xa(jn+1)-xa(jn), ya(jn+1)-ya(jn)) * v2d ( xa(jn+2)-xa(jn), ya(jn+2)-ya(jn))
49      END DO
50      poly_surf = 0.5_rl * zs   
51      !
52      RETURN
53   END FUNCTION poly_surf
54   !
55   ELEMENTAL FUNCTION dist (x1, y1, x2, y2)
56      !> Distance between two points (cartesian)
57      USE declare
58      IMPLICIT NONE
59      REAL (kind=rl) :: dist
60      REAL (kind=rl), INTENT ( in) :: x1, y1, x2, y2
61      dist = SQRT ( (x2-x1)**2 + (y2-y1)**2 )
62      RETURN
63   END FUNCTION dist
64   ELEMENTAL FUNCTION ddist (x1, y1, x2, y2)
65      !> Distance between two points (cartesian), quadruple precision
66      USE declare
67      IMPLICIT NONE
68      REAL (kind=rd) :: ddist
69      REAL (kind=rd), INTENT ( in) :: x1, y1, x2, y2
70      ddist = SQRT ( (x2-x1)**2 + (y2-y1)**2 )
71      RETURN
72   END FUNCTION ddist
73   !
74   ELEMENTAL FUNCTION dgeodist (x1, y1, x2, y2)
75      !> Distance between two points (on sphere), quadruple precision
76      USE declare
77      IMPLICIT NONE
78      REAL (kind=rd) :: dgeodist
79      REAL (kind=rd), INTENT (in) :: x1, y1, x2, y2
80      REAL (kind=rd) :: zs, zrad
81      zrad = ACOS ( -1.0_rd) / 180.0_rd
82      zs =     SIN (zrad*REAL(y1,rd)) * SIN (zrad*REAL(y2,rd)) &
83         &  +  COS (zrad*REAL(y1,rd)) * COS (zrad*REAL(y2,rd)) * COS(zrad*REAL (x2-x1,rd))
84      zs = MAX (-1.0_rd, MIN (1.0_rd, zs))
85      dgeodist =  REAL ( ACOS (zs), KIND=rl)
86      RETURN
87   END FUNCTION dgeodist
88   !
89!-$$   ELEMENTAL FUNCTION geodist (x1, y1, x2, y2)
90!-$$      !> Distance between two points (on sphere)
91!-$$      USE declare
92!-$$      IMPLICIT NONE
93!-$$      REAL (kind=rl) :: geodist
94!-$$      REAL (kind=rl), INTENT (in) :: x1, y1, x2, y2
95!-$$      geodist = REAL (dgeodist (REAL (x1,rd), REAL (y1,rd), REAL (x2,rd), REAL(y2,rd)),rl)
96!-$$   END FUNCTION geodist
97
98   ELEMENTAL FUNCTION geodist (zlon1, zlat1, zlon2, zlat2)
99      !> Distance between two points (on sphere)
100      USE declare
101      IMPLICIT NONE
102      REAL (kind=rl) :: geodist
103      REAL (kind=rl), INTENT (in) :: zlon1, zlat1, zlon2, zlat2
104      REAL (kind=rl) :: zs, zrad
105      zrad = ACOS ( -1.0_rl) / 180.0_rl
106      zs = SIN (zrad*zlat1) * SIN (zrad*zlat2) +  COS (zrad*zlat1) * COS (zrad*zlat2) * COS(zrad*(zlon2-zlon1))
107      zs = MAX (-1.0_rl, MIN (1.0_rl, zs))
108      geodist =  ACOS (zs)
109      RETURN
110   END FUNCTION geodist
111
112!-$$   ELEMENTAL FUNCTION geodist_min (zlon1, zlat1, zlon2, zlat2, zdmax)
113!-$$      !> Distance between two points (on sphere). Simplified for too far points
114!-$$      USE declare
115!-$$      IMPLICIT NONE
116!-$$      REAL (kind=rl) :: geodist
117!-$$      REAL (kind=rl), INTENT (in) :: zlon1, zlat1, zlon2, zlat2, zdmax
118!-$$      REAL (kind=rl) :: zs, zrad
119!-$$
120!-$$      IF ( ABS (zlat2-zlat1)  .GT. zdmax * zrad ) THEN
121!-$$         geodist = zdmax
122!-$$         RETURN
123!-$$      END IF
124!-$$     
125!-$$     
126!-$$      zrad = ACOS ( -1.0_rl) / 180.0_rl
127!-$$      zs = SIN (zrad*zlat1) * SIN (zrad*zlat2) +  COS (zrad*zlat1) * COS (zrad*zlat2) * COS(zrad*(zlon2-zlon1))
128!-$$      zs = MAX (-1.0_rl, MIN (1.0_rl, zs))
129!-$$      geodist =  ACOS (zs)
130!-$$      RETURN
131!-$$   END FUNCTION geodist_min
132   
133   !
134   FUNCTION cartdist (zlon1, zlat1, zlon2, zlat2)
135      !> Distance between two points (on sphere)
136      ! Simplified computation
137      USE declare
138      IMPLICIT NONE
139      REAL (kind=rl) :: cartdist
140      REAL (kind=rl), INTENT (in) :: zlon1, zlat1, zlon2, zlat2
141      REAL (kind=rl) :: x1, y1, z1, x2, y2, z2, c1, c2, dx, dy, dz, dxyz
142      REAL (kind=rl) :: zrad
143      zrad = ACOS ( -1.0_rl) / 180.0_rl
144      c1   = COS(zrad*zlat1)
145      x1   = c1*COS(zrad*zlon1)
146      y1   = c1*SIN(zrad*zlon1)
147      z1   = SIN(zrad*zlat1)
148      c2   = COS(zrad*zlat2) 
149      x2   = c2*COS(zrad*zlon2)
150      y2   = c2*SIN(zrad*zlon2)
151      z2   = SIN(zrad*zlat2)
152     
153      dx = x1-x1 ; dy = y1-y2 ; dz = z1-z2
154      dxyz = dx*dx + dy*dy + dz*dz
155      cartdist = SQRT ( dxyz )
156
157   END FUNCTION cartdist
158   !
159   ELEMENTAL FUNCTION an_som (x0, y0, x1, y1, x2, y2)
160      !> Angle au sommet d'un triangle spherique
161      USE declare
162      IMPLICIT NONE
163      REAL (kind=rd) :: an_som
164      REAL (kind=rd), INTENT ( in) :: x0, y0, x1, y1, x2, y2
165      REAL (kind=rd) :: za, zb, zc, zs
166      za = dgeodist (REAL(x1,rd), REAL(y1,rd), REAL(x2,rd), REAL(y2,rd))
167      zb = dgeodist (REAL(x0,rd), REAL(y0,rd), REAL(x1,rd), REAL(y1,rd))
168      zc = dgeodist (REAL(x0,rd), REAL(y0,rd), REAL(x2,rd), REAL(y2,rd))
169      IF ( za == 0.0_rd .OR. zb == 0.0_rd .OR. zc == 0.0_rd ) THEN
170         an_som = 0.0_rd
171      ELSE
172         zs =  ( COS(za)-COS(zb)*COS(zc) ) / ( SIN(zb)*SIN(zc) )
173         an_som = REAL (ACOS (zs))
174      ENDIF
175      RETURN
176   END FUNCTION an_som
177   !
178   ELEMENTAL FUNCTION surf_sphe (x1, y1, x2, y2, x3, y3) 
179      !> Surface d'un triangle spherique
180      USE declare
181      IMPLICIT NONE
182      REAL (kind=rd) :: surf_sphe
183      REAL (kind=rd), INTENT ( in) :: x1, y1, x2, y2, x3, y3
184      REAL (kind=rd) :: za, zb, zc
185      za = an_som (REAL(x1,rd), REAL(y1,rd), REAL(x3,rd), REAL(y3,rd), REAL(x2,rd), REAL(y2,rd))
186      zb = an_som (REAL(x2,rd), REAL(y2,rd), REAL(x1,rd), REAL(y1,rd), REAL(x3,rd), REAL(y3,rd))
187      zc = an_som (REAL(x3,rd), REAL(y3,rd), REAL(x2,rd), REAL(y2,rd), REAL(x1,rd), REAL(y1,rd))
188      IF ( za == 0.0_rd .OR. zb == 0.0_rd .OR. zc == 0.0_rd ) THEN
189         surf_sphe = 0.0_rl
190      ELSE
191         surf_sphe = za + zb + zc - ACOS ( -1.0_rd)
192      ENDIF
193      RETURN
194   END FUNCTION surf_sphe
195   !
196   FUNCTION surf_box (xed, yed)
197      !> Surface d'une boite de modele
198      USE declare
199      IMPLICIT NONE
200      REAL (kind=rl) :: surf_box
201      REAL (kind=rl), DIMENSION(9), INTENT(in) :: xed, yed
202      INTEGER (kind=il) :: je, jne
203      REAL (kind=rd) :: zsurf
204
205      jne = SIZE(xed)
206      zsurf = 0.0_rl
207
208      DO je = 1, jne-1
209         zsurf = zsurf + surf_sphe (REAL(xed(jne ),rd), REAL(yed(jne ),rd), &
210            &                       REAL(xed(je  ),rd), REAL(yed(je  ),rd), &
211            &                       REAL(xed(je+1),rd), REAL(yed(je+1),rd) )
212      END DO
213
214      surf_box = REAL (zsurf, kind = rl)
215
216      RETURN
217   END FUNCTION surf_box
218   !
219END MODULE math
Note: See TracBrowser for help on using the repository browser.