source: codes/icosagcm/trunk/src/dcmip/dcmip2016_supercell.f90

Last change on this file was 899, checked in by adurocher, 5 years ago

trunk : Fixed GCC warnings

Fixed iso c bindings
fixed warnings with -Wall -Wno-aliasing -Wno-unused -Wno-unused-dummy-argument -Wno-maybe-uninitialized -Wno-tabs warnings
Removed all unused variables (-Wunused-variable)
vector%dot_product is now dot_product_3d to avoid compilation warning "dot_product shadows intrinsic" with GCC

  • Property svn:executable set to *
File size: 24.1 KB
Line 
1MODULE dcmip2016_supercell_mod
2
3!=======================================================================
4!
5!  Date:  April 22, 2016
6!
7!  Functions for setting up idealized initial conditions for the
8!  Klemp et al. supercell test.  Before sampling the result,
9!  supercell_test_init() must be called.
10!
11!  SUBROUTINE supercell_test(
12!    lon,lat,p,z,zcoords,u,v,t,thetav,ps,rho,q,pert)
13!
14!  Given a point specified by:
15!      lon    longitude (radians)
16!      lat    latitude (radians)
17!      p/z    pressure (Pa) / height (m)
18!  zcoords    1 if z is specified, 0 if p is specified
19!     pert    1 if thermal perturbation included, 0 if not
20!
21!  the functions will return:
22!        p    pressure if z is specified (Pa)
23!        z    geopotential height if p is specified (m)
24!        u    zonal wind (m s^-1)
25!        v    meridional wind (m s^-1)
26!        t    temperature (K)
27!   thetav    virtual potential temperature (K)
28!       ps    surface pressure (Pa)
29!      rho    density (kj m^-3)
30!        q    water vapor mixing ratio (kg/kg)
31!
32!  Author: Paul Ullrich
33!          University of California, Davis
34!          Email: paullrich@ucdavis.edu
35!
36!          Based on a code by Joseph Klemp
37!          (National Center for Atmospheric Research)
38!
39!=======================================================================
40
41  IMPLICIT NONE
42
43!=======================================================================
44!    Physical constants
45!=======================================================================
46
47  REAL(8), PARAMETER ::               &
48       a     = 6371220.0d0,           & ! Reference Earth's Radius (m)
49       Rd    = 287.0d0,               & ! Ideal gas const dry air (J kg^-1 K^1)
50       g     = 9.80616d0,             & ! Gravity (m s^2)
51       cp    = 1004.5d0,              & ! Specific heat capacity (J kg^-1 K^1)
52       Lvap  = 2.5d6,                 & ! Latent heat of vaporization of water
53       Rvap  = 461.5d0,               & ! Ideal gas constnat for water vapor
54       Mvap  = 0.608d0,               & ! Ratio of molar mass of dry air/water
55       pi    = 3.14159265358979d0,    & ! pi
56       p0    = 100000.0d0,            & ! surface pressure (Pa)
57       kappa = 2.d0/7.d0,             & ! Ratio of Rd to cp
58       omega = 7.29212d-5,            & ! Reference rotation rate of the Earth (s^-1)
59       deg2rad  = pi/180.d0             ! Conversion factor of degrees to radians
60
61!=======================================================================
62!    Test case parameters
63!=======================================================================
64  INTEGER(4), PARAMETER ::            &
65       nz         = 30         ,      & ! number of vertical levels in init
66       nphi       = 16                  ! number of meridional points in init
67
68  REAL(8), PARAMETER ::               &
69       z1         = 0.0d0      ,      & ! lower sample altitude
70       z2         = 50000.0d0           ! upper sample altitude
71
72  REAL(8), PARAMETER ::               &
73       X          = 120.d0     ,      & ! Earth reduction factor
74       theta0     = 300.d0     ,      & ! theta at the equatorial surface
75       theta_tr   = 343.d0     ,      & ! theta at the tropopause
76       z_tr       = 12000.d0   ,      & ! altitude at the tropopause
77       T_tr       = 213.d0     ,      & ! temperature at the tropopause
78       pseq       = 100000.0d0          ! surface pressure at equator (Pa)
79       !pseq       = 95690.0d0           ! surface pressure at equator (Pa)
80
81  REAL(8), PARAMETER ::               &
82       us         = 30.d0      ,      & ! maximum zonal wind velocity
83       uc         = 15.d0      ,      & ! coordinate reference velocity
84       zs         = 5000.d0    ,      & ! lower altitude of maximum velocity
85       zt         = 1000.d0             ! transition distance of velocity
86 
87  REAL(8), PARAMETER ::               &
88       pert_dtheta = 3.d0         ,   & ! perturbation magnitude
89       pert_lonc   = 0.d0         ,   & ! perturbation longitude
90       pert_latc   = 0.d0         ,   & ! perturbation latitude
91       pert_rh     = 10000.d0 * X ,   & ! perturbation horiz. halfwidth
92       pert_zc     = 1500.d0      ,   & ! perturbation center altitude
93       pert_rz     = 1500.d0            ! perturbation vert. halfwidth
94
95!-----------------------------------------------------------------------
96!    Coefficients computed from initialization
97!-----------------------------------------------------------------------
98  INTEGER(4)                  :: initialized = 0
99
100  REAL(8), DIMENSION(nphi)    :: phicoord
101  REAL(8), DIMENSION(nz)      :: zcoord
102  REAL(8), DIMENSION(nphi,nz) :: thetavyz
103  REAL(8), DIMENSION(nphi,nz) :: exneryz
104  REAL(8), DIMENSION(nz)      :: qveq
105
106CONTAINS
107
108!=======================================================================
109!    Generate the supercell initial conditions
110!=======================================================================
111  SUBROUTINE supercell_init() &
112    BIND(c, name = "supercell_init")
113
114    IMPLICIT NONE
115
116    ! d/dphi and int(dphi) operators
117    REAL(8), DIMENSION(nphi,nphi) :: ddphi, intphi
118
119    ! d/dz and int(dz) operators
120    REAL(8), DIMENSION(nz, nz) :: ddz, intz
121
122    ! Buffer matrices for computing SVD of d/dphi operator
123    REAL(8), DIMENSION(nphi,nphi) :: ddphibak
124    REAL(8), DIMENSION(nphi,nphi) :: svdpu, svdpvt
125    REAL(8), DIMENSION(nphi)      :: svdps
126    REAL(8), DIMENSION(5*nphi)    :: pwork
127
128    ! Buffer matrices for computing SVD of d/dz operator
129    REAL(8), DIMENSION(nz, nz) :: ddzbak
130    REAL(8), DIMENSION(nz, nz) :: svdzu, svdzvt
131    REAL(8), DIMENSION(nz)     :: svdzs
132    REAL(8), DIMENSION(5*nz)   :: zwork
133
134    ! Buffer data for calculation of SVD
135    INTEGER(4) :: lwork, info
136
137    ! Sampled values of ueq**2 and d/dz(ueq**2)
138    REAL(8), DIMENSION(nphi, nz) :: ueq2, dueq2
139
140    ! Buffer matrices for iteration
141    REAL(8), DIMENSION(nphi, nz) :: phicoordmat, dztheta, rhs, irhs
142 
143    ! Buffer for sampled potential temperature at equator
144    REAL(8), DIMENSION(nz) :: thetaeq
145
146    ! Buffer for computed equatorial Exner pressure and relative humidity
147    REAL(8), DIMENSION(nz) :: exnereq, H
148
149    ! Variables for calculation of equatorial profile
150    REAL(8) :: exnereqs, p, T, qvs
151
152    ! Loop indices
153    INTEGER(4) :: i, k, iter
154
155    ! Chebyshev nodes in the phi direction
156    do i = 1, nphi
157      phicoord(i) = - cos(dble(i-1) * pi / dble(nphi-1))
158      phicoord(i) = 0.25d0 * pi * (phicoord(i) + 1.0d0)
159    end do
160
161    ! Matrix of phis
162    do k = 1, nz
163      phicoordmat(:,k) = phicoord
164    end do
165
166    ! Chebyshev nodes in the z direction
167    do k = 1, nz
168      zcoord(k) = - cos(dble(k-1) * pi / dble(nz-1))
169      zcoord(k) = z1 + 0.5d0*(z2-z1)*(zcoord(k)+1.0d0)
170    end do
171
172    ! Compute the d/dphi operator
173    do i = 1, nphi
174      call diff_lagrangian_polynomial_coeffs( &
175        nphi, phicoord, ddphi(:,i), phicoord(i))
176    end do
177
178    ! Zero derivative at pole
179    ddphi(:,nphi) = 0.0d0
180
181    ! Compute the d/dz operator
182    do k = 1, nz
183      call diff_lagrangian_polynomial_coeffs( &
184        nz, zcoord, ddz(:,k), zcoord(k))
185    end do
186
187    ! Compute the int(dphi) operator via pseudoinverse
188    lwork = 5*nphi
189
190    ddphibak = ddphi
191    call DGESVD('A', 'A', &
192       nphi, nphi, ddphibak, nphi, &
193       svdps, svdpu, nphi, svdpvt, nphi, &
194       pwork, lwork, info)
195
196    if (info .ne. 0) then
197      write(*,*) 'Unable to compute SVD of d/dphi matrix'
198      stop
199    end if
200
201    do i = 1, nphi
202      if (abs(svdps(i)) .le. 1.0d-12) then
203        call DSCAL(nphi, 0.0d0, svdpu(1,i), 1)
204      else
205        call DSCAL(nphi, 1.0d0 / svdps(i), svdpu(1,i), 1)
206      end if
207    end do
208    call DGEMM('T', 'T', &
209      nphi, nphi, nphi, 1.0d0, svdpvt, nphi, svdpu, nphi, 0.0d0, &
210      intphi, nphi)
211
212    ! Compute the int(dz) operator via pseudoinverse
213    lwork = 5*nz
214
215    ddzbak = ddz
216    call DGESVD('A', 'A', &
217       nz, nz, ddzbak, nz, &
218       svdzs, svdzu, nz, svdzvt, nz, &
219       zwork, lwork, info)
220
221    if (info .ne. 0) then
222      write(*,*) 'Unable to compute SVD of d/dz matrix'
223      stop
224    end if
225
226    do i = 1, nz
227      if (abs(svdzs(i)) .le. 1.0d-12) then
228        call DSCAL(nz, 0.0d0, svdzu(1,i), 1)
229      else
230        call DSCAL(nz, 1.0d0 / svdzs(i), svdzu(1,i), 1)
231      end if
232    end do
233    call DGEMM('T', 'T', &
234      nz, nz, nz, 1.0d0, svdzvt, nz, svdzu, nz, 0.0d0, &
235      intz, nz)
236
237    ! Sample the equatorial velocity field and its derivative
238    do k = 1, nz
239      ueq2(1,k) = zonal_velocity(zcoord(k), 0.0d0)
240      ueq2(1,k) = ueq2(1,k)**2
241    end do
242    do k = 1, nz
243      dueq2(1,k) = dot_product(ddz(:,k), ueq2(1,:))
244    end do
245    do i = 2, nphi
246      ueq2(i,:) = ueq2(1,:)
247      dueq2(i,:) = dueq2(1,:)
248    end do
249
250    ! Initialize potential temperature at equator
251    do k = 1, nz
252      thetaeq(k) = equator_theta(zcoord(k))
253      H(k) = equator_relative_humidity(zcoord(k))
254    end do
255    thetavyz(1,:) = thetaeq
256
257    ! Exner pressure at the equatorial surface
258    exnereqs = (pseq / p0)**(Rd/cp)
259
260    ! Iterate on equatorial profile
261    do iter = 1, 12
262
263      ! Calculate Exner pressure in equatorial column (p0 at surface)
264      rhs(1,:) = - g / cp / thetavyz(1,:)
265      do k = 1, nz
266        exnereq(k) = dot_product(intz(:,k), rhs(1,:))
267      end do
268      do k = 2, nz
269        exnereq(k) = exnereq(k) + (exnereqs - exnereq(1))
270      end do
271      exnereq(1) = exnereqs
272
273      ! Calculate new pressure and temperature
274      do k = 1, nz
275        p = p0 * exnereq(k)**(cp/Rd)
276        T = thetaeq(k) * exnereq(k)
277
278        qvs = saturation_mixing_ratio(p, T)
279        qveq(k) = qvs * H(k)
280
281        thetavyz(1,k) = thetaeq(k) * (1.d0 + 0.61d0 * qveq(k))
282      end do
283    end do
284
285    !do k = 1, nz
286    !  write(*,*) exnereq(k) * thetaeq(k)
287    !end do
288
289    ! Iterate on remainder of domain
290    do iter = 1, 12
291
292      ! Compute d/dz(theta)
293      do i = 1, nphi
294        do k = 1, nz
295          dztheta(i,k) = dot_product(ddz(:,k), thetavyz(i,:))
296        end do
297      end do
298
299      ! Compute rhs
300      rhs = sin(2.0d0*phicoordmat)/(2.0d0*g) &
301            * (ueq2 * dztheta - thetavyz * dueq2)
302
303      ! Integrate
304      do k = 1, nz
305        do i = 1, nphi
306          irhs(i,k) = dot_product(intphi(:,i), rhs(:,k))
307        end do
308      end do
309
310      ! Apply boundary conditions (fixed Dirichlet condition at equator)
311      do i = 2, nphi
312        irhs(i,:) = irhs(i,:) + (thetavyz(1,:) - irhs(1,:))
313      end do
314      irhs(1,:) = thetavyz(1,:)
315
316      ! Compute difference after iteration
317      !err = sum(irhs - thetavyz)
318      !write(*,*) iter, err
319
320      ! Update iteration
321      thetavyz = irhs
322    end do
323
324    ! Calculate pressure through remainder of domain
325    rhs = - ueq2 * sin(phicoordmat) * cos(phicoordmat) / cp / thetavyz
326
327    do k = 1, nz
328      do i = 1, nphi
329        exneryz(i,k) = dot_product(intphi(:,i), rhs(:,k))
330      end do
331      do i = 2, nphi
332        exneryz(i,k) = exneryz(i,k) + (exnereq(k) - exneryz(1,k))
333      end do
334
335      exneryz(1,k) = exnereq(k)
336    end do
337
338    ! Initialization successful
339    initialized = 1
340
341  END SUBROUTINE supercell_init
342
343!-----------------------------------------------------------------------
344!    Evaluate the supercell initial conditions
345!-----------------------------------------------------------------------
346  SUBROUTINE supercell_test(lon,lat,p,z,zcoords,u,v,t,thetav,ps,rho,q,pert) &
347    BIND(c, name = "supercell_test")
348    use iso_c_binding
349    IMPLICIT NONE
350
351    !------------------------------------------------
352    !   Input / output parameters
353    !------------------------------------------------
354    REAL(KIND=c_double), INTENT(IN)  :: &
355                lon,        & ! Longitude (radians)
356                lat           ! Latitude (radians)
357
358    REAL(KIND=c_double), INTENT(INOUT) :: &
359                p,            & ! Pressure (Pa)
360                z               ! Altitude (m)
361
362    INTEGER(KIND=c_int32_t), INTENT(IN) :: zcoords     ! 1 if z coordinates are specified
363                                       ! 0 if p coordinates are specified
364
365    REAL(KIND=c_double), INTENT(OUT) :: &
366                u,          & ! Zonal wind (m s^-1)
367                v,          & ! Meridional wind (m s^-1)
368                t,          & ! Temperature (K)
369                thetav,     & ! Virtual potential Temperature (K)
370                ps,         & ! Surface Pressure (Pa)
371                rho,        & ! density (kg m^-3)
372                q             ! water vapor mixing ratio (kg/kg)
373
374    INTEGER(KIND=c_int32_t), INTENT(IN) :: pert  ! 1 if perturbation should be included
375                                 ! 0 if no perturbation should be included
376
377    !------------------------------------------------
378    !   Local variables
379    !------------------------------------------------
380
381    ! Absolute latitude
382    REAL(8) :: nh_lat
383
384    ! Check that we are initialized
385    if (initialized .ne. 1) then
386      write(*,*) 'supercell_init() has not been called'
387      stop
388    end if
389
390    !------------------------------------------------
391    !   Begin sampling
392    !------------------------------------------------
393
394    ! Northern hemisphere latitude
395    if (lat .le. 0.0d0) then
396      nh_lat = -lat
397    else
398      nh_lat = lat
399    end if
400
401    ! Sample surface pressure
402    CALL supercell_z(lon, lat, 0.d0, ps, thetav, rho, q, pert)
403
404    ! Calculate dependent variables
405    if (zcoords .eq. 1) then
406      CALL supercell_z(lon, lat, z, p, thetav, rho, q, pert)
407    else
408      CALL supercell_p(lon, lat, p, z, thetav, rho, q, pert)
409    end if
410
411    ! Sample the zonal velocity
412    u = zonal_velocity(z, lat)
413
414    ! Zero meridional velocity
415    v = 0.d0
416
417    ! Temperature
418    t = thetav / (1.d0 + 0.61d0 * q) * (p / p0)**(Rd/cp)
419
420  END SUBROUTINE supercell_test
421
422!-----------------------------------------------------------------------
423!    Calculate pointwise pressure and temperature
424!-----------------------------------------------------------------------
425  SUBROUTINE supercell_z(lon, lat, z, p, thetav, rho, q, pert)
426
427    REAL(8), INTENT(IN)  :: &
428                lon,        & ! Longitude (radians)
429                lat,        & ! Latitude (radians)
430                z             ! Altitude (m)
431
432    INTEGER, INTENT(IN) :: pert  ! 1 if perturbation should be included
433                                 ! 0 if no perturbation should be included
434
435    ! Evaluated variables
436    REAL(8), INTENT(OUT) :: p, thetav, rho, q
437
438    ! Northern hemisphere latitude
439    REAL(8) :: nh_lat
440
441    ! Pointwise Exner pressure
442    REAL(8) :: exner
443
444    ! Assembled variable values in a column
445    REAL(8), DIMENSION(nz) :: varcol
446
447    ! Coefficients for computing a polynomial fit in each coordinate
448    REAL(8), DIMENSION(nphi) :: fitphi
449    REAL(8), DIMENSION(nz)   :: fitz
450
451    ! Loop indices
452    INTEGER(4) :: k
453
454    ! Northern hemisphere latitude
455    if (lat .le. 0.0d0) then
456      nh_lat = -lat
457    else
458      nh_lat = lat
459    end if
460
461    ! Perform fit
462    CALL lagrangian_polynomial_coeffs(nz, zcoord, fitz, z)
463    CALL lagrangian_polynomial_coeffs(nphi, phicoord, fitphi, nh_lat)
464
465    ! Obtain exner pressure of background state
466    do k = 1, nz
467      varcol(k) = dot_product(fitphi, exneryz(:,k))
468    end do
469    exner = dot_product(fitz, varcol)
470    p = p0 * exner**(cp/Rd)
471
472    ! Sample the initialized fit at this point for theta_v
473    do k = 1, nz
474      varcol(k) = dot_product(fitphi, thetavyz(:,k))
475    end do
476    thetav = dot_product(fitz, varcol)
477
478    ! Sample water vapor mixing ratio
479    q = dot_product(fitz, qveq)
480
481    ! Fixed density
482    rho = p / (Rd * exner * thetav)
483
484    ! Modified virtual potential temperature
485    if (pert .ne. 0) then
486        thetav = thetav &
487           + thermal_perturbation(lon, lat, z) * (1.d0 + 0.61d0 * q)
488    end if
489
490    ! Updated pressure
491    p = p0 * (rho * Rd * thetav / p0)**(cp/(cp-Rd))
492
493  END SUBROUTINE supercell_z
494
495!-----------------------------------------------------------------------
496!    Calculate pointwise z and temperature given pressure
497!-----------------------------------------------------------------------
498  SUBROUTINE supercell_p(lon, lat, p, z, thetav, rho, q, pert)
499
500    REAL(8), INTENT(IN)  :: &
501                lon,        & ! Longitude (radians)
502                lat,        & ! Latitude (radians)
503                p             ! Pressure (Pa)
504
505    INTEGER, INTENT(IN) :: pert  ! 1 if perturbation should be included
506                                 ! 0 if no perturbation should be included
507
508    ! Evaluated variables
509    REAL(8), INTENT(OUT) :: z, thetav, rho, q
510
511    ! Bounding interval and sampled values
512    REAL(8) :: za, zb, zc, pa, pb, pc
513
514    ! Iterate
515    INTEGER(4) :: iter
516
517    za = z
518    zb = z2
519
520    CALL supercell_z(lon, lat, za, pa, thetav, rho, q, pert)
521    CALL supercell_z(lon, lat, zb, pb, thetav, rho, q, pert)
522
523    if (pa .lt. p) then
524      write(*,*) 'Requested pressure out of range on bottom, adjust sample interval'
525      write(*,*) pa, p
526      stop
527    end if
528    if (pb .gt. p) then
529      write(*,*) 'Requested pressure out of range on top, adjust sample interval'
530      write(*,*) pb, p
531      stop
532    end if
533
534    ! Iterate using fixed point method
535    do iter = 1, 100
536
537      zc = (za * (pb - p) - zb * (pa - p)) / (pb - pa)
538
539      CALL supercell_z(lon, lat, zc, pc, thetav, rho, q, pert)
540
541      !write(*,*) pc
542
543      if (abs((pc - p) / p) .lt. 1.d-10) then
544        exit
545      end if
546
547      if (pc .gt. p) then
548        za = zc
549        pa = pc
550      else
551        zb = zc
552        pb = pc
553      end if
554    end do
555
556    if (iter .eq. 101) then
557      write(*,*) 'Iteration failed to converge'
558      stop
559    end if
560
561    z = zc
562
563  END SUBROUTINE supercell_p
564
565!-----------------------------------------------------------------------
566!    Calculate pointwise z and temperature given pressure
567!-----------------------------------------------------------------------
568  REAL(8) FUNCTION thermal_perturbation(lon, lat, z)
569
570    REAL(8), INTENT(IN)  :: &
571                lon,        & ! Longitude (radians)
572                lat,        & ! Latitude (radians)
573                z             ! Altitude (m)
574
575    ! Great circle radius from the perturbation centerpoint
576    REAL(8) :: gr
577
578    ! Approximately spherical radius from the perturbation centerpoint
579    REAL(8) :: Rtheta
580
581    gr = a*acos(sin(pert_latc*deg2rad)*sin(lat) + &
582         (cos(pert_latc*deg2rad)*cos(lat)*cos(lon-pert_lonc*deg2rad)))
583
584    Rtheta = sqrt((gr/pert_rh)**2 + ((z - pert_zc) / pert_rz)**2)
585
586    if (Rtheta .le. 1.d0) then
587      thermal_perturbation = pert_dtheta * (cos(0.5d0 * pi * Rtheta))**2
588    else
589      thermal_perturbation = 0.0d0
590    end if
591
592  END FUNCTION thermal_perturbation
593
594!-----------------------------------------------------------------------
595!    Calculate the reference zonal velocity
596!-----------------------------------------------------------------------
597  REAL(8) FUNCTION zonal_velocity(z, lat)
598
599    IMPLICIT NONE
600
601    REAL(8), INTENT(IN) :: z, lat
602
603    if (z .le. zs - zt) then
604      zonal_velocity = us * (z / zs) - uc
605    elseif (abs(z - zs) .le. zt) then
606      zonal_velocity = &
607        (-4.0d0/5.0d0 + 3.0d0*z/zs - 5.0d0/4.0d0*(z**2)/(zs**2)) * us - uc
608    else
609      zonal_velocity = us - uc
610    end if
611
612    zonal_velocity = zonal_velocity * cos(lat)
613     
614  END FUNCTION zonal_velocity
615
616!-----------------------------------------------------------------------
617!    Calculate pointwise theta at the equator at the given altitude
618!-----------------------------------------------------------------------
619  REAL(8) FUNCTION equator_theta(z)
620
621    IMPLICIT NONE
622
623    REAL(8), INTENT(IN) :: z
624
625    if (z .le. z_tr) then
626      equator_theta = &
627        theta0 + (theta_tr - theta0) * (z / z_tr)**(1.25d0)
628    else
629      equator_theta = &
630        theta_tr * exp(g/cp/T_tr * (z - z_tr))
631    end if
632
633  END FUNCTION equator_theta
634
635!-----------------------------------------------------------------------
636!    Calculate pointwise relative humidity (in %) at the equator at the
637!    given altitude
638!-----------------------------------------------------------------------
639  REAL(8) FUNCTION equator_relative_humidity(z)
640
641    IMPLICIT NONE
642
643    REAL(8), INTENT(IN) :: z
644
645    if (z .le. z_tr) then
646      equator_relative_humidity = 1.0d0 - 0.75d0 * (z / z_tr)**(1.25d0)
647    else
648      equator_relative_humidity = 0.25d0
649    end if
650
651  END FUNCTION equator_relative_humidity
652
653!-----------------------------------------------------------------------
654!    Calculate saturation mixing ratio (in kg/kg) in terms of pressure
655!    (in Pa) and temperature (in K)
656!-----------------------------------------------------------------------
657  REAL(8) FUNCTION saturation_mixing_ratio(p, T)
658
659    IMPLICIT NONE
660
661    REAL(8), INTENT(IN)  :: &
662                p,        & ! Pressure in Pa
663                T           ! Temperature
664
665    saturation_mixing_ratio = &
666      380.d0 / p * exp(17.27d0 * (T - 273.d0) / (T - 36.d0))
667
668    if (saturation_mixing_ratio > 0.014) then
669      saturation_mixing_ratio = 0.014
670    end if
671
672  END FUNCTION saturation_mixing_ratio
673
674!-----------------------------------------------------------------------
675!    Calculate coefficients for a Lagrangian polynomial
676!-----------------------------------------------------------------------
677  SUBROUTINE lagrangian_polynomial_coeffs(npts, x, coeffs, xs)
678
679    IMPLICIT NONE
680
681    ! Number of points to fit
682    INTEGER(4), INTENT(IN) :: npts
683
684    ! Sample points to fit
685    REAL(8), DIMENSION(npts), INTENT(IN) :: x
686
687    ! Computed coefficients
688    REAL(8), DIMENSION(npts), INTENT(OUT) :: coeffs
689
690    ! Point at which sample is taken
691    REAL(8), INTENT(IN) :: xs
692
693    ! Loop indices
694    INTEGER(4) :: i, j
695   
696    ! Compute the Lagrangian polynomial coefficients
697    do i = 1, npts
698      coeffs(i) = 1.0d0
699      do j = 1, npts
700        if (i .eq. j) then
701          cycle
702        end if
703        coeffs(i) = coeffs(i) * (xs - x(j)) / (x(i) - x(j))
704      end do
705    end do
706
707  END SUBROUTINE lagrangian_polynomial_coeffs
708
709!-----------------------------------------------------------------------
710!    Calculate coefficients of the derivative of a Lagrangian polynomial
711!-----------------------------------------------------------------------
712  SUBROUTINE diff_lagrangian_polynomial_coeffs(npts, x, coeffs, xs)
713
714    IMPLICIT NONE
715
716    ! Number of points to fit
717    INTEGER(4), INTENT(IN) :: npts
718
719    ! Sample points to fit
720    REAL(8), DIMENSION(npts), INTENT(IN) :: x
721
722    ! Computed coefficients
723    REAL(8), DIMENSION(npts), INTENT(OUT) :: coeffs
724
725    ! Point at which sample is taken
726    REAL(8), INTENT(IN) :: xs
727
728    ! Loop indices
729    INTEGER(4) :: i, j, imatch
730
731    ! Buffer sum
732    REAL(8) :: coeffsum, differential
733
734    ! Check if xs is equivalent to one of the values of x
735    imatch = (-1)
736    do i = 1, npts
737      if (abs(xs - x(i)) < 1.0d-14) then
738        imatch = i
739        exit
740      end if
741    end do
742
743    ! Equivalence detected; special treatment required
744    if (imatch .ne. (-1)) then
745      do i = 1, npts
746        coeffs(i) = 1.0d0
747        coeffsum = 0.0d0
748
749        do j = 1, npts
750          if ((j .eq. i) .or. (j .eq. imatch)) then
751            cycle
752          end if
753
754          coeffs(i) = coeffs(i) * (xs - x(j)) / (x(i) - x(j))
755          coeffsum = coeffsum + 1.0 / (xs - x(j))
756        end do
757
758        if (i .ne. imatch) then
759          coeffs(i) = coeffs(i)                   &
760            * (1.0 + (xs - x(imatch)) * coeffsum) &
761            / (x(i) - x(imatch))
762        else
763          coeffs(i) = coeffs(i) * coeffsum
764        end if
765      end do
766
767    ! No equivalence; simply differentiate Lagrangian fit
768    else
769      call lagrangian_polynomial_coeffs(npts, x, coeffs, xs)
770
771      do i = 1, npts
772        differential = 0.0d0
773        do j = 1, npts
774          if (i .eq. j) then
775            cycle
776          end if
777          differential = differential + 1.0 / (xs - x(j))
778        end do
779        coeffs(i) = coeffs(i) * differential
780      end do
781    end if
782
783  END SUBROUTINE
784
785END MODULE dcmip2016_supercell_mod
Note: See TracBrowser for help on using the repository browser.